From: Matthew Vernon Date: Fri, 8 Nov 2024 16:26:58 +0000 (+0000) Subject: New upstream version 10.44 X-Git-Tag: archive/raspbian/10.45-1+rpi1^2~1^2~2 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=de9d274b27a349b705585e592760039b00a3e6ee;p=pcre2.git New upstream version 10.44 --- diff --git a/CMakeLists.txt b/CMakeLists.txt index a17a261..b73ed73 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1130,8 +1130,8 @@ FILE(GLOB html ${PROJECT_SOURCE_DIR}/doc/html/*.html) FILE(GLOB man1 ${PROJECT_SOURCE_DIR}/doc/*.1) FILE(GLOB man3 ${PROJECT_SOURCE_DIR}/doc/*.3) -INSTALL(FILES ${man1} DESTINATION man/man1) -INSTALL(FILES ${man3} DESTINATION man/man3) +INSTALL(FILES ${man1} DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) +INSTALL(FILES ${man3} DESTINATION ${CMAKE_INSTALL_MANDIR}/man3) INSTALL(FILES ${html} DESTINATION share/doc/pcre2/html) IF(MSVC AND INSTALL_MSVC_PDB) diff --git a/ChangeLog b/ChangeLog index 99001da..ea228c1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,7 +2,60 @@ Change Log for PCRE2 -------------------- Before the move to GitHub, this was the only record of changes to PCRE2. Now -there is often more detail in the pull requests. +there is also the log of commit messages. + +Version 10.44 07-June-2024 +-------------------------- + +1. If a pattern contained a variable-length lookbehind in which the first +branch was not the one with the shortest minimum length, and the lookbehind +contained a capturing group, and elsewhere in the pattern there was another +lookbehind that referenced that group, the pattern was incorrectly compiled, +leading to unpredictable results, including crashes in JIT compiling. An +example pattern is: /(((?<=123?456456|ABC)))(?<=\2)/ + +2. Further updates to the oss-fuzz support: + + (a) Limit quantifiers for groups and classes to be no more than 10. This + avoids very long JIT compile times that happen in some cases when groups + are replicated for quantification, and very long match times when + classes contain a lot of non-ascii characters. + + (b) Added PCRE2_EXTENDED_MORE to the list of allowed options. + + (c) Arranged for text error messages to be shown in 16-bit and 32-bit modes. + + (d) Made the output in standalone mode more readable. + + (e) General code tidies. + + (f) Limit the size of compiled patterns to 10MB (see 6 below). + + (g) Do not run JIT on patterns whose compiled length is greater than 200K + bytes because this takes a long time, causing oss-fuzz to time out. + + (h) Avoid compiling or matching twice with the same options (this could + happen if the input didn't set any options). + +3. Increase the maximum length of a name for a group from 32 to 128 because +there is a user for whom 32 is too small. + +4. Cause pcre2test to output a message when pcre2_jit_compile() gives an error +return if either jitverify or info is specified. + +5. Some auxiliary files for building under OpenVMS that were contributed by +Alexey Chupahin have been installed. + +6. Added pcre2_set_max_pattern_compiled_length() to limit the size of compiled +patterns. + +7. There was a bug in the implementation of \X caused by my (PH) misreading or +misunderstanding one of the grapheme sequence breaking rules in Unicode Annex +#29. A break should occur between two characters with the Extended Pictographic +break property unless a zero-width joiner intervenes. PCRE2 was not insisting +on the ZWJ, causing \X to match more than it should. See GitHub issue #410. + +8. Avoid compilation issues with proprietary compilers in UNIX since 10.43. Version 10.43 16-February-2024 @@ -124,7 +177,7 @@ pcre2_match() was not fully resetting all captures that had been set within a 32. Changed the meaning of \w (and its synonyms) in UCP mode to match Perl. It now matches characters whose general categories are L or N or whose particular -categories are Mn (non-spacing mark) or Pc (combining puntuation). The latter +categories are Mn (non-spacing mark) or Pc (combining punctuation). The latter includes underscore. 33. Changed the meaning of [:xdigit:] in UCP mode to match Perl. It now also @@ -297,7 +350,7 @@ elsewhere that can never be obeyed in normal testing has been excluded from coverage. 15. Fixed a bug in pcre2grep that could cause an extra newline to be written -after output generaed by --output. +after output generated by --output. 16. If a file has a .bz2 extension but is not in fact compressed, pcre2grep should process it as a plain text file. A bug stopped this happening; now fixed @@ -452,7 +505,7 @@ Version 10.39 29-October-2021 that an appropriate width is chosen if pointers are 64bit wide and long is not (ex: Windows 64bit). - IMHO removing the cast (and therefore the possibilty of truncation) + IMHO removing the cast (and therefore the possibility of truncation) make the code cleaner and the fallback is likely portable enough with all 64-bit POSIX systems doing LP64 except for Windows. @@ -587,7 +640,7 @@ now the same as Perl. quantifier was nevertheless complaining that a quantifier number was too big. 5. A run of autoconf suggested that configure.ac was out-of-date with respect -to the lastest autoconf. Running autoupdate made some valid changes, some valid +to the latest autoconf. Running autoupdate made some valid changes, some valid suggestions, and also some invalid changes, which were fixed by hand. Autoconf now runs clean and the resulting "configure" seems to work, so I hope nothing is broken. Later: the requirement for autoconf 2.70 broke some automatic test @@ -619,7 +672,7 @@ compiler. This fixes https://bugs.exim.org/show_bug.cgi?id=2578. Patch for Makefile.am and configure.ac by H.J. Lu. Equivalent patch for CMakeLists.txt invented by PH. -2. Fix inifinite loop when a single byte newline is searched in JIT when +2. Fix infinite loop when a single byte newline is searched in JIT when invalid utf8 mode is enabled. 3. Updated CMakeLists.txt with patch from Wolfgang Stöggl (Bugzilla #2584): @@ -732,7 +785,7 @@ after the end a repeated group, the captured substrings had their values from the final repetition, not from an earlier repetition that might be the destination of a backtrack. This feature was documented, and was carried over into PCRE2. However, it has now been realized that the major refactoring that -was done for 10.30 has made this atomicizing unnecessary, and it is confusing +was done for 10.30 has made this atomizing unnecessary, and it is confusing when users are unaware of it, making some patterns appear not to be working as expected. Capture values of recursive back references in repeated groups are now correctly backtracked, so this unnecessary restriction has been removed. @@ -1895,7 +1948,7 @@ not recognize this syntax. 7. Automatic callouts are no longer generated before and after callouts in the pattern. -8. When pcre2test was outputing information from a callout, the caret indicator +8. When pcre2test was outputting information from a callout, the caret indicator for the current position in the subject line was incorrect if it was after an escape sequence for a character whose code point was greater than \x{ff}. @@ -2276,7 +2329,7 @@ if it fails when running the interpreter with a 16MiB stack (and if changing the stack size via pcre2test is possible). This avoids having to manually set a large stack size when testing with clang. -42. Fix register overwite in JIT when SSE2 acceleration is enabled. +42. Fix register overwrite in JIT when SSE2 acceleration is enabled. 43. Detect integer overflow in pcre2test pattern and data repetition counts. @@ -3029,7 +3082,7 @@ characters, for example: /(?:(?=.)|(?config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by PCRE2 $as_me 10.43, which was +It was created by PCRE2 $as_me 10.44, which was generated by GNU Autoconf 2.72. Invocation command line was $ $0$ac_configure_args_raw @@ -3372,7 +3372,7 @@ fi # Define the identity of the package. PACKAGE='pcre2' - VERSION='10.43' + VERSION='10.44' printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h @@ -5214,8 +5214,8 @@ esac -macro_version='2.4.7.4-1ec8f-dirty' -macro_revision='2.4.7.4' +macro_version='2.5.0.1-38c1-dirty' +macro_revision='2.5.0.1' @@ -5726,7 +5726,7 @@ if test yes = "$GCC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 printf %s "checking for ld used by $CC... " >&6; } case $host in - *-*-mingw*) + *-*-mingw* | *-*-windows*) # gcc leaves a trailing carriage return, which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) @@ -5855,7 +5855,7 @@ else # Tru64's nm complains that /dev/null is an invalid object file # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty case $build_os in - mingw*) lt_bad_file=conftest.nm/nofile ;; + mingw* | windows*) lt_bad_file=conftest.nm/nofile ;; *) lt_bad_file=/dev/null ;; esac case `"$tmp_nm" -B $lt_bad_file 2>&1 | $SED '1q'` in @@ -6088,7 +6088,7 @@ else case e in #( lt_cv_sys_max_cmd_len=-1; ;; - cygwin* | mingw* | cegcc*) + cygwin* | mingw* | windows* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, @@ -6110,7 +6110,7 @@ else case e in #( lt_cv_sys_max_cmd_len=8192; ;; - bitrig* | darwin* | dragonfly* | freebsd* | midnightbsd* | netbsd* | openbsd*) + darwin* | dragonfly* | freebsd* | midnightbsd* | netbsd* | openbsd*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` @@ -6253,7 +6253,7 @@ else case e in #( e) case $host in *-*-mingw* ) case $build in - *-*-mingw* ) # actually msys + *-*-mingw* | *-*-windows* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 ;; *-*-cygwin* ) @@ -6266,7 +6266,7 @@ else case e in #( ;; *-*-cygwin* ) case $build in - *-*-mingw* ) # actually msys + *-*-mingw* | *-*-windows* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin ;; *-*-cygwin* ) @@ -6302,9 +6302,9 @@ else case e in #( e) #assume ordinary cross tools, or native build. lt_cv_to_tool_file_cmd=func_convert_file_noop case $host in - *-*-mingw* ) + *-*-mingw* | *-*-windows* ) case $build in - *-*-mingw* ) # actually msys + *-*-mingw* | *-*-windows* ) # actually msys lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 ;; esac @@ -6340,7 +6340,7 @@ case $reload_flag in esac reload_cmds='$LD$reload_flag -o $output$reload_objs' case $host_os in - cygwin* | mingw* | pw32* | cegcc*) + cygwin* | mingw* | windows* | pw32* | cegcc*) if test yes != "$GCC"; then reload_cmds=false fi @@ -6362,9 +6362,8 @@ esac -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}file", so it can be a program name with args. -set dummy ${ac_tool_prefix}file; ac_word=$2 +# Extract the first word of "file", so it can be a program name with args. +set dummy file; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_FILECMD+y} @@ -6385,7 +6384,7 @@ do esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_FILECMD="${ac_tool_prefix}file" + ac_cv_prog_FILECMD=":" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi @@ -6406,66 +6405,6 @@ printf "%s\n" "no" >&6; } fi -fi -if test -z "$ac_cv_prog_FILECMD"; then - ac_ct_FILECMD=$FILECMD - # Extract the first word of "file", so it can be a program name with args. -set dummy file; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_FILECMD+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ac_ct_FILECMD"; then - ac_cv_prog_ac_ct_FILECMD="$ac_ct_FILECMD" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_FILECMD="file" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_FILECMD=$ac_cv_prog_ac_ct_FILECMD -if test -n "$ac_ct_FILECMD"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_FILECMD" >&5 -printf "%s\n" "$ac_ct_FILECMD" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - if test "x$ac_ct_FILECMD" = x; then - FILECMD=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - FILECMD=$ac_ct_FILECMD - fi -else - FILECMD="$ac_cv_prog_FILECMD" -fi - @@ -6597,7 +6536,6 @@ lt_cv_deplibs_check_method='unknown' # 'none' -- dependencies not supported. # 'unknown' -- same as none, but documents that we really don't know. # 'pass_all' -- all dependencies passed with no checks. -# 'test_compile' -- check by making test program. # 'file_magic [[regex]]' -- check by looking for files in library path # that responds to the $file_magic_cmd with a given extended regex. # If you have 'file' or equivalent on your system and you're not sure @@ -6624,7 +6562,7 @@ cygwin*) lt_cv_file_magic_cmd='func_win32_libid' ;; -mingw* | pw32*) +mingw* | windows* | pw32*) # Base MSYS/MinGW do not provide the 'file' command needed by # func_win32_libid shell function, so use a weaker test based on 'objdump', # unless we find 'file', for example because we are cross-compiling. @@ -6724,7 +6662,7 @@ newos6*) lt_cv_deplibs_check_method=pass_all ;; -openbsd* | bitrig*) +openbsd*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' else @@ -6792,7 +6730,7 @@ file_magic_glob= want_nocaseglob=no if test "$build" = "$host"; then case $host_os in - mingw* | pw32*) + mingw* | windows* | pw32*) if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then want_nocaseglob=yes else @@ -6948,7 +6886,7 @@ else case e in #( e) lt_cv_sharedlib_from_linklib_cmd='unknown' case $host_os in -cygwin* | mingw* | pw32* | cegcc*) +cygwin* | mingw* | windows* | pw32* | cegcc*) # two different shell functions defined in ltmain.sh; # decide which one to use based on capabilities of $DLLTOOL case `$DLLTOOL --help 2>&1` in @@ -7100,7 +7038,7 @@ fi # Use ARFLAGS variable as AR's operation code to sync the variable naming with # Automake. If both AR_FLAGS and ARFLAGS are specified, AR_FLAGS should have -# higher priority because thats what people were doing historically (setting +# higher priority because that's what people were doing historically (setting # ARFLAGS for automake and AR_FLAGS for libtool). FIXME: Make the AR_FLAGS # variable obsoleted/removed. @@ -7409,15 +7347,8 @@ old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then - case $host_os in - bitrig* | openbsd*) - old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" - ;; - *) - old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" - ;; - esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" fi case $host_os in @@ -7497,7 +7428,7 @@ case $host_os in aix*) symcode='[BCDT]' ;; -cygwin* | mingw* | pw32* | cegcc*) +cygwin* | mingw* | windows* | pw32* | cegcc*) symcode='[ABCDGISTW]' ;; hpux*) @@ -7512,7 +7443,7 @@ osf*) symcode='[BCDEGQRST]' ;; solaris*) - symcode='[BDRT]' + symcode='[BCDRT]' ;; sco3.2v5*) symcode='[DT]' @@ -7576,7 +7507,7 @@ $lt_c_name_lib_hook\ # Handle CRLF in mingw tool chain opt_cr= case $build_os in -mingw*) +mingw* | windows*) opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac @@ -7812,7 +7743,9 @@ lt_sysroot= case $with_sysroot in #( yes) if test yes = "$GCC"; then - lt_sysroot=`$CC --print-sysroot 2>/dev/null` + # Trim trailing / since we'll always append absolute paths and we want + # to avoid //, if only for less confusing output for the user. + lt_sysroot=`$CC --print-sysroot 2>/dev/null | $SED 's:/\+$::'` fi ;; #( /*) @@ -8029,7 +7962,7 @@ mips64*-*linux*) ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ -s390*-*linux*|s390*-*tpf*|sparc*-*linux*) +s390*-*linux*|s390*-*tpf*|sparc*-*linux*|x86_64-gnu*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. Note that the listed cases only cover the # situations where additional linker options are needed (such as when @@ -8048,7 +7981,7 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; - x86_64-*linux*) + x86_64-*linux*|x86_64-gnu*) case `$FILECMD conftest.o` in *x86-64*) LD="${LD-ld} -m elf32_x86_64" @@ -8077,7 +8010,7 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; - x86_64-*linux*) + x86_64-*linux*|x86_64-gnu*) LD="${LD-ld} -m elf_x86_64" ;; powerpcle-*linux*) @@ -8298,23 +8231,23 @@ fi test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5 printf %s "checking if $MANIFEST_TOOL is a manifest tool... " >&6; } -if test ${lt_cv_path_mainfest_tool+y} +if test ${lt_cv_path_manifest_tool+y} then : printf %s "(cached) " >&6 else case e in #( - e) lt_cv_path_mainfest_tool=no + e) lt_cv_path_manifest_tool=no echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5 $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out cat conftest.err >&5 if $GREP 'Manifest Tool' conftest.out > /dev/null; then - lt_cv_path_mainfest_tool=yes + lt_cv_path_manifest_tool=yes fi rm -f conftest* ;; esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5 -printf "%s\n" "$lt_cv_path_mainfest_tool" >&6; } -if test yes != "$lt_cv_path_mainfest_tool"; then +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_manifest_tool" >&5 +printf "%s\n" "$lt_cv_path_manifest_tool" >&6; } +if test yes != "$lt_cv_path_manifest_tool"; then MANIFEST_TOOL=: fi @@ -9063,7 +8996,7 @@ fi enable_win32_dll=yes case $host in -*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) +*-*-cygwin* | *-*-mingw* | *-*-windows* | *-*-pw32* | *-*-cegcc*) if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}as", so it can be a program name with args. set dummy ${ac_tool_prefix}as; ac_word=$2 @@ -10020,7 +9953,7 @@ lt_prog_compiler_static= # PIC is the default for these OSes. ;; - mingw* | cygwin* | pw32* | os2* | cegcc*) + mingw* | windows* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style @@ -10123,7 +10056,7 @@ lt_prog_compiler_static= esac ;; - mingw* | cygwin* | pw32* | os2* | cegcc*) + mingw* | windows* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). lt_prog_compiler_pic='-DDLL_EXPORT' @@ -10164,6 +10097,12 @@ lt_prog_compiler_static= lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-static' ;; + *flang) + # Flang compiler. + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fPIC' + lt_prog_compiler_static='-static' + ;; # icc used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. icc* | ifort*) @@ -10635,7 +10574,7 @@ printf %s "checking whether the $compiler linker ($LD) supports shared libraries extract_expsyms_cmds= case $host_os in - cygwin* | mingw* | pw32* | cegcc*) + cygwin* | mingw* | windows* | pw32* | cegcc*) # FIXME: the MSVC++ and ICC port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++ or Intel C++ Compiler. @@ -10647,7 +10586,7 @@ printf %s "checking whether the $compiler linker ($LD) supports shared libraries # we just hope/assume this is gcc and not c89 (= MSVC++ or ICC) with_gnu_ld=yes ;; - openbsd* | bitrig*) + openbsd*) with_gnu_ld=no ;; esac @@ -10750,7 +10689,7 @@ _LT_EOF fi ;; - cygwin* | mingw* | pw32* | cegcc*) + cygwin* | mingw* | windows* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, # as there is no search path for DLLs. hardcode_libdir_flag_spec='-L$libdir' @@ -10806,7 +10745,7 @@ _LT_EOF cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' - old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' + old_archive_from_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' enable_shared_with_static_runtimes=yes file_list_spec='@' ;; @@ -11297,7 +11236,7 @@ fi export_dynamic_flag_spec=-rdynamic ;; - cygwin* | mingw* | pw32* | cegcc*) + cygwin* | mingw* | windows* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++ or Intel C++ Compiler. # hardcode_libdir_flag_spec is actually meaningless, as there is @@ -11314,14 +11253,14 @@ fi # Tell ltmain to make .dll files, not .so files. shrext_cmds=.dll # FIXME: Setting linknames here is a bad hack. - archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' + archive_cmds='$CC -Fe $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then cp "$export_symbols" "$output_objdir/$soname.def"; echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; else $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; fi~ - $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + $CC -Fe $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, )='true' @@ -11630,7 +11569,7 @@ printf "%s\n" "$lt_cv_irix_exported_symbol" >&6; } *nto* | *qnx*) ;; - openbsd* | bitrig*) + openbsd*) if test -f /usr/libexec/ld.so; then hardcode_direct=yes hardcode_shlibpath_var=no @@ -11673,7 +11612,7 @@ printf "%s\n" "$lt_cv_irix_exported_symbol" >&6; } cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' - old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' + old_archive_from_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' enable_shared_with_static_runtimes=yes file_list_spec='@' ;; @@ -12115,7 +12054,7 @@ if test yes = "$GCC"; then *) lt_awk_arg='/^libraries:/' ;; esac case $host_os in - mingw* | cegcc*) lt_sed_strip_eq='s|=\([A-Za-z]:\)|\1|g' ;; + mingw* | windows* | cegcc*) lt_sed_strip_eq='s|=\([A-Za-z]:\)|\1|g' ;; *) lt_sed_strip_eq='s|=/|/|g' ;; esac lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` @@ -12173,7 +12112,7 @@ BEGIN {RS = " "; FS = "/|\n";} { # AWK program above erroneously prepends '/' to C:/dos/paths # for these hosts. case $host_os in - mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ + mingw* | windows* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ $SED 's|/\([A-Za-z]:\)|\1|g'` ;; esac sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` @@ -12341,7 +12280,7 @@ bsdi[45]*) # libtool to hard-code these into programs ;; -cygwin* | mingw* | pw32* | cegcc*) +cygwin* | mingw* | windows* | pw32* | cegcc*) version_type=windows shrext_cmds=.dll need_version=no @@ -12373,7 +12312,7 @@ cygwin* | mingw* | pw32* | cegcc*) sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api" ;; - mingw* | cegcc*) + mingw* | windows* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' ;; @@ -12392,7 +12331,7 @@ cygwin* | mingw* | pw32* | cegcc*) library_names_spec='$libname.dll.lib' case $build_os in - mingw*) + mingw* | windows*) sys_lib_search_path_spec= lt_save_ifs=$IFS IFS=';' @@ -12640,7 +12579,7 @@ linux*android*) version_type=none # Android doesn't support versioned libraries. need_lib_prefix=no need_version=no - library_names_spec='$libname$release$shared_ext' + library_names_spec='$libname$release$shared_ext $libname$shared_ext' soname_spec='$libname$release$shared_ext' finish_cmds= shlibpath_var=LD_LIBRARY_PATH @@ -12652,8 +12591,9 @@ linux*android*) hardcode_into_libs=yes dynamic_linker='Android linker' - # Don't embed -rpath directories since the linker doesn't support them. - hardcode_libdir_flag_spec='-L$libdir' + # -rpath works at least for libraries that are not overridden by + # libraries installed in system locations. + hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' ;; # This must be glibc/ELF. @@ -12710,7 +12650,7 @@ fi # before this can be enabled. hardcode_into_libs=yes - # Ideally, we could use ldconfig to report *all* directores which are + # Ideally, we could use ldconfig to report *all* directories which are # searched for libraries, however this is still not possible. Aside from not # being certain /sbin/ldconfig is available, command # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64, @@ -12767,7 +12707,7 @@ newsos6) dynamic_linker='ldqnx.so' ;; -openbsd* | bitrig*) +openbsd*) version_type=sunos sys_lib_dlsearch_path_spec=/usr/lib need_lib_prefix=no @@ -13108,7 +13048,7 @@ else lt_cv_dlopen_self=yes ;; - mingw* | pw32* | cegcc*) + mingw* | windows* | pw32* | cegcc*) lt_cv_dlopen=LoadLibrary lt_cv_dlopen_libs= ;; @@ -14084,6 +14024,10 @@ printf "%s\n" "#define PCRE2_EXPORT __attribute__ ((visibility (\"default\")))" printf "%s\n" "#define PCRE2_EXPORT /**/" >>confdefs.h fi + else + +printf "%s\n" "#define PCRE2_EXPORT /**/" >>confdefs.h + fi @@ -14194,9 +14138,9 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu # Versioning PCRE2_MAJOR="10" -PCRE2_MINOR="43" +PCRE2_MINOR="44" PCRE2_PRERELEASE="" -PCRE2_DATE="2024-02-16" +PCRE2_DATE="2024-06-07" if test "$PCRE2_MINOR" = "08" -o "$PCRE2_MINOR" = "09" then @@ -14325,7 +14269,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu /* end confdefs.h. */ #define SLJIT_CONFIG_AUTO 1 - #include "src/sljit/sljitConfigInternal.h" + #include "src/sljit/sljitConfigCPU.h" #if (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED) #error unsupported #endif @@ -16281,7 +16225,7 @@ printf "%s\n" "#define HEAP_LIMIT $with_heap_limit" >>confdefs.h -printf "%s\n" "#define MAX_NAME_SIZE 32" >>confdefs.h +printf "%s\n" "#define MAX_NAME_SIZE 128" >>confdefs.h @@ -16324,13 +16268,13 @@ esac # are m4 variables, assigned above. EXTRA_LIBPCRE2_8_LDFLAGS="$EXTRA_LIBPCRE2_8_LDFLAGS \ - $NO_UNDEFINED -version-info 12:0:12" + $NO_UNDEFINED -version-info 13:0:13" EXTRA_LIBPCRE2_16_LDFLAGS="$EXTRA_LIBPCRE2_16_LDFLAGS \ - $NO_UNDEFINED -version-info 12:0:12" + $NO_UNDEFINED -version-info 13:0:13" EXTRA_LIBPCRE2_32_LDFLAGS="$EXTRA_LIBPCRE2_32_LDFLAGS \ - $NO_UNDEFINED -version-info 12:0:12" + $NO_UNDEFINED -version-info 13:0:13" EXTRA_LIBPCRE2_POSIX_LDFLAGS="$EXTRA_LIBPCRE2_POSIX_LDFLAGS \ $NO_UNDEFINED -version-info 3:5:0" @@ -17458,7 +17402,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by PCRE2 $as_me 10.43, which was +This file was extended by PCRE2 $as_me 10.44, which was generated by GNU Autoconf 2.72. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -17526,7 +17470,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ -PCRE2 config.status 10.43 +PCRE2 config.status 10.44 configured by $0, generated by GNU Autoconf 2.72, with options \\"\$ac_cs_config\\" @@ -18665,13 +18609,13 @@ See 'config.log' for more details" "$LINENO" 5; } # Provide generalized library-building support services. # Written by Gordon Matzigkeit, 1996 -# Copyright (C) 2014 Free Software Foundation, Inc. +# Copyright (C) 2024 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # GNU Libtool is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of of the License, or +# the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # As a special exception to the GNU General Public License, if you @@ -19055,7 +18999,7 @@ hardcode_direct=$hardcode_direct # Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes # DIR into the resulting binary and the resulting library dependency is -# "absolute",i.e impossible to change by setting \$shlibpath_var if the +# "absolute",i.e. impossible to change by setting \$shlibpath_var if the # library is relocated. hardcode_direct_absolute=$hardcode_direct_absolute diff --git a/configure.ac b/configure.ac index 77b77f3..6091ea4 100644 --- a/configure.ac +++ b/configure.ac @@ -9,14 +9,14 @@ dnl The PCRE2_PRERELEASE feature is for identifying release candidates. It might dnl be defined as -RC2, for example. For real releases, it should be empty. m4_define(pcre2_major, [10]) -m4_define(pcre2_minor, [43]) +m4_define(pcre2_minor, [44]) m4_define(pcre2_prerelease, []) -m4_define(pcre2_date, [2024-02-16]) +m4_define(pcre2_date, [2024-06-07]) # Libtool shared library interface versions (current:revision:age) -m4_define(libpcre2_8_version, [12:0:12]) -m4_define(libpcre2_16_version, [12:0:12]) -m4_define(libpcre2_32_version, [12:0:12]) +m4_define(libpcre2_8_version, [13:0:13]) +m4_define(libpcre2_16_version, [13:0:13]) +m4_define(libpcre2_32_version, [13:0:13]) m4_define(libpcre2_posix_version, [3:5:0]) # NOTE: The CMakeLists.txt file searches for the above variables in the first @@ -191,7 +191,7 @@ if test "$enable_jit" = "auto"; then CPPFLAGS=-I$srcdir AC_COMPILE_IFELSE([AC_LANG_SOURCE([[ #define SLJIT_CONFIG_AUTO 1 - #include "src/sljit/sljitConfigInternal.h" + #include "src/sljit/sljitConfigCPU.h" #if (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED) #error unsupported #endif]])], enable_jit=yes, enable_jit=no) @@ -883,7 +883,7 @@ AC_DEFINE_UNQUOTED([HEAP_LIMIT], [$with_heap_limit], [ a pattern. It applies to both pcre2_match() and pcre2_dfa_match(). It does not apply to JIT matching. The value is in kibibytes (units of 1024 bytes).]) -AC_DEFINE([MAX_NAME_SIZE], [32], [ +AC_DEFINE([MAX_NAME_SIZE], [128], [ This limit is parameterized just in case anybody ever wants to change it. Care must be taken if it is increased, because it guards against integer overflow caused by enormously large patterns.]) diff --git a/doc/html/NON-AUTOTOOLS-BUILD.txt b/doc/html/NON-AUTOTOOLS-BUILD.txt index c0b9eed..851976a 100644 --- a/doc/html/NON-AUTOTOOLS-BUILD.txt +++ b/doc/html/NON-AUTOTOOLS-BUILD.txt @@ -13,6 +13,7 @@ This document contains the following sections: Building PCRE2 on Windows with Visual Studio Testing with RunTest.bat Building PCRE2 on native z/OS and z/VM + Building PCRE2 under VMS GENERAL @@ -416,6 +417,14 @@ Everything in that location, source and executable, is in EBCDIC and native z/OS file formats. The port provides an API for LE languages such as COBOL and for the z/OS and z/VM versions of the Rexx languages. + +BUILDING PCRE2 UNDER VMS + +Alexey Chuphin has contributed some auxiliary files for building PCRE2 under +OpenVMS. They are in the "vms" directory in the distribution tarball. Please +read the file called vms/openvms_readme.txt. The pcre2test and pcre2grep +programs contain some VMS-specific code. + =========================== -Last Updated: 15 April 2023 +Last Updated: 16 April 2024 =========================== diff --git a/doc/html/README.txt b/doc/html/README.txt index 8ef6262..dab5e94 100644 --- a/doc/html/README.txt +++ b/doc/html/README.txt @@ -24,7 +24,6 @@ contents of this README file are: The PCRE2 APIs Documentation for PCRE2 - Contributions by users of PCRE2 Building PCRE2 on non-Unix-like systems Building PCRE2 without using autotools Building PCRE2 using autotools @@ -944,7 +943,14 @@ The distribution should contain the files listed below. src/config.h.generic ) a version of config.h for use in non-"configure" ) environments +(F) Auxiliary files for building PCRE2 under OpenVMS + + vms/configure.com ) + vms/openvms_readme.txt ) These files were contributed by a PCRE2 user. + vms/pcre2.h_patch ) + vms/stdint.h ) + Philip Hazel Email local part: Philip.Hazel Email domain: gmail.com -Last updated: 24 November 2023 +Last updated: 15 April 2024 diff --git a/doc/html/index.html b/doc/html/index.html index f056fed..e4dc786 100644 --- a/doc/html/index.html +++ b/doc/html/index.html @@ -252,8 +252,11 @@ in the library. pcre2_set_match_limit   Set the match limit +pcre2_set_max_pattern_compiled_length +   Set the maximum length of a compiled pattern + pcre2_set_max_pattern_length -   Set the maximum length of pattern +   Set the maximum length of a pattern pcre2_set_max_varlookbehind   Set the maximum match length for a variable-length lookbehind diff --git a/doc/html/pcre2_set_max_pattern_compiled_length.html b/doc/html/pcre2_set_max_pattern_compiled_length.html new file mode 100644 index 0000000..ab570cf --- /dev/null +++ b/doc/html/pcre2_set_max_pattern_compiled_length.html @@ -0,0 +1,44 @@ + + +pcre2_set_max_pattern_compiled_length specification + + +

pcre2_set_max_pattern_compiled_length man page

+

+Return to the PCRE2 index page. +

+

+This page is part of the PCRE2 HTML documentation. It was generated +automatically from the original man page. If there is any nonsense in it, +please consult the man page, in case the conversion went wrong. +
+
+SYNOPSIS +
+

+#include <pcre2.h> +

+

+int pcre2_set_max_pattern_compiled_length( + pcre2_compile_context *ccontext, PCRE2_SIZE value); +

+
+DESCRIPTION +
+

+This function sets, in a compile context, the maximum size (in bytes) for the +memory needed to hold the compiled version of a pattern that is compiled with +this context. The result is always zero. If a pattern that is passed to +pcre2_compile() with this context needs more memory, an error is +generated. The default is the largest number that a PCRE2_SIZE variable can +hold, which is effectively unlimited. +

+

+There is a complete description of the PCRE2 native API in the +pcre2api +page and a description of the POSIX API in the +pcre2posix +page. +

+Return to the PCRE2 index page. +

diff --git a/doc/html/pcre2api.html b/doc/html/pcre2api.html index 23997d7..6b60ee9 100644 --- a/doc/html/pcre2api.html +++ b/doc/html/pcre2api.html @@ -161,6 +161,10 @@ document for an overview of all the PCRE2 documentation. PCRE2_SIZE value);

+int pcre2_set_max_pattern_compiled_length( + pcre2_compile_context *ccontext, PCRE2_SIZE value); +
+
int pcre2_set_max_varlookbehind(pcre2_compile_contest *ccontext, " uint32_t value);
@@ -874,6 +878,18 @@ external sources can limit their size. The default is the largest number that a PCRE2_SIZE variable can hold, which is effectively unlimited.

+int pcre2_set_max_pattern_compiled_length( + pcre2_compile_context *ccontext, PCRE2_SIZE value); +
+
+This sets a maximum size, in bytes, for the memory needed to hold the compiled +version of a pattern that is compiled with this context. If the pattern needs +more memory, an error is generated. This facility is provided so that +applications that accept patterns from external sources can limit the amount of +memory they use. The default is the largest number that a PCRE2_SIZE variable +can hold, which is effectively unlimited. +
+
int pcre2_set_max_varlookbehind(pcre2_compile_contest *ccontext, " uint32_t value);
@@ -4161,7 +4177,7 @@ Cambridge, England.


REVISION

-Last updated: 27 January 2024 +Last updated: 24 April 2024
Copyright © 1997-2024 University of Cambridge.
diff --git a/doc/html/pcre2build.html b/doc/html/pcre2build.html index 3276a66..d4b0d33 100644 --- a/doc/html/pcre2build.html +++ b/doc/html/pcre2build.html @@ -50,7 +50,8 @@ Autotools. Also in the distribution are files to support building using README contains general information about building with Autotools (some of which is repeated below), and also has some comments about building on various operating -systems. There is a lot more information about building PCRE2 without using +systems. The files in the vms directory support building under OpenVMS. +There is a lot more information about building PCRE2 without using Autotools (including information about using CMake and building "by hand") in the text file called NON-AUTOTOOLS-BUILD. @@ -642,9 +643,9 @@ Cambridge, England.


REVISION

-Last updated: 24 November 2023 +Last updated: 15 April 2024
-Copyright © 1997-2023 University of Cambridge. +Copyright © 1997-2024 University of Cambridge.

Return to the PCRE2 index page. diff --git a/doc/html/pcre2jit.html b/doc/html/pcre2jit.html index 8eb86f2..d97d800 100644 --- a/doc/html/pcre2jit.html +++ b/doc/html/pcre2jit.html @@ -52,7 +52,7 @@ JIT support is an optional feature of PCRE2. The "configure" option you want to use JIT. The support is limited to the following hardware platforms:

-  ARM 32-bit (v5, v7, and Thumb2)
+  ARM 32-bit (v7, and Thumb2)
   ARM 64-bit
   IBM s390x 64 bit
   Intel x86 32-bit and 64-bit
@@ -487,9 +487,9 @@ Cambridge, England.
 


REVISION

-Last updated: 23 January 2023 +Last updated: 21 February 2024
-Copyright © 1997-2023 University of Cambridge. +Copyright © 1997-2024 University of Cambridge.

Return to the PCRE2 index page. diff --git a/doc/html/pcre2pattern.html b/doc/html/pcre2pattern.html index debce8d..cf50c1a 100644 --- a/doc/html/pcre2pattern.html +++ b/doc/html/pcre2pattern.html @@ -1034,17 +1034,19 @@ L, V, LV, or LVT character; an LV or V character may be followed by a V or T character; an LVT or T character may be followed only by a T character.

-4. Do not end before extending characters or spacing marks or the "zero-width -joiner" character. Characters with the "mark" property always have the +4. Do not end before extending characters or spacing marks or the zero-width +joiner (ZWJ) character. Characters with the "mark" property always have the "extend" grapheme breaking property.

5. Do not end after prepend characters.

-6. Do not break within emoji modifier sequences or emoji zwj sequences. That -is, do not break between characters with the Extended_Pictographic property. -Extend and ZWJ characters are allowed between the characters. +6. Do not end within emoji modifier sequences or emoji ZWJ (zero-width +joiner) sequences. An emoji ZWJ sequence consists of a character with the +Extended_Pictographic property, optionally followed by one or more characters +with the Extend property, followed by the ZWJ character, followed by another +Extended_Pictographic character.

7. Do not break within emoji flag sequences. That is, do not break between @@ -1843,7 +1845,7 @@ using the Python syntax. PCRE2 supports both the Perl and the Python syntax.

In PCRE2, a capture group can be named in one of three ways: (?<name>...) or -(?'name'...) as in Perl, or (?P<name>...) as in Python. Names may be up to 32 +(?'name'...) as in Perl, or (?P<name>...) as in Python. Names may be up to 128 code units long. When PCRE2_UTF is not set, they may contain only ASCII alphanumeric characters and underscores, but must start with a non-digit. When PCRE2_UTF is set, the syntax of group names is extended to allow any Unicode @@ -3844,7 +3846,7 @@ Cambridge, England.


REVISION

-Last updated: 19 January 2024 +Last updated: 04 June 2024
Copyright © 1997-2024 University of Cambridge.
diff --git a/doc/html/pcre2test.html b/doc/html/pcre2test.html index fdeed5f..6cc3cc3 100644 --- a/doc/html/pcre2test.html +++ b/doc/html/pcre2test.html @@ -696,7 +696,9 @@ heavily used in the test files. jitfast use JIT fast path jitverify verify JIT use locale=<name> use this locale - max_pattern_length=<n> set maximum pattern length + max_pattern_compiled ) set maximum compiled pattern + _length=<n> ) length (bytes) + max_pattern_length=<n> set maximum pattern length (code units) max_varlookbehind=<n> set maximum variable lookbehind length memory show memory used newline=<type> set newline type @@ -1019,6 +1021,15 @@ The max_pattern_length modifier sets a limit, in code units, to the length of pattern that pcre2_compile() will accept. Breaching the limit causes a compilation error. The default is the largest number a PCRE2_SIZE variable can hold (essentially unlimited). +

+
+Limiting the size of a compiled pattern +
+

+The max_pattern_compiled_length modifier sets a limit, in bytes, to the +amount of memory used by a compiled pattern. Breaching the limit causes a +compilation error. The default is the largest number a PCRE2_SIZE variable can +hold (essentially unlimited).


Using the POSIX wrapper API @@ -2193,7 +2204,7 @@ Cambridge, England.


REVISION

-Last updated: 27 January 2024 +Last updated: 24 April 2024
Copyright © 1997-2024 University of Cambridge.
diff --git a/doc/index.html.src b/doc/index.html.src index f056fed..e4dc786 100644 --- a/doc/index.html.src +++ b/doc/index.html.src @@ -252,8 +252,11 @@ in the library. pcre2_set_match_limit   Set the match limit +pcre2_set_max_pattern_compiled_length +   Set the maximum length of a compiled pattern + pcre2_set_max_pattern_length -   Set the maximum length of pattern +   Set the maximum length of a pattern pcre2_set_max_varlookbehind   Set the maximum match length for a variable-length lookbehind diff --git a/doc/pcre2.txt b/doc/pcre2.txt index e160647..85eead6 100644 --- a/doc/pcre2.txt +++ b/doc/pcre2.txt @@ -283,6 +283,9 @@ PCRE2 NATIVE API COMPILE CONTEXT FUNCTIONS int pcre2_set_max_pattern_length(pcre2_compile_context *ccontext, PCRE2_SIZE value); + int pcre2_set_max_pattern_compiled_length( + pcre2_compile_context *ccontext, PCRE2_SIZE value); + int pcre2_set_max_varlookbehind(pcre2_compile_contest *ccontext, uint32_t value); @@ -912,6 +915,17 @@ PCRE2 CONTEXTS largest number that a PCRE2_SIZE variable can hold, which is effec- tively unlimited. + int pcre2_set_max_pattern_compiled_length( + pcre2_compile_context *ccontext, PCRE2_SIZE value); + + This sets a maximum size, in bytes, for the memory needed to hold the + compiled version of a pattern that is compiled with this context. If + the pattern needs more memory, an error is generated. This facility is + provided so that applications that accept patterns from external + sources can limit the amount of memory they use. The default is the + largest number that a PCRE2_SIZE variable can hold, which is effec- + tively unlimited. + int pcre2_set_max_varlookbehind(pcre2_compile_contest *ccontext, uint32_t value); @@ -3998,11 +4012,11 @@ AUTHOR REVISION - Last updated: 27 January 2024 + Last updated: 24 April 2024 Copyright (c) 1997-2024 University of Cambridge. -PCRE2 10.43 27 January 2024 PCRE2API(3) +PCRE2 10.44 24 April 2024 PCRE2API(3) ------------------------------------------------------------------------------ @@ -4022,11 +4036,12 @@ BUILDING PCRE2 CMake instead of configure. The text file README contains general in- formation about building with Autotools (some of which is repeated be- low), and also has some comments about building on various operating - systems. There is a lot more information about building PCRE2 without - using Autotools (including information about using CMake and building - "by hand") in the text file called NON-AUTOTOOLS-BUILD. You should - consult this file as well as the README file if you are building in a - non-Unix-like environment. + systems. The files in the vms directory support building under OpenVMS. + There is a lot more information about building PCRE2 without using Au- + totools (including information about using CMake and building "by + hand") in the text file called NON-AUTOTOOLS-BUILD. You should consult + this file as well as the README file if you are building in a non-Unix- + like environment. PCRE2 BUILD-TIME OPTIONS @@ -4624,11 +4639,11 @@ AUTHOR REVISION - Last updated: 24 November 2023 - Copyright (c) 1997-2023 University of Cambridge. + Last updated: 15 April 2024 + Copyright (c) 1997-2024 University of Cambridge. -PCRE2 10.43 24 November PCRE2BUILD(3) +PCRE2 10.44 15 April 2024 PCRE2BUILD(3) ------------------------------------------------------------------------------ @@ -5333,7 +5348,7 @@ AVAILABILITY OF JIT SUPPORT built if you want to use JIT. The support is limited to the following hardware platforms: - ARM 32-bit (v5, v7, and Thumb2) + ARM 32-bit (v7, and Thumb2) ARM 64-bit IBM s390x 64 bit Intel x86 32-bit and 64-bit @@ -5739,11 +5754,11 @@ AUTHOR REVISION - Last updated: 23 January 2023 - Copyright (c) 1997-2023 University of Cambridge. + Last updated: 21 February 2024 + Copyright (c) 1997-2024 University of Cambridge. -PCRE2 10.43 23 January 2023 PCRE2JIT(3) +PCRE2 10.43 21 February 2024 PCRE2JIT(3) ------------------------------------------------------------------------------ @@ -7355,16 +7370,17 @@ BACKSLASH be followed by a V or T character; an LVT or T character may be fol- lowed only by a T character. - 4. Do not end before extending characters or spacing marks or the - "zero-width joiner" character. Characters with the "mark" property al- + 4. Do not end before extending characters or spacing marks or the zero- + width joiner (ZWJ) character. Characters with the "mark" property al- ways have the "extend" grapheme breaking property. 5. Do not end after prepend characters. - 6. Do not break within emoji modifier sequences or emoji zwj sequences. - That is, do not break between characters with the Extended_Pictographic - property. Extend and ZWJ characters are allowed between the charac- - ters. + 6. Do not end within emoji modifier sequences or emoji ZWJ (zero-width + joiner) sequences. An emoji ZWJ sequence consists of a character with + the Extended_Pictographic property, optionally followed by one or more + characters with the Extend property, followed by the ZWJ character, + followed by another Extended_Pictographic character. 7. Do not break within emoji flag sequences. That is, do not break be- tween regional indicator (RI) characters if there are an odd number of @@ -8120,8 +8136,8 @@ NAMED CAPTURE GROUPS In PCRE2, a capture group can be named in one of three ways: (?...) or (?'name'...) as in Perl, or (?P...) as in Python. - Names may be up to 32 code units long. When PCRE2_UTF is not set, they - may contain only ASCII alphanumeric characters and underscores, but + Names may be up to 128 code units long. When PCRE2_UTF is not set, they + may contain only ASCII alphanumeric characters and underscores, but must start with a non-digit. When PCRE2_UTF is set, the syntax of group names is extended to allow any Unicode letter or Unicode decimal digit. In other words, group names must match one of these patterns: @@ -8129,42 +8145,42 @@ NAMED CAPTURE GROUPS ^[_A-Za-z][_A-Za-z0-9]*\z when PCRE2_UTF is not set ^[_\p{L}][_\p{L}\p{Nd}]*\z when PCRE2_UTF is set - References to capture groups from other parts of the pattern, such as - backreferences, recursion, and conditions, can all be made by name as + References to capture groups from other parts of the pattern, such as + backreferences, recursion, and conditions, can all be made by name as well as by number. Named capture groups are allocated numbers as well as names, exactly as - if the names were not present. In both PCRE2 and Perl, capture groups - are primarily identified by numbers; any names are just aliases for + if the names were not present. In both PCRE2 and Perl, capture groups + are primarily identified by numbers; any names are just aliases for these numbers. The PCRE2 API provides function calls for extracting the - complete name-to-number translation table from a compiled pattern, as - well as convenience functions for extracting captured substrings by + complete name-to-number translation table from a compiled pattern, as + well as convenience functions for extracting captured substrings by name. - Warning: When more than one capture group has the same number, as de- + Warning: When more than one capture group has the same number, as de- scribed in the previous section, a name given to one of them applies to - all of them. Perl allows identically numbered groups to have different + all of them. Perl allows identically numbered groups to have different names. Consider this pattern, where there are two capture groups, both numbered 1: (?|(?aa)|(?bb)) - Perl allows this, with both names AA and BB as aliases of group 1. + Perl allows this, with both names AA and BB as aliases of group 1. Thus, after a successful match, both names yield the same value (either "aa" or "bb"). - In an attempt to reduce confusion, PCRE2 does not allow the same group + In an attempt to reduce confusion, PCRE2 does not allow the same group number to be associated with more than one name. The example above pro- - vokes a compile-time error. However, there is still scope for confu- + vokes a compile-time error. However, there is still scope for confu- sion. Consider this pattern: (?|(?aa)|(bb)) Although the second group number 1 is not explicitly named, the name AA - is still an alias for any group 1. Whether the pattern matches "aa" or + is still an alias for any group 1. Whether the pattern matches "aa" or "bb", a reference by name to group AA yields the matched string. - By default, a name must be unique within a pattern, except that dupli- + By default, a name must be unique within a pattern, except that dupli- cate names are permitted for groups with the same number, for example: (?|(?aa)|(?bb)) @@ -8173,10 +8189,10 @@ NAMED CAPTURE GROUPS NAMES option at compile time, or by the use of (?J) within the pattern, as described in the section entitled "Internal Option Setting" above. - Duplicate names can be useful for patterns where only one instance of - the named capture group can match. Suppose you want to match the name - of a weekday, either as a 3-letter abbreviation or as the full name, - and in both cases you want to extract the abbreviation. This pattern + Duplicate names can be useful for patterns where only one instance of + the named capture group can match. Suppose you want to match the name + of a weekday, either as a 3-letter abbreviation or as the full name, + and in both cases you want to extract the abbreviation. This pattern (ignoring the line breaks) does the job: (?J) @@ -8186,17 +8202,17 @@ NAMED CAPTURE GROUPS (?Thu)(?:rsday)?| (?Sat)(?:urday)? - There are five capture groups, but only one is ever set after a match. - The convenience functions for extracting the data by name returns the - substring for the first (and in this example, the only) group of that + There are five capture groups, but only one is ever set after a match. + The convenience functions for extracting the data by name returns the + substring for the first (and in this example, the only) group of that name that matched. This saves searching to find which numbered group it - was. (An alternative way of solving this problem is to use a "branch + was. (An alternative way of solving this problem is to use a "branch reset" group, as described in the previous section.) - If you make a backreference to a non-unique named group from elsewhere - in the pattern, the groups to which the name refers are checked in the - order in which they appear in the overall pattern. The first one that - is set is used for the reference. For example, this pattern matches + If you make a backreference to a non-unique named group from elsewhere + in the pattern, the groups to which the name refers are checked in the + order in which they appear in the overall pattern. The first one that + is set is used for the reference. For example, this pattern matches both "foofoo" and "barbar" but not "foobar" or "barfoo": (?J)(?:(?foo)|(?bar))\k @@ -8209,15 +8225,15 @@ NAMED CAPTURE GROUPS If you use a named reference in a condition test (see the section about conditions below), either to check whether a capture group has matched, or to check for recursion, all groups with the same name are tested. If - the condition is true for any one of them, the overall condition is - true. This is the same behaviour as testing by number. For further de- - tails of the interfaces for handling named capture groups, see the + the condition is true for any one of them, the overall condition is + true. This is the same behaviour as testing by number. For further de- + tails of the interfaces for handling named capture groups, see the pcre2api documentation. REPETITION - Repetition is specified by quantifiers, which may follow any one of + Repetition is specified by quantifiers, which may follow any one of these items: a literal data character @@ -8233,16 +8249,16 @@ REPETITION If a quantifier does not follow a repeatable item, an error occurs. The general repetition quantifier specifies a minimum and maximum number of - permitted matches by giving two numbers in curly brackets (braces), - separated by a comma. The numbers must be less than 65536, and the + permitted matches by giving two numbers in curly brackets (braces), + separated by a comma. The numbers must be less than 65536, and the first must be less than or equal to the second. For example, z{2,4} - matches "zz", "zzz", or "zzzz". A closing brace on its own is not a - special character. If the second number is omitted, but the comma is - present, there is no upper limit; if the second number and the comma - are both omitted, the quantifier specifies an exact number of required + matches "zz", "zzz", or "zzzz". A closing brace on its own is not a + special character. If the second number is omitted, but the comma is + present, there is no upper limit; if the second number and the comma + are both omitted, the quantifier specifies an exact number of required matches. Thus [aeiou]{3,} @@ -8251,65 +8267,65 @@ REPETITION \d{8} - matches exactly 8 digits. If the first number is omitted, the lower + matches exactly 8 digits. If the first number is omitted, the lower limit is taken as zero; in this case the upper limit must be present. X{,4} is interpreted as X{0,4} - This is a change in behaviour that happened in Perl 5.34.0 and PCRE2 - 10.43. In earlier versions such a sequence was not interpreted as a + This is a change in behaviour that happened in Perl 5.34.0 and PCRE2 + 10.43. In earlier versions such a sequence was not interpreted as a quantifier. Other regular expression engines may behave either way. - If the characters that follow an opening brace do not match the syntax + If the characters that follow an opening brace do not match the syntax of a quantifier, the brace is taken as a literal character. In particu- lar, this means that {,} is a literal string of three characters. Note that not every opening brace is potentially the start of a quanti- - fier because braces are used in other items such as \N{U+345} or + fier because braces are used in other items such as \N{U+345} or \k{name}. In UTF modes, quantifiers apply to characters rather than to individual - code units. Thus, for example, \x{100}{2} matches two characters, each + code units. Thus, for example, \x{100}{2} matches two characters, each of which is represented by a two-byte sequence in a UTF-8 string. Simi- - larly, \X{3} matches three Unicode extended grapheme clusters, each of - which may be several code units long (and they may be of different + larly, \X{3} matches three Unicode extended grapheme clusters, each of + which may be several code units long (and they may be of different lengths). The quantifier {0} is permitted, causing the expression to behave as if the previous item and the quantifier were not present. This may be use- - ful for capture groups that are referenced as subroutines from else- - where in the pattern (but see also the section entitled "Defining cap- + ful for capture groups that are referenced as subroutines from else- + where in the pattern (but see also the section entitled "Defining cap- ture groups for use by reference only" below). Except for parenthesized - groups, items that have a {0} quantifier are omitted from the compiled + groups, items that have a {0} quantifier are omitted from the compiled pattern. - For convenience, the three most common quantifiers have single-charac- + For convenience, the three most common quantifiers have single-charac- ter abbreviations: * is equivalent to {0,} + is equivalent to {1,} ? is equivalent to {0,1} - It is possible to construct infinite loops by following a group that - can match no characters with a quantifier that has no upper limit, for + It is possible to construct infinite loops by following a group that + can match no characters with a quantifier that has no upper limit, for example: (a?)* - Earlier versions of Perl and PCRE1 used to give an error at compile + Earlier versions of Perl and PCRE1 used to give an error at compile time for such patterns. However, because there are cases where this can be useful, such patterns are now accepted, but whenever an iteration of - such a group matches no characters, matching moves on to the next item - in the pattern instead of repeatedly matching an empty string. This - does not prevent backtracking into any of the iterations if a subse- + such a group matches no characters, matching moves on to the next item + in the pattern instead of repeatedly matching an empty string. This + does not prevent backtracking into any of the iterations if a subse- quent item fails to match. - By default, quantifiers are "greedy", that is, they match as much as - possible (up to the maximum number of permitted repetitions), without - causing the rest of the pattern to fail. The classic example of where + By default, quantifiers are "greedy", that is, they match as much as + possible (up to the maximum number of permitted repetitions), without + causing the rest of the pattern to fail. The classic example of where this gives problems is in trying to match comments in C programs. These - appear between /* and */ and within the comment, individual * and / - characters may appear. An attempt to match C comments by applying the + appear between /* and */ and within the comment, individual * and / + characters may appear. An attempt to match C comments by applying the pattern /\*.*\*/ @@ -8318,17 +8334,17 @@ REPETITION /* first comment */ not comment /* second comment */ - fails, because it matches the entire string owing to the greediness of - the .* item. However, if a quantifier is followed by a question mark, + fails, because it matches the entire string owing to the greediness of + the .* item. However, if a quantifier is followed by a question mark, it ceases to be greedy, and instead matches the minimum number of times possible, so the pattern /\*.*?\*/ - does the right thing with C comments. The meaning of the various quan- + does the right thing with C comments. The meaning of the various quan- tifiers is not otherwise changed, just the preferred number of matches. - Do not confuse this use of question mark with its use as a quantifier - in its own right. Because it has two uses, it can sometimes appear + Do not confuse this use of question mark with its use as a quantifier + in its own right. Because it has two uses, it can sometimes appear doubled, as in \d??\d @@ -8337,55 +8353,55 @@ REPETITION only way the rest of the pattern matches. If the PCRE2_UNGREEDY option is set (an option that is not available in - Perl), the quantifiers are not greedy by default, but individual ones - can be made greedy by following them with a question mark. In other + Perl), the quantifiers are not greedy by default, but individual ones + can be made greedy by following them with a question mark. In other words, it inverts the default behaviour. - When a parenthesized group is quantified with a minimum repeat count - that is greater than 1 or with a limited maximum, more memory is re- + When a parenthesized group is quantified with a minimum repeat count + that is greater than 1 or with a limited maximum, more memory is re- quired for the compiled pattern, in proportion to the size of the mini- mum or maximum. - If a pattern starts with .* or .{0,} and the PCRE2_DOTALL option - (equivalent to Perl's /s) is set, thus allowing the dot to match new- - lines, the pattern is implicitly anchored, because whatever follows - will be tried against every character position in the subject string, - so there is no point in retrying the overall match at any position af- - ter the first. PCRE2 normally treats such a pattern as though it were + If a pattern starts with .* or .{0,} and the PCRE2_DOTALL option + (equivalent to Perl's /s) is set, thus allowing the dot to match new- + lines, the pattern is implicitly anchored, because whatever follows + will be tried against every character position in the subject string, + so there is no point in retrying the overall match at any position af- + ter the first. PCRE2 normally treats such a pattern as though it were preceded by \A. - In cases where it is known that the subject string contains no new- - lines, it is worth setting PCRE2_DOTALL in order to obtain this opti- + In cases where it is known that the subject string contains no new- + lines, it is worth setting PCRE2_DOTALL in order to obtain this opti- mization, or alternatively, using ^ to indicate anchoring explicitly. - However, there are some cases where the optimization cannot be used. - When .* is inside capturing parentheses that are the subject of a - backreference elsewhere in the pattern, a match at the start may fail + However, there are some cases where the optimization cannot be used. + When .* is inside capturing parentheses that are the subject of a + backreference elsewhere in the pattern, a match at the start may fail where a later one succeeds. Consider, for example: (.*)abc\1 - If the subject is "xyz123abc123" the match point is the fourth charac- + If the subject is "xyz123abc123" the match point is the fourth charac- ter. For this reason, such a pattern is not implicitly anchored. - Another case where implicit anchoring is not applied is when the lead- - ing .* is inside an atomic group. Once again, a match at the start may + Another case where implicit anchoring is not applied is when the lead- + ing .* is inside an atomic group. Once again, a match at the start may fail where a later one succeeds. Consider this pattern: (?>.*?a)b - It matches "ab" in the subject "aab". The use of the backtracking con- - trol verbs (*PRUNE) and (*SKIP) also disable this optimization, and + It matches "ab" in the subject "aab". The use of the backtracking con- + trol verbs (*PRUNE) and (*SKIP) also disable this optimization, and there is an option, PCRE2_NO_DOTSTAR_ANCHOR, to do so explicitly. - When a capture group is repeated, the value captured is the substring + When a capture group is repeated, the value captured is the substring that matched the final iteration. For example, after (tweedle[dume]{3}\s*)+ has matched "tweedledum tweedledee" the value of the captured substring - is "tweedledee". However, if there are nested capture groups, the cor- - responding captured values may have been set in previous iterations. + is "tweedledee". However, if there are nested capture groups, the cor- + responding captured values may have been set in previous iterations. For example, after (a|(b))+ @@ -8395,57 +8411,57 @@ REPETITION ATOMIC GROUPING AND POSSESSIVE QUANTIFIERS - With both maximizing ("greedy") and minimizing ("ungreedy" or "lazy") - repetition, failure of what follows normally causes the repeated item - to be re-evaluated to see if a different number of repeats allows the - rest of the pattern to match. Sometimes it is useful to prevent this, - either to change the nature of the match, or to cause it fail earlier - than it otherwise might, when the author of the pattern knows there is + With both maximizing ("greedy") and minimizing ("ungreedy" or "lazy") + repetition, failure of what follows normally causes the repeated item + to be re-evaluated to see if a different number of repeats allows the + rest of the pattern to match. Sometimes it is useful to prevent this, + either to change the nature of the match, or to cause it fail earlier + than it otherwise might, when the author of the pattern knows there is no point in carrying on. - Consider, for example, the pattern \d+foo when applied to the subject + Consider, for example, the pattern \d+foo when applied to the subject line 123456bar After matching all 6 digits and then failing to match "foo", the normal - action of the matcher is to try again with only 5 digits matching the - \d+ item, and then with 4, and so on, before ultimately failing. - "Atomic grouping" (a term taken from Jeffrey Friedl's book) provides + action of the matcher is to try again with only 5 digits matching the + \d+ item, and then with 4, and so on, before ultimately failing. + "Atomic grouping" (a term taken from Jeffrey Friedl's book) provides the means for specifying that once a group has matched, it is not to be re-evaluated in this way. - If we use atomic grouping for the previous example, the matcher gives - up immediately on failing to match "foo" the first time. The notation + If we use atomic grouping for the previous example, the matcher gives + up immediately on failing to match "foo" the first time. The notation is a kind of special parenthesis, starting with (?> as in this example: (?>\d+)foo - Perl 5.28 introduced an experimental alphabetic form starting with (* + Perl 5.28 introduced an experimental alphabetic form starting with (* which may be easier to remember: (*atomic:\d+)foo - This kind of parenthesized group "locks up" the part of the pattern it + This kind of parenthesized group "locks up" the part of the pattern it contains once it has matched, and a failure further into the pattern is - prevented from backtracking into it. Backtracking past it to previous + prevented from backtracking into it. Backtracking past it to previous items, however, works as normal. An alternative description is that a group of this type matches exactly - the string of characters that an identical standalone pattern would + the string of characters that an identical standalone pattern would match, if anchored at the current point in the subject string. - Atomic groups are not capture groups. Simple cases such as the above - example can be thought of as a maximizing repeat that must swallow - everything it can. So, while both \d+ and \d+? are prepared to adjust - the number of digits they match in order to make the rest of the pat- + Atomic groups are not capture groups. Simple cases such as the above + example can be thought of as a maximizing repeat that must swallow + everything it can. So, while both \d+ and \d+? are prepared to adjust + the number of digits they match in order to make the rest of the pat- tern match, (?>\d+) can only match an entire sequence of digits. - Atomic groups in general can of course contain arbitrarily complicated + Atomic groups in general can of course contain arbitrarily complicated expressions, and can be nested. However, when the contents of an atomic - group is just a single repeated item, as in the example above, a sim- - pler notation, called a "possessive quantifier" can be used. This con- - sists of an additional + character following a quantifier. Using this + group is just a single repeated item, as in the example above, a sim- + pler notation, called a "possessive quantifier" can be used. This con- + sists of an additional + character following a quantifier. Using this notation, the previous example can be rewritten as \d++foo @@ -8455,46 +8471,46 @@ ATOMIC GROUPING AND POSSESSIVE QUANTIFIERS (abc|xyz){2,3}+ - Possessive quantifiers are always greedy; the setting of the PCRE2_UN- - GREEDY option is ignored. They are a convenient notation for the sim- - pler forms of atomic group. However, there is no difference in the - meaning of a possessive quantifier and the equivalent atomic group, - though there may be a performance difference; possessive quantifiers + Possessive quantifiers are always greedy; the setting of the PCRE2_UN- + GREEDY option is ignored. They are a convenient notation for the sim- + pler forms of atomic group. However, there is no difference in the + meaning of a possessive quantifier and the equivalent atomic group, + though there may be a performance difference; possessive quantifiers should be slightly faster. - The possessive quantifier syntax is an extension to the Perl 5.8 syn- - tax. Jeffrey Friedl originated the idea (and the name) in the first + The possessive quantifier syntax is an extension to the Perl 5.8 syn- + tax. Jeffrey Friedl originated the idea (and the name) in the first edition of his book. Mike McCloskey liked it, so implemented it when he - built Sun's Java package, and PCRE1 copied it from there. It found its + built Sun's Java package, and PCRE1 copied it from there. It found its way into Perl at release 5.10. - PCRE2 has an optimization that automatically "possessifies" certain - simple pattern constructs. For example, the sequence A+B is treated as - A++B because there is no point in backtracking into a sequence of A's + PCRE2 has an optimization that automatically "possessifies" certain + simple pattern constructs. For example, the sequence A+B is treated as + A++B because there is no point in backtracking into a sequence of A's when B must follow. This feature can be disabled by the PCRE2_NO_AUTO- POSSESS option, or starting the pattern with (*NO_AUTO_POSSESS). When a pattern contains an unlimited repeat inside a group that can it- - self be repeated an unlimited number of times, the use of an atomic - group is the only way to avoid some failing matches taking a very long + self be repeated an unlimited number of times, the use of an atomic + group is the only way to avoid some failing matches taking a very long time indeed. The pattern (\D+|<\d+>)*[!?] - matches an unlimited number of substrings that either consist of non- - digits, or digits enclosed in <>, followed by either ! or ?. When it + matches an unlimited number of substrings that either consist of non- + digits, or digits enclosed in <>, followed by either ! or ?. When it matches, it runs quickly. However, if it is applied to aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - it takes a long time before reporting failure. This is because the - string can be divided between the internal \D+ repeat and the external - * repeat in a large number of ways, and all have to be tried. (The ex- + it takes a long time before reporting failure. This is because the + string can be divided between the internal \D+ repeat and the external + * repeat in a large number of ways, and all have to be tried. (The ex- ample uses [!?] rather than a single character at the end, because both PCRE2 and Perl have an optimization that allows for fast failure when a - single character is used. They remember the last single character that - is required for a match, and fail early if it is not present in the - string.) If the pattern is changed so that it uses an atomic group, + single character is used. They remember the last single character that + is required for a match, and fail early if it is not present in the + string.) If the pattern is changed so that it uses an atomic group, like this: ((?>\D+)|<\d+>)*[!?] @@ -8505,28 +8521,28 @@ ATOMIC GROUPING AND POSSESSIVE QUANTIFIERS BACKREFERENCES Outside a character class, a backslash followed by a digit greater than - 0 (and possibly further digits) is a backreference to a capture group + 0 (and possibly further digits) is a backreference to a capture group earlier (that is, to its left) in the pattern, provided there have been that many previous capture groups. - However, if the decimal number following the backslash is less than 8, - it is always taken as a backreference, and causes an error only if - there are not that many capture groups in the entire pattern. In other + However, if the decimal number following the backslash is less than 8, + it is always taken as a backreference, and causes an error only if + there are not that many capture groups in the entire pattern. In other words, the group that is referenced need not be to the left of the ref- - erence for numbers less than 8. A "forward backreference" of this type + erence for numbers less than 8. A "forward backreference" of this type can make sense when a repetition is involved and the group to the right has participated in an earlier iteration. - It is not possible to have a numerical "forward backreference" to a - group whose number is 8 or more using this syntax because a sequence - such as \50 is interpreted as a character defined in octal. See the + It is not possible to have a numerical "forward backreference" to a + group whose number is 8 or more using this syntax because a sequence + such as \50 is interpreted as a character defined in octal. See the subsection entitled "Non-printing characters" above for further details - of the handling of digits following a backslash. Other forms of back- - referencing do not suffer from this restriction. In particular, there + of the handling of digits following a backslash. Other forms of back- + referencing do not suffer from this restriction. In particular, there is no problem when named capture groups are used (see below). - Another way of avoiding the ambiguity inherent in the use of digits - following a backslash is to use the \g escape sequence. This escape + Another way of avoiding the ambiguity inherent in the use of digits + following a backslash is to use the \g escape sequence. This escape must be followed by a signed or unsigned number, optionally enclosed in braces. These examples are all identical: @@ -8534,54 +8550,54 @@ BACKREFERENCES (ring), \g1 (ring), \g{1} - An unsigned number specifies an absolute reference without the ambigu- + An unsigned number specifies an absolute reference without the ambigu- ity that is present in the older syntax. It is also useful when literal - digits follow the reference. A signed number is a relative reference. + digits follow the reference. A signed number is a relative reference. Consider this example: (abc(def)ghi)\g{-1} The sequence \g{-1} is a reference to the capture group whose number is - one less than the number of the next group to be started, so in this - example (where the next group would be numbered 3) is it equivalent to - \2, and \g{-2} would be equivalent to \1. Note that if this construct - is inside a capture group, that group is included in the count, so in + one less than the number of the next group to be started, so in this + example (where the next group would be numbered 3) is it equivalent to + \2, and \g{-2} would be equivalent to \1. Note that if this construct + is inside a capture group, that group is included in the count, so in this example \g{-2} also refers to group 1: (A)(\g{-2}B) - The use of relative references can be helpful in long patterns, and - also in patterns that are created by joining together fragments that + The use of relative references can be helpful in long patterns, and + also in patterns that are created by joining together fragments that contain references within themselves. - The sequence \g{+1} is a reference to the next capture group that is - started after this item, and \g{+2} refers to the one after that, and - so on. This kind of forward reference can be useful in patterns that + The sequence \g{+1} is a reference to the next capture group that is + started after this item, and \g{+2} refers to the one after that, and + so on. This kind of forward reference can be useful in patterns that repeat. Perl does not support the use of + in this way. - A backreference matches whatever actually most recently matched the - capture group in the current subject string, rather than anything at + A backreference matches whatever actually most recently matched the + capture group in the current subject string, rather than anything at all that matches the group (see "Groups as subroutines" below for a way of doing that). So the pattern (sens|respons)e and \1ibility - matches "sense and sensibility" and "response and responsibility", but - not "sense and responsibility". If caseful matching is in force at the - time of the backreference, the case of letters is relevant. For exam- + matches "sense and sensibility" and "response and responsibility", but + not "sense and responsibility". If caseful matching is in force at the + time of the backreference, the case of letters is relevant. For exam- ple, ((?i)rah)\s+\1 - matches "rah rah" and "RAH RAH", but not "RAH rah", even though the + matches "rah rah" and "RAH RAH", but not "RAH rah", even though the original capture group is matched caselessly. - There are several different ways of writing backreferences to named - capture groups. The .NET syntax is \k{name}, the Python syntax is - (?=name), and the original Perl syntax is \k or \k'name'. All of - these are now supported by both Perl and PCRE2. Perl 5.10's unified - backreference syntax, in which \g can be used for both numeric and - named references, is also supported by PCRE2. We could rewrite the + There are several different ways of writing backreferences to named + capture groups. The .NET syntax is \k{name}, the Python syntax is + (?=name), and the original Perl syntax is \k or \k'name'. All of + these are now supported by both Perl and PCRE2. Perl 5.10's unified + backreference syntax, in which \g can be used for both numeric and + named references, is also supported by PCRE2. We could rewrite the above example in any of the following ways: (?(?i)rah)\s+\k @@ -8589,114 +8605,114 @@ BACKREFERENCES (?P(?i)rah)\s+(?P=p1) (?(?i)rah)\s+\g{p1} - A capture group that is referenced by name may appear in the pattern + A capture group that is referenced by name may appear in the pattern before or after the reference. - There may be more than one backreference to the same group. If a group - has not actually been used in a particular match, backreferences to it + There may be more than one backreference to the same group. If a group + has not actually been used in a particular match, backreferences to it always fail by default. For example, the pattern (a|(bc))\2 - always fails if it starts to match "a" rather than "bc". However, if + always fails if it starts to match "a" rather than "bc". However, if the PCRE2_MATCH_UNSET_BACKREF option is set at compile time, a backref- erence to an unset value matches an empty string. - Because there may be many capture groups in a pattern, all digits fol- - lowing a backslash are taken as part of a potential backreference num- - ber. If the pattern continues with a digit character, some delimiter - must be used to terminate the backreference. If the PCRE2_EXTENDED or - PCRE2_EXTENDED_MORE option is set, this can be white space. Otherwise, + Because there may be many capture groups in a pattern, all digits fol- + lowing a backslash are taken as part of a potential backreference num- + ber. If the pattern continues with a digit character, some delimiter + must be used to terminate the backreference. If the PCRE2_EXTENDED or + PCRE2_EXTENDED_MORE option is set, this can be white space. Otherwise, the \g{} syntax or an empty comment (see "Comments" below) can be used. Recursive backreferences - A backreference that occurs inside the group to which it refers fails - when the group is first used, so, for example, (a\1) never matches. - However, such references can be useful inside repeated groups. For ex- + A backreference that occurs inside the group to which it refers fails + when the group is first used, so, for example, (a\1) never matches. + However, such references can be useful inside repeated groups. For ex- ample, the pattern (a|b\1)+ matches any number of "a"s and also "aba", "ababbaa" etc. At each iter- ation of the group, the backreference matches the character string cor- - responding to the previous iteration. In order for this to work, the - pattern must be such that the first iteration does not need to match - the backreference. This can be done using alternation, as in the exam- + responding to the previous iteration. In order for this to work, the + pattern must be such that the first iteration does not need to match + the backreference. This can be done using alternation, as in the exam- ple above, or by a quantifier with a minimum of zero. For versions of PCRE2 less than 10.25, backreferences of this type used - to cause the group that they reference to be treated as an atomic - group. This restriction no longer applies, and backtracking into such + to cause the group that they reference to be treated as an atomic + group. This restriction no longer applies, and backtracking into such groups can occur as normal. ASSERTIONS - An assertion is a test on the characters following or preceding the + An assertion is a test on the characters following or preceding the current matching point that does not consume any characters. The simple - assertions coded as \b, \B, \A, \G, \Z, \z, ^ and $ are described + assertions coded as \b, \B, \A, \G, \Z, \z, ^ and $ are described above. - More complicated assertions are coded as parenthesized groups. There - are two kinds: those that look ahead of the current position in the - subject string, and those that look behind it, and in each case an as- - sertion may be positive (must match for the assertion to be true) or - negative (must not match for the assertion to be true). An assertion + More complicated assertions are coded as parenthesized groups. There + are two kinds: those that look ahead of the current position in the + subject string, and those that look behind it, and in each case an as- + sertion may be positive (must match for the assertion to be true) or + negative (must not match for the assertion to be true). An assertion group is matched in the normal way, and if it is true, matching contin- - ues after it, but with the matching position in the subject string re- + ues after it, but with the matching position in the subject string re- set to what it was before the assertion was processed. - The Perl-compatible lookaround assertions are atomic. If an assertion - is true, but there is a subsequent matching failure, there is no back- - tracking into the assertion. However, there are some cases where non- - atomic assertions can be useful. PCRE2 has some support for these, de- + The Perl-compatible lookaround assertions are atomic. If an assertion + is true, but there is a subsequent matching failure, there is no back- + tracking into the assertion. However, there are some cases where non- + atomic assertions can be useful. PCRE2 has some support for these, de- scribed in the section entitled "Non-atomic assertions" below, but they are not Perl-compatible. - A lookaround assertion may appear as the condition in a conditional - group (see below). In this case, the result of matching the assertion + A lookaround assertion may appear as the condition in a conditional + group (see below). In this case, the result of matching the assertion determines which branch of the condition is followed. - Assertion groups are not capture groups. If an assertion contains cap- - ture groups within it, these are counted for the purposes of numbering - the capture groups in the whole pattern. Within each branch of an as- - sertion, locally captured substrings may be referenced in the usual - way. For example, a sequence such as (.)\g{-1} can be used to check + Assertion groups are not capture groups. If an assertion contains cap- + ture groups within it, these are counted for the purposes of numbering + the capture groups in the whole pattern. Within each branch of an as- + sertion, locally captured substrings may be referenced in the usual + way. For example, a sequence such as (.)\g{-1} can be used to check that two adjacent characters are the same. - When a branch within an assertion fails to match, any substrings that - were captured are discarded (as happens with any pattern branch that - fails to match). A negative assertion is true only when all its + When a branch within an assertion fails to match, any substrings that + were captured are discarded (as happens with any pattern branch that + fails to match). A negative assertion is true only when all its branches fail to match; this means that no captured substrings are ever - retained after a successful negative assertion. When an assertion con- + retained after a successful negative assertion. When an assertion con- tains a matching branch, what happens depends on the type of assertion. - For a positive assertion, internally captured substrings in the suc- - cessful branch are retained, and matching continues with the next pat- - tern item after the assertion. For a negative assertion, a matching - branch means that the assertion is not true. If such an assertion is - being used as a condition in a conditional group (see below), captured - substrings are retained, because matching continues with the "no" + For a positive assertion, internally captured substrings in the suc- + cessful branch are retained, and matching continues with the next pat- + tern item after the assertion. For a negative assertion, a matching + branch means that the assertion is not true. If such an assertion is + being used as a condition in a conditional group (see below), captured + substrings are retained, because matching continues with the "no" branch of the condition. For other failing negative assertions, control passes to the previous backtracking point, thus discarding any captured strings within the assertion. - Most assertion groups may be repeated; though it makes no sense to as- + Most assertion groups may be repeated; though it makes no sense to as- sert the same thing several times, the side effect of capturing in pos- itive assertions may occasionally be useful. However, an assertion that - forms the condition for a conditional group may not be quantified. - PCRE2 used to restrict the repetition of assertions, but from release - 10.35 the only restriction is that an unlimited maximum repetition is - changed to be one more than the minimum. For example, {3,} is treated + forms the condition for a conditional group may not be quantified. + PCRE2 used to restrict the repetition of assertions, but from release + 10.35 the only restriction is that an unlimited maximum repetition is + changed to be one more than the minimum. For example, {3,} is treated as {3,4}. Alphabetic assertion names - Traditionally, symbolic sequences such as (?= and (?<= have been used - to specify lookaround assertions. Perl 5.28 introduced some experimen- + Traditionally, symbolic sequences such as (?= and (?<= have been used + to specify lookaround assertions. Perl 5.28 introduced some experimen- tal alphabetic alternatives which might be easier to remember. They all - start with (* instead of (? and must be written using lower case let- + start with (* instead of (? and must be written using lower case let- ters. PCRE2 supports the following synonyms: (*positive_lookahead: or (*pla: is the same as (?= @@ -8704,8 +8720,8 @@ ASSERTIONS (*positive_lookbehind: or (*plb: is the same as (?<= (*negative_lookbehind: or (*nlb: is the same as (? .*? \b\1\b ){2} - For a subject such as "word1 word2 word3 word2 word3 word4" the result - is "word3". How does it work? At the start, ^(?x) anchors the pattern + For a subject such as "word1 word2 word3 word2 word3 word4" the result + is "word3". How does it work? At the start, ^(?x) anchors the pattern and sets the "x" option, which causes white space (introduced for read- - ability) to be ignored. Inside the assertion, the greedy .* at first + ability) to be ignored. Inside the assertion, the greedy .* at first consumes the entire string, but then has to backtrack until the rest of - the assertion can match a word, which is captured by group 1. In other - words, when the assertion first succeeds, it captures the right-most + the assertion can match a word, which is captured by group 1. In other + words, when the assertion first succeeds, it captures the right-most word in the string. - The current matching point is then reset to the start of the subject, - and the rest of the pattern match checks for two occurrences of the - captured word, using an ungreedy .*? to scan from the left. If this - succeeds, we are done, but if the last word in the string does not oc- - cur twice, this part of the pattern fails. If a traditional atomic - lookahead (?= or (*pla: had been used, the assertion could not be re- + The current matching point is then reset to the start of the subject, + and the rest of the pattern match checks for two occurrences of the + captured word, using an ungreedy .*? to scan from the left. If this + succeeds, we are done, but if the last word in the string does not oc- + cur twice, this part of the pattern fails. If a traditional atomic + lookahead (?= or (*pla: had been used, the assertion could not be re- entered, and the whole match would fail. The pattern would succeed only if the very last word in the subject was found twice. - Using a non-atomic lookahead, however, means that when the last word - does not occur twice in the string, the lookahead can backtrack and - find the second-last word, and so on, until either the match succeeds, + Using a non-atomic lookahead, however, means that when the last word + does not occur twice in the string, the lookahead can backtrack and + find the second-last word, and so on, until either the match succeeds, or all words have been tested. Two conditions must be met for a non-atomic assertion to be useful: the - contents of one or more capturing groups must change after a backtrack - into the assertion, and there must be a backreference to a changed - group later in the pattern. If this is not the case, the rest of the - pattern match fails exactly as before because nothing has changed, so + contents of one or more capturing groups must change after a backtrack + into the assertion, and there must be a backreference to a changed + group later in the pattern. If this is not the case, the rest of the + pattern match fails exactly as before because nothing has changed, so using a non-atomic assertion just wastes resources. - There is one exception to backtracking into a non-atomic assertion. If - an (*ACCEPT) control verb is triggered, the assertion succeeds atomi- - cally. That is, a subsequent match failure cannot backtrack into the + There is one exception to backtracking into a non-atomic assertion. If + an (*ACCEPT) control verb is triggered, the assertion succeeds atomi- + cally. That is, a subsequent match failure cannot backtrack into the assertion. - Non-atomic assertions are not supported by the alternative matching + Non-atomic assertions are not supported by the alternative matching function pcre2_dfa_match(). They are supported by JIT, but only if they do not contain any control verbs such as (*ACCEPT). (This may change in future). Note that assertions that appear as conditions for conditional @@ -8914,42 +8930,42 @@ NON-ATOMIC ASSERTIONS SCRIPT RUNS - In concept, a script run is a sequence of characters that are all from - the same Unicode script such as Latin or Greek. However, because some - scripts are commonly used together, and because some diacritical and - other marks are used with multiple scripts, it is not that simple. + In concept, a script run is a sequence of characters that are all from + the same Unicode script such as Latin or Greek. However, because some + scripts are commonly used together, and because some diacritical and + other marks are used with multiple scripts, it is not that simple. There is a full description of the rules that PCRE2 uses in the section entitled "Script Runs" in the pcre2unicode documentation. - If part of a pattern is enclosed between (*script_run: or (*sr: and a - closing parenthesis, it fails if the sequence of characters that it - matches are not a script run. After a failure, normal backtracking oc- - curs. Script runs can be used to detect spoofing attacks using charac- - ters that look the same, but are from different scripts. The string - "paypal.com" is an infamous example, where the letters could be a mix- + If part of a pattern is enclosed between (*script_run: or (*sr: and a + closing parenthesis, it fails if the sequence of characters that it + matches are not a script run. After a failure, normal backtracking oc- + curs. Script runs can be used to detect spoofing attacks using charac- + ters that look the same, but are from different scripts. The string + "paypal.com" is an infamous example, where the letters could be a mix- ture of Latin and Cyrillic. This pattern ensures that the matched char- acters in a sequence of non-spaces that follow white space are a script run: \s+(*sr:\S+) - To be sure that they are all from the Latin script (for example), a + To be sure that they are all from the Latin script (for example), a lookahead can be used: \s+(?=\p{Latin})(*sr:\S+) This works as long as the first character is expected to be a character - in that script, and not (for example) punctuation, which is allowed - with any script. If this is not the case, a more creative lookahead is - needed. For example, if digits, underscore, and dots are permitted at + in that script, and not (for example) punctuation, which is allowed + with any script. If this is not the case, a more creative lookahead is + needed. For example, if digits, underscore, and dots are permitted at the start: \s+(?=[0-9_.]*\p{Latin})(*sr:\S+) - In many cases, backtracking into a script run pattern fragment is not - desirable. The script run can employ an atomic group to prevent this. - Because this is a common requirement, a shorthand notation is provided + In many cases, backtracking into a script run pattern fragment is not + desirable. The script run can employ an atomic group to prevent this. + Because this is a common requirement, a shorthand notation is provided by (*atomic_script_run: or (*asr: (*asr:...) is the same as (*sr:(?>...)) @@ -8957,13 +8973,13 @@ SCRIPT RUNS Note that the atomic group is inside the script run. Putting it outside would not prevent backtracking into the script run pattern. - Support for script runs is not available if PCRE2 is compiled without + Support for script runs is not available if PCRE2 is compiled without Unicode support. A compile-time error is given if any of the above con- - structs is encountered. Script runs are not supported by the alternate - matching function, pcre2_dfa_match() because they use the same mecha- + structs is encountered. Script runs are not supported by the alternate + matching function, pcre2_dfa_match() because they use the same mecha- nism as capturing parentheses. - Warning: The (*ACCEPT) control verb (see below) should not be used + Warning: The (*ACCEPT) control verb (see below) should not be used within a script run group, because it causes an immediate exit from the group, bypassing the script run checking. @@ -8972,117 +8988,117 @@ CONDITIONAL GROUPS It is possible to cause the matching process to obey a pattern fragment conditionally or to choose between two alternative fragments, depending - on the result of an assertion, or whether a specific capture group has + on the result of an assertion, or whether a specific capture group has already been matched. The two possible forms of conditional group are: (?(condition)yes-pattern) (?(condition)yes-pattern|no-pattern) - If the condition is satisfied, the yes-pattern is used; otherwise the - no-pattern (if present) is used. An absent no-pattern is equivalent to - an empty string (it always matches). If there are more than two alter- - natives in the group, a compile-time error occurs. Each of the two al- + If the condition is satisfied, the yes-pattern is used; otherwise the + no-pattern (if present) is used. An absent no-pattern is equivalent to + an empty string (it always matches). If there are more than two alter- + natives in the group, a compile-time error occurs. Each of the two al- ternatives may itself contain nested groups of any form, including con- - ditional groups; the restriction to two alternatives applies only at - the level of the condition itself. This pattern fragment is an example + ditional groups; the restriction to two alternatives applies only at + the level of the condition itself. This pattern fragment is an example where the alternatives are complex: (?(1) (A|B|C) | (D | (?(2)E|F) | E) ) There are five kinds of condition: references to capture groups, refer- - ences to recursion, two pseudo-conditions called DEFINE and VERSION, + ences to recursion, two pseudo-conditions called DEFINE and VERSION, and assertions. Checking for a used capture group by number - If the text between the parentheses consists of a sequence of digits, - the condition is true if a capture group of that number has previously - matched. If there is more than one capture group with the same number - (see the earlier section about duplicate group numbers), the condition - is true if any of them have matched. An alternative notation, which is + If the text between the parentheses consists of a sequence of digits, + the condition is true if a capture group of that number has previously + matched. If there is more than one capture group with the same number + (see the earlier section about duplicate group numbers), the condition + is true if any of them have matched. An alternative notation, which is a PCRE2 extension, not supported by Perl, is to precede the digits with a plus or minus sign. In this case, the group number is relative rather - than absolute. The most recently opened capture group (which could be - enclosing this condition) can be referenced by (?(-1), the next most + than absolute. The most recently opened capture group (which could be + enclosing this condition) can be referenced by (?(-1), the next most recent by (?(-2), and so on. Inside loops it can also make sense to re- - fer to subsequent groups. The next capture group to be opened can be - referenced as (?(+1), and so on. The value zero in any of these forms + fer to subsequent groups. The next capture group to be opened can be + referenced as (?(+1), and so on. The value zero in any of these forms is not used; it provokes a compile-time error. - Consider the following pattern, which contains non-significant white - space to make it more readable (assume the PCRE2_EXTENDED option) and + Consider the following pattern, which contains non-significant white + space to make it more readable (assume the PCRE2_EXTENDED option) and to divide it into three parts for ease of discussion: ( \( )? [^()]+ (?(1) \) ) - The first part matches an optional opening parenthesis, and if that + The first part matches an optional opening parenthesis, and if that character is present, sets it as the first captured substring. The sec- - ond part matches one or more characters that are not parentheses. The - third part is a conditional group that tests whether or not the first - capture group matched. If it did, that is, if subject started with an - opening parenthesis, the condition is true, and so the yes-pattern is - executed and a closing parenthesis is required. Otherwise, since no- + ond part matches one or more characters that are not parentheses. The + third part is a conditional group that tests whether or not the first + capture group matched. If it did, that is, if subject started with an + opening parenthesis, the condition is true, and so the yes-pattern is + executed and a closing parenthesis is required. Otherwise, since no- pattern is not present, the conditional group matches nothing. In other - words, this pattern matches a sequence of non-parentheses, optionally + words, this pattern matches a sequence of non-parentheses, optionally enclosed in parentheses. - If you were embedding this pattern in a larger one, you could use a + If you were embedding this pattern in a larger one, you could use a relative reference: ...other stuff... ( \( )? [^()]+ (?(-1) \) ) ... - This makes the fragment independent of the parentheses in the larger + This makes the fragment independent of the parentheses in the larger pattern. Checking for a used capture group by name - Perl uses the syntax (?()...) or (?('name')...) to test for a - used capture group by name. For compatibility with earlier versions of - PCRE1, which had this facility before Perl, the syntax (?(name)...) is - also recognized. Note, however, that undelimited names consisting of - the letter R followed by digits are ambiguous (see the following sec- + Perl uses the syntax (?()...) or (?('name')...) to test for a + used capture group by name. For compatibility with earlier versions of + PCRE1, which had this facility before Perl, the syntax (?(name)...) is + also recognized. Note, however, that undelimited names consisting of + the letter R followed by digits are ambiguous (see the following sec- tion). Rewriting the above example to use a named group gives this: (? \( )? [^()]+ (?() \) ) - If the name used in a condition of this kind is a duplicate, the test - is applied to all groups of the same name, and is true if any one of + If the name used in a condition of this kind is a duplicate, the test + is applied to all groups of the same name, and is true if any one of them has matched. Checking for pattern recursion - "Recursion" in this sense refers to any subroutine-like call from one - part of the pattern to another, whether or not it is actually recur- - sive. See the sections entitled "Recursive patterns" and "Groups as + "Recursion" in this sense refers to any subroutine-like call from one + part of the pattern to another, whether or not it is actually recur- + sive. See the sections entitled "Recursive patterns" and "Groups as subroutines" below for details of recursion and subroutine calls. - If a condition is the string (R), and there is no capture group with - the name R, the condition is true if matching is currently in a recur- - sion or subroutine call to the whole pattern or any capture group. If - digits follow the letter R, and there is no group with that name, the - condition is true if the most recent call is into a group with the - given number, which must exist somewhere in the overall pattern. This + If a condition is the string (R), and there is no capture group with + the name R, the condition is true if matching is currently in a recur- + sion or subroutine call to the whole pattern or any capture group. If + digits follow the letter R, and there is no group with that name, the + condition is true if the most recent call is into a group with the + given number, which must exist somewhere in the overall pattern. This is a contrived example that is equivalent to a+b: ((?(R1)a+|(?1)b)) - However, in both cases, if there is a capture group with a matching - name, the condition tests for its being set, as described in the sec- - tion above, instead of testing for recursion. For example, creating a - group with the name R1 by adding (?) to the above pattern com- + However, in both cases, if there is a capture group with a matching + name, the condition tests for its being set, as described in the sec- + tion above, instead of testing for recursion. For example, creating a + group with the name R1 by adding (?) to the above pattern com- pletely changes its meaning. If a name preceded by ampersand follows the letter R, for example: (?(R&name)...) - the condition is true if the most recent recursion is into a group of + the condition is true if the most recent recursion is into a group of that name (which must exist within the pattern). This condition does not check the entire recursion stack. It tests only - the current level. If the name used in a condition of this kind is a - duplicate, the test is applied to all groups of the same name, and is + the current level. If the name used in a condition of this kind is a + duplicate, the test is applied to all groups of the same name, and is true if any one of them is the most recent recursion. At "top level", all these recursion test conditions are false. @@ -9090,111 +9106,111 @@ CONDITIONAL GROUPS Defining capture groups for use by reference only If the condition is the string (DEFINE), the condition is always false, - even if there is a group with the name DEFINE. In this case, there may + even if there is a group with the name DEFINE. In this case, there may be only one alternative in the rest of the conditional group. It is al- - ways skipped if control reaches this point in the pattern; the idea of - DEFINE is that it can be used to define subroutines that can be refer- - enced from elsewhere. (The use of subroutines is described below.) For - example, a pattern to match an IPv4 address such as "192.168.23.245" + ways skipped if control reaches this point in the pattern; the idea of + DEFINE is that it can be used to define subroutines that can be refer- + enced from elsewhere. (The use of subroutines is described below.) For + example, a pattern to match an IPv4 address such as "192.168.23.245" could be written like this (ignore white space and line breaks): (?(DEFINE) (? 2[0-4]\d | 25[0-5] | 1\d\d | [1-9]?\d) ) \b (?&byte) (\.(?&byte)){3} \b - The first part of the pattern is a DEFINE group inside which another - group named "byte" is defined. This matches an individual component of - an IPv4 address (a number less than 256). When matching takes place, - this part of the pattern is skipped because DEFINE acts like a false - condition. The rest of the pattern uses references to the named group - to match the four dot-separated components of an IPv4 address, insist- + The first part of the pattern is a DEFINE group inside which another + group named "byte" is defined. This matches an individual component of + an IPv4 address (a number less than 256). When matching takes place, + this part of the pattern is skipped because DEFINE acts like a false + condition. The rest of the pattern uses references to the named group + to match the four dot-separated components of an IPv4 address, insist- ing on a word boundary at each end. Checking the PCRE2 version - Programs that link with a PCRE2 library can check the version by call- - ing pcre2_config() with appropriate arguments. Users of applications - that do not have access to the underlying code cannot do this. A spe- - cial "condition" called VERSION exists to allow such users to discover + Programs that link with a PCRE2 library can check the version by call- + ing pcre2_config() with appropriate arguments. Users of applications + that do not have access to the underlying code cannot do this. A spe- + cial "condition" called VERSION exists to allow such users to discover which version of PCRE2 they are dealing with by using this condition to - match a string such as "yesno". VERSION must be followed either by "=" + match a string such as "yesno". VERSION must be followed either by "=" or ">=" and a version number. For example: (?(VERSION>=10.4)yes|no) - This pattern matches "yes" if the PCRE2 version is greater or equal to - 10.4, or "no" otherwise. The fractional part of the version number may + This pattern matches "yes" if the PCRE2 version is greater or equal to + 10.4, or "no" otherwise. The fractional part of the version number may not contain more than two digits. Assertion conditions - If the condition is not in any of the above formats, it must be a - parenthesized assertion. This may be a positive or negative lookahead - or lookbehind assertion. However, it must be a traditional atomic as- + If the condition is not in any of the above formats, it must be a + parenthesized assertion. This may be a positive or negative lookahead + or lookbehind assertion. However, it must be a traditional atomic as- sertion, not one of the non-atomic assertions. - Consider this pattern, again containing non-significant white space, + Consider this pattern, again containing non-significant white space, and with the two alternatives on the second line: (?(?=[^a-z]*[a-z]) \d{2}-[a-z]{3}-\d{2} | \d{2}-\d{2}-\d{2} ) - The condition is a positive lookahead assertion that matches an op- + The condition is a positive lookahead assertion that matches an op- tional sequence of non-letters followed by a letter. In other words, it tests for the presence of at least one letter in the subject. If a let- - ter is found, the subject is matched against the first alternative; - otherwise it is matched against the second. This pattern matches - strings in one of the two forms dd-aaa-dd or dd-dd-dd, where aaa are + ter is found, the subject is matched against the first alternative; + otherwise it is matched against the second. This pattern matches + strings in one of the two forms dd-aaa-dd or dd-dd-dd, where aaa are letters and dd are digits. When an assertion that is a condition contains capture groups, any cap- - turing that occurs in a matching branch is retained afterwards, for - both positive and negative assertions, because matching always contin- - ues after the assertion, whether it succeeds or fails. (Compare non- - conditional assertions, for which captures are retained only for posi- + turing that occurs in a matching branch is retained afterwards, for + both positive and negative assertions, because matching always contin- + ues after the assertion, whether it succeeds or fails. (Compare non- + conditional assertions, for which captures are retained only for posi- tive assertions that succeed.) COMMENTS There are two ways of including comments in patterns that are processed - by PCRE2. In both cases, the start of the comment must not be in a - character class, nor in the middle of any other sequence of related - characters such as (?: or a group name or number. The characters that + by PCRE2. In both cases, the start of the comment must not be in a + character class, nor in the middle of any other sequence of related + characters such as (?: or a group name or number. The characters that make up a comment play no part in the pattern matching. - The sequence (?# marks the start of a comment that continues up to the - next closing parenthesis. Nested parentheses are not permitted. If the - PCRE2_EXTENDED or PCRE2_EXTENDED_MORE option is set, an unescaped # - character also introduces a comment, which in this case continues to - immediately after the next newline character or character sequence in + The sequence (?# marks the start of a comment that continues up to the + next closing parenthesis. Nested parentheses are not permitted. If the + PCRE2_EXTENDED or PCRE2_EXTENDED_MORE option is set, an unescaped # + character also introduces a comment, which in this case continues to + immediately after the next newline character or character sequence in the pattern. Which characters are interpreted as newlines is controlled - by an option passed to the compiling function or by a special sequence + by an option passed to the compiling function or by a special sequence at the start of the pattern, as described in the section entitled "New- line conventions" above. Note that the end of this type of comment is a - literal newline sequence in the pattern; escape sequences that happen + literal newline sequence in the pattern; escape sequences that happen to represent a newline do not count. For example, consider this pattern - when PCRE2_EXTENDED is set, and the default newline convention (a sin- + when PCRE2_EXTENDED is set, and the default newline convention (a sin- gle linefeed character) is in force: abc #comment \n still comment - On encountering the # character, pcre2_compile() skips along, looking - for a newline in the pattern. The sequence \n is still literal at this - stage, so it does not terminate the comment. Only an actual character + On encountering the # character, pcre2_compile() skips along, looking + for a newline in the pattern. The sequence \n is still literal at this + stage, so it does not terminate the comment. Only an actual character with the code value 0x0a (the default newline) does so. RECURSIVE PATTERNS - Consider the problem of matching a string in parentheses, allowing for - unlimited nested parentheses. Without the use of recursion, the best - that can be done is to use a pattern that matches up to some fixed - depth of nesting. It is not possible to handle an arbitrary nesting + Consider the problem of matching a string in parentheses, allowing for + unlimited nested parentheses. Without the use of recursion, the best + that can be done is to use a pattern that matches up to some fixed + depth of nesting. It is not possible to handle an arbitrary nesting depth. For some time, Perl has provided a facility that allows regular expres- - sions to recurse (amongst other things). It does this by interpolating - Perl code in the expression at run time, and the code can refer to the + sions to recurse (amongst other things). It does this by interpolating + Perl code in the expression at run time, and the code can refer to the expression itself. A Perl pattern using code interpolation to solve the parentheses problem can be created like this: @@ -9203,67 +9219,67 @@ RECURSIVE PATTERNS The (?p{...}) item interpolates Perl code at run time, and in this case refers recursively to the pattern in which it appears. - Obviously, PCRE2 cannot support the interpolation of Perl code. In- - stead, it supports special syntax for recursion of the entire pattern, + Obviously, PCRE2 cannot support the interpolation of Perl code. In- + stead, it supports special syntax for recursion of the entire pattern, and also for individual capture group recursion. After its introduction in PCRE1 and Python, this kind of recursion was subsequently introduced into Perl at release 5.10. - A special item that consists of (? followed by a number greater than - zero and a closing parenthesis is a recursive subroutine call of the - capture group of the given number, provided that it occurs inside that - group. (If not, it is a non-recursive subroutine call, which is de- + A special item that consists of (? followed by a number greater than + zero and a closing parenthesis is a recursive subroutine call of the + capture group of the given number, provided that it occurs inside that + group. (If not, it is a non-recursive subroutine call, which is de- scribed in the next section.) The special item (?R) or (?0) is a recur- sive call of the entire regular expression. - This PCRE2 pattern solves the nested parentheses problem (assume the + This PCRE2 pattern solves the nested parentheses problem (assume the PCRE2_EXTENDED option is set so that white space is ignored): \( ( [^()]++ | (?R) )* \) - First it matches an opening parenthesis. Then it matches any number of - substrings which can either be a sequence of non-parentheses, or a re- + First it matches an opening parenthesis. Then it matches any number of + substrings which can either be a sequence of non-parentheses, or a re- cursive match of the pattern itself (that is, a correctly parenthesized - substring). Finally there is a closing parenthesis. Note the use of a - possessive quantifier to avoid backtracking into sequences of non- + substring). Finally there is a closing parenthesis. Note the use of a + possessive quantifier to avoid backtracking into sequences of non- parentheses. - If this were part of a larger pattern, you would not want to recurse + If this were part of a larger pattern, you would not want to recurse the entire pattern, so instead you could use this: ( \( ( [^()]++ | (?1) )* \) ) - We have put the pattern into parentheses, and caused the recursion to + We have put the pattern into parentheses, and caused the recursion to refer to them instead of the whole pattern. - In a larger pattern, keeping track of parenthesis numbers can be - tricky. This is made easier by the use of relative references. Instead + In a larger pattern, keeping track of parenthesis numbers can be + tricky. This is made easier by the use of relative references. Instead of (?1) in the pattern above you can write (?-2) to refer to the second - most recently opened parentheses preceding the recursion. In other - words, a negative number counts capturing parentheses leftwards from + most recently opened parentheses preceding the recursion. In other + words, a negative number counts capturing parentheses leftwards from the point at which it is encountered. - Be aware however, that if duplicate capture group numbers are in use, - relative references refer to the earliest group with the appropriate + Be aware however, that if duplicate capture group numbers are in use, + relative references refer to the earliest group with the appropriate number. Consider, for example: (?|(a)|(b)) (c) (?-2) The first two capture groups (a) and (b) are both numbered 1, and group - (c) is number 2. When the reference (?-2) is encountered, the second - most recently opened parentheses has the number 1, but it is the first + (c) is number 2. When the reference (?-2) is encountered, the second + most recently opened parentheses has the number 1, but it is the first such group (the (a) group) to which the recursion refers. This would be - the same if an absolute reference (?1) was used. In other words, rela- + the same if an absolute reference (?1) was used. In other words, rela- tive references are just a shorthand for computing a group number. - It is also possible to refer to subsequent capture groups, by writing - references such as (?+2). However, these cannot be recursive because - the reference is not inside the parentheses that are referenced. They - are always non-recursive subroutine calls, as described in the next + It is also possible to refer to subsequent capture groups, by writing + references such as (?+2). However, these cannot be recursive because + the reference is not inside the parentheses that are referenced. They + are always non-recursive subroutine calls, as described in the next section. - An alternative approach is to use named parentheses. The Perl syntax - for this is (?&name); PCRE1's earlier syntax (?P>name) is also sup- + An alternative approach is to use named parentheses. The Perl syntax + for this is (?&name); PCRE1's earlier syntax (?P>name) is also sup- ported. We could rewrite the above example as follows: (? \( ( [^()]++ | (?&pn) )* \) ) @@ -9272,57 +9288,57 @@ RECURSIVE PATTERNS used. The example pattern that we have been looking at contains nested unlim- - ited repeats, and so the use of a possessive quantifier for matching - strings of non-parentheses is important when applying the pattern to + ited repeats, and so the use of a possessive quantifier for matching + strings of non-parentheses is important when applying the pattern to strings that do not match. For example, when this pattern is applied to (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa() - it yields "no match" quickly. However, if a possessive quantifier is - not used, the match runs for a very long time indeed because there are - so many different ways the + and * repeats can carve up the subject, + it yields "no match" quickly. However, if a possessive quantifier is + not used, the match runs for a very long time indeed because there are + so many different ways the + and * repeats can carve up the subject, and all have to be tested before failure can be reported. - At the end of a match, the values of capturing parentheses are those - from the outermost level. If you want to obtain intermediate values, a + At the end of a match, the values of capturing parentheses are those + from the outermost level. If you want to obtain intermediate values, a callout function can be used (see below and the pcre2callout documenta- tion). If the pattern above is matched against (ab(cd)ef) - the value for the inner capturing parentheses (numbered 2) is "ef", - which is the last value taken on at the top level. If a capture group - is not matched at the top level, its final captured value is unset, - even if it was (temporarily) set at a deeper level during the matching + the value for the inner capturing parentheses (numbered 2) is "ef", + which is the last value taken on at the top level. If a capture group + is not matched at the top level, its final captured value is unset, + even if it was (temporarily) set at a deeper level during the matching process. - Do not confuse the (?R) item with the condition (R), which tests for - recursion. Consider this pattern, which matches text in angle brack- - ets, allowing for arbitrary nesting. Only digits are allowed in nested - brackets (that is, when recursing), whereas any characters are permit- + Do not confuse the (?R) item with the condition (R), which tests for + recursion. Consider this pattern, which matches text in angle brack- + ets, allowing for arbitrary nesting. Only digits are allowed in nested + brackets (that is, when recursing), whereas any characters are permit- ted at the outer level. < (?: (?(R) \d++ | [^<>]*+) | (?R)) * > - In this pattern, (?(R) is the start of a conditional group, with two - different alternatives for the recursive and non-recursive cases. The + In this pattern, (?(R) is the start of a conditional group, with two + different alternatives for the recursive and non-recursive cases. The (?R) item is the actual recursive call. Differences in recursion processing between PCRE2 and Perl Some former differences between PCRE2 and Perl no longer exist. - Before release 10.30, recursion processing in PCRE2 differed from Perl - in that a recursive subroutine call was always treated as an atomic - group. That is, once it had matched some of the subject string, it was - never re-entered, even if it contained untried alternatives and there - was a subsequent matching failure. (Historical note: PCRE implemented + Before release 10.30, recursion processing in PCRE2 differed from Perl + in that a recursive subroutine call was always treated as an atomic + group. That is, once it had matched some of the subject string, it was + never re-entered, even if it contained untried alternatives and there + was a subsequent matching failure. (Historical note: PCRE implemented recursion before Perl did.) - Starting with release 10.30, recursive subroutine calls are no longer + Starting with release 10.30, recursive subroutine calls are no longer treated as atomic. That is, they can be re-entered to try unused alter- - natives if there is a matching failure later in the pattern. This is - now compatible with the way Perl works. If you want a subroutine call + natives if there is a matching failure later in the pattern. This is + now compatible with the way Perl works. If you want a subroutine call to be atomic, you must explicitly enclose it in an atomic group. Supporting backtracking into recursions simplifies certain types of re- @@ -9330,47 +9346,47 @@ RECURSIVE PATTERNS ^((.)(?1)\2|.?)$ - The second branch in the group matches a single central character in - the palindrome when there are an odd number of characters, or nothing - when there are an even number of characters, but in order to work it - has to be able to try the second case when the rest of the pattern + The second branch in the group matches a single central character in + the palindrome when there are an odd number of characters, or nothing + when there are an even number of characters, but in order to work it + has to be able to try the second case when the rest of the pattern match fails. If you want to match typical palindromic phrases, the pat- - tern has to ignore all non-word characters, which can be done like + tern has to ignore all non-word characters, which can be done like this: ^\W*+((.)\W*+(?1)\W*+\2|\W*+.?)\W*+$ - If run with the PCRE2_CASELESS option, this pattern matches phrases - such as "A man, a plan, a canal: Panama!". Note the use of the posses- - sive quantifier *+ to avoid backtracking into sequences of non-word + If run with the PCRE2_CASELESS option, this pattern matches phrases + such as "A man, a plan, a canal: Panama!". Note the use of the posses- + sive quantifier *+ to avoid backtracking into sequences of non-word characters. Without this, PCRE2 takes a great deal longer (ten times or - more) to match typical phrases, and Perl takes so long that you think + more) to match typical phrases, and Perl takes so long that you think it has gone into a loop. - Another way in which PCRE2 and Perl used to differ in their recursion - processing is in the handling of captured values. Formerly in Perl, - when a group was called recursively or as a subroutine (see the next + Another way in which PCRE2 and Perl used to differ in their recursion + processing is in the handling of captured values. Formerly in Perl, + when a group was called recursively or as a subroutine (see the next section), it had no access to any values that were captured outside the - recursion, whereas in PCRE2 these values can be referenced. Consider + recursion, whereas in PCRE2 these values can be referenced. Consider this pattern: ^(.)(\1|a(?2)) - This pattern matches "bab". The first capturing parentheses match "b", + This pattern matches "bab". The first capturing parentheses match "b", then in the second group, when the backreference \1 fails to match "b", the second alternative matches "a" and then recurses. In the recursion, - \1 does now match "b" and so the whole match succeeds. This match used + \1 does now match "b" and so the whole match succeeds. This match used to fail in Perl, but in later versions (I tried 5.024) it now works. GROUPS AS SUBROUTINES - If the syntax for a recursive group call (either by number or by name) - is used outside the parentheses to which it refers, it operates a bit - like a subroutine in a programming language. More accurately, PCRE2 + If the syntax for a recursive group call (either by number or by name) + is used outside the parentheses to which it refers, it operates a bit + like a subroutine in a programming language. More accurately, PCRE2 treats the referenced group as an independent subpattern which it tries - to match at the current matching position. The called group may be de- - fined before or after the reference. A numbered reference can be ab- + to match at the current matching position. The called group may be de- + fined before or after the reference. A numbered reference can be ab- solute or relative, as in these examples: (...(absolute)...)...(?2)... @@ -9381,106 +9397,106 @@ GROUPS AS SUBROUTINES (sens|respons)e and \1ibility - matches "sense and sensibility" and "response and responsibility", but + matches "sense and sensibility" and "response and responsibility", but not "sense and responsibility". If instead the pattern (sens|respons)e and (?1)ibility - is used, it does match "sense and responsibility" as well as the other - two strings. Another example is given in the discussion of DEFINE + is used, it does match "sense and responsibility" as well as the other + two strings. Another example is given in the discussion of DEFINE above. - Like recursions, subroutine calls used to be treated as atomic, but - this changed at PCRE2 release 10.30, so backtracking into subroutine - calls can now occur. However, any capturing parentheses that are set + Like recursions, subroutine calls used to be treated as atomic, but + this changed at PCRE2 release 10.30, so backtracking into subroutine + calls can now occur. However, any capturing parentheses that are set during the subroutine call revert to their previous values afterwards. - Processing options such as case-independence are fixed when a group is - defined, so if it is used as a subroutine, such options cannot be + Processing options such as case-independence are fixed when a group is + defined, so if it is used as a subroutine, such options cannot be changed for different calls. For example, consider this pattern: (abc)(?i:(?-1)) - It matches "abcabc". It does not match "abcABC" because the change of + It matches "abcabc". It does not match "abcABC" because the change of processing option does not affect the called group. - The behaviour of backtracking control verbs in groups when called as + The behaviour of backtracking control verbs in groups when called as subroutines is described in the section entitled "Backtracking verbs in subroutines" below. ONIGURUMA SUBROUTINE SYNTAX - For compatibility with Oniguruma, the non-Perl syntax \g followed by a + For compatibility with Oniguruma, the non-Perl syntax \g followed by a name or a number enclosed either in angle brackets or single quotes, is an alternative syntax for calling a group as a subroutine, possibly re- - cursively. Here are two of the examples used above, rewritten using + cursively. Here are two of the examples used above, rewritten using this syntax: (? \( ( (?>[^()]+) | \g )* \) ) (sens|respons)e and \g'1'ibility - PCRE2 supports an extension to Oniguruma: if a number is preceded by a + PCRE2 supports an extension to Oniguruma: if a number is preceded by a plus or a minus sign it is taken as a relative reference. For example: (abc)(?i:\g<-1>) - Note that \g{...} (Perl syntax) and \g<...> (Oniguruma syntax) are not - synonymous. The former is a backreference; the latter is a subroutine + Note that \g{...} (Perl syntax) and \g<...> (Oniguruma syntax) are not + synonymous. The former is a backreference; the latter is a subroutine call. CALLOUTS Perl has a feature whereby using the sequence (?{...}) causes arbitrary - Perl code to be obeyed in the middle of matching a regular expression. + Perl code to be obeyed in the middle of matching a regular expression. This makes it possible, amongst other things, to extract different sub- strings that match the same pair of parentheses when there is a repeti- tion. - PCRE2 provides a similar feature, but of course it cannot obey arbi- - trary Perl code. The feature is called "callout". The caller of PCRE2 - provides an external function by putting its entry point in a match - context using the function pcre2_set_callout(), and then passing that - context to pcre2_match() or pcre2_dfa_match(). If no match context is + PCRE2 provides a similar feature, but of course it cannot obey arbi- + trary Perl code. The feature is called "callout". The caller of PCRE2 + provides an external function by putting its entry point in a match + context using the function pcre2_set_callout(), and then passing that + context to pcre2_match() or pcre2_dfa_match(). If no match context is passed, or if the callout entry point is set to NULL, callouts are dis- abled. - Within a regular expression, (?C) indicates a point at which the - external function is to be called. There are two kinds of callout: - those with a numerical argument and those with a string argument. (?C) - on its own with no argument is treated as (?C0). A numerical argument - allows the application to distinguish between different callouts. - String arguments were added for release 10.20 to make it possible for - script languages that use PCRE2 to embed short scripts within patterns + Within a regular expression, (?C) indicates a point at which the + external function is to be called. There are two kinds of callout: + those with a numerical argument and those with a string argument. (?C) + on its own with no argument is treated as (?C0). A numerical argument + allows the application to distinguish between different callouts. + String arguments were added for release 10.20 to make it possible for + script languages that use PCRE2 to embed short scripts within patterns in a similar way to Perl. During matching, when PCRE2 reaches a callout point, the external func- - tion is called. It is provided with the number or string argument of - the callout, the position in the pattern, and one item of data that is + tion is called. It is provided with the number or string argument of + the callout, the position in the pattern, and one item of data that is also set in the match block. The callout function may cause matching to proceed, to backtrack, or to fail. - By default, PCRE2 implements a number of optimizations at matching - time, and one side-effect is that sometimes callouts are skipped. If - you need all possible callouts to happen, you need to set options that - disable the relevant optimizations. More details, including a complete - description of the programming interface to the callout function, are + By default, PCRE2 implements a number of optimizations at matching + time, and one side-effect is that sometimes callouts are skipped. If + you need all possible callouts to happen, you need to set options that + disable the relevant optimizations. More details, including a complete + description of the programming interface to the callout function, are given in the pcre2callout documentation. Callouts with numerical arguments - If you just want to have a means of identifying different callout - points, put a number less than 256 after the letter C. For example, + If you just want to have a means of identifying different callout + points, put a number less than 256 after the letter C. For example, this pattern has two callout points: (?C1)abc(?C2)def - If the PCRE2_AUTO_CALLOUT flag is passed to pcre2_compile(), numerical - callouts are automatically installed before each item in the pattern. - They are all numbered 255. If there is a conditional group in the pat- + If the PCRE2_AUTO_CALLOUT flag is passed to pcre2_compile(), numerical + callouts are automatically installed before each item in the pattern. + They are all numbered 255. If there is a conditional group in the pat- tern whose condition is an assertion, an additional callout is inserted - just before the condition. An explicit callout may also be set at this + just before the condition. An explicit callout may also be set at this position, as in this example: (?(?C9)(?=a)abc|def) @@ -9490,78 +9506,78 @@ CALLOUTS Callouts with string arguments - A delimited string may be used instead of a number as a callout argu- - ment. The starting delimiter must be one of ` ' " ^ % # $ { and the + A delimited string may be used instead of a number as a callout argu- + ment. The starting delimiter must be one of ` ' " ^ % # $ { and the ending delimiter is the same as the start, except for {, where the end- - ing delimiter is }. If the ending delimiter is needed within the + ing delimiter is }. If the ending delimiter is needed within the string, it must be doubled. For example: (?C'ab ''c'' d')xyz(?C{any text})pqr - The doubling is removed before the string is passed to the callout + The doubling is removed before the string is passed to the callout function. BACKTRACKING CONTROL - There are a number of special "Backtracking Control Verbs" (to use - Perl's terminology) that modify the behaviour of backtracking during - matching. They are generally of the form (*VERB) or (*VERB:NAME). Some + There are a number of special "Backtracking Control Verbs" (to use + Perl's terminology) that modify the behaviour of backtracking during + matching. They are generally of the form (*VERB) or (*VERB:NAME). Some verbs take either form, and may behave differently depending on whether - or not a name argument is present. The names are not required to be + or not a name argument is present. The names are not required to be unique within the pattern. - By default, for compatibility with Perl, a name is any sequence of + By default, for compatibility with Perl, a name is any sequence of characters that does not include a closing parenthesis. The name is not - processed in any way, and it is not possible to include a closing - parenthesis in the name. This can be changed by setting the - PCRE2_ALT_VERBNAMES option, but the result is no longer Perl-compati- + processed in any way, and it is not possible to include a closing + parenthesis in the name. This can be changed by setting the + PCRE2_ALT_VERBNAMES option, but the result is no longer Perl-compati- ble. - When PCRE2_ALT_VERBNAMES is set, backslash processing is applied to - verb names and only an unescaped closing parenthesis terminates the - name. However, the only backslash items that are permitted are \Q, \E, - and sequences such as \x{100} that define character code points. Char- + When PCRE2_ALT_VERBNAMES is set, backslash processing is applied to + verb names and only an unescaped closing parenthesis terminates the + name. However, the only backslash items that are permitted are \Q, \E, + and sequences such as \x{100} that define character code points. Char- acter type escapes such as \d are faulted. A closing parenthesis can be included in a name either as \) or between - \Q and \E. In addition to backslash processing, if the PCRE2_EXTENDED + \Q and \E. In addition to backslash processing, if the PCRE2_EXTENDED or PCRE2_EXTENDED_MORE option is also set, unescaped whitespace in verb names is skipped, and #-comments are recognized, exactly as in the rest - of the pattern. PCRE2_EXTENDED and PCRE2_EXTENDED_MORE do not affect + of the pattern. PCRE2_EXTENDED and PCRE2_EXTENDED_MORE do not affect verb names unless PCRE2_ALT_VERBNAMES is also set. - The maximum length of a name is 255 in the 8-bit library and 65535 in - the 16-bit and 32-bit libraries. If the name is empty, that is, if the - closing parenthesis immediately follows the colon, the effect is as if + The maximum length of a name is 255 in the 8-bit library and 65535 in + the 16-bit and 32-bit libraries. If the name is empty, that is, if the + closing parenthesis immediately follows the colon, the effect is as if the colon were not there. Any number of these verbs may occur in a pat- tern. Except for (*ACCEPT), they may not be quantified. - Since these verbs are specifically related to backtracking, most of - them can be used only when the pattern is to be matched using the tra- + Since these verbs are specifically related to backtracking, most of + them can be used only when the pattern is to be matched using the tra- ditional matching function, because that uses a backtracking algorithm. - With the exception of (*FAIL), which behaves like a failing negative + With the exception of (*FAIL), which behaves like a failing negative assertion, the backtracking control verbs cause an error if encountered by the DFA matching function. - The behaviour of these verbs in repeated groups, assertions, and in - capture groups called as subroutines (whether or not recursively) is + The behaviour of these verbs in repeated groups, assertions, and in + capture groups called as subroutines (whether or not recursively) is documented below. Optimizations that affect backtracking verbs PCRE2 contains some optimizations that are used to speed up matching by running some checks at the start of each match attempt. For example, it - may know the minimum length of matching subject, or that a particular + may know the minimum length of matching subject, or that a particular character must be present. When one of these optimizations bypasses the - running of a match, any included backtracking verbs will not, of + running of a match, any included backtracking verbs will not, of course, be processed. You can suppress the start-of-match optimizations - by setting the PCRE2_NO_START_OPTIMIZE option when calling pcre2_com- - pile(), or by starting the pattern with (*NO_START_OPT). There is more + by setting the PCRE2_NO_START_OPTIMIZE option when calling pcre2_com- + pile(), or by starting the pattern with (*NO_START_OPT). There is more discussion of this option in the section entitled "Compiling a pattern" in the pcre2api documentation. - Experiments with Perl suggest that it too has similar optimizations, + Experiments with Perl suggest that it too has similar optimizations, and like PCRE2, turning them off can change the result of a match. Verbs that act immediately @@ -9570,77 +9586,77 @@ BACKTRACKING CONTROL (*ACCEPT) or (*ACCEPT:NAME) - This verb causes the match to end successfully, skipping the remainder - of the pattern. However, when it is inside a capture group that is + This verb causes the match to end successfully, skipping the remainder + of the pattern. However, when it is inside a capture group that is called as a subroutine, only that group is ended successfully. Matching then continues at the outer level. If (*ACCEPT) in triggered in a posi- - tive assertion, the assertion succeeds; in a negative assertion, the + tive assertion, the assertion succeeds; in a negative assertion, the assertion fails. - If (*ACCEPT) is inside capturing parentheses, the data so far is cap- + If (*ACCEPT) is inside capturing parentheses, the data so far is cap- tured. For example: A((?:A|B(*ACCEPT)|C)D) - This matches "AB", "AAD", or "ACD"; when it matches "AB", "B" is cap- + This matches "AB", "AAD", or "ACD"; when it matches "AB", "B" is cap- tured by the outer parentheses. - (*ACCEPT) is the only backtracking verb that is allowed to be quanti- - fied because an ungreedy quantification with a minimum of zero acts + (*ACCEPT) is the only backtracking verb that is allowed to be quanti- + fied because an ungreedy quantification with a minimum of zero acts only when a backtrack happens. Consider, for example, (A(*ACCEPT)??B)C - where A, B, and C may be complex expressions. After matching "A", the - matcher processes "BC"; if that fails, causing a backtrack, (*ACCEPT) - is triggered and the match succeeds. In both cases, all but C is cap- - tured. Whereas (*COMMIT) (see below) means "fail on backtrack", a re- + where A, B, and C may be complex expressions. After matching "A", the + matcher processes "BC"; if that fails, causing a backtrack, (*ACCEPT) + is triggered and the match succeeds. In both cases, all but C is cap- + tured. Whereas (*COMMIT) (see below) means "fail on backtrack", a re- peated (*ACCEPT) of this type means "succeed on backtrack". - Warning: (*ACCEPT) should not be used within a script run group, be- - cause it causes an immediate exit from the group, bypassing the script + Warning: (*ACCEPT) should not be used within a script run group, be- + cause it causes an immediate exit from the group, bypassing the script run checking. (*FAIL) or (*FAIL:NAME) - This verb causes a matching failure, forcing backtracking to occur. It - may be abbreviated to (*F). It is equivalent to (?!) but easier to + This verb causes a matching failure, forcing backtracking to occur. It + may be abbreviated to (*F). It is equivalent to (?!) but easier to read. The Perl documentation notes that it is probably useful only when combined with (?{}) or (??{}). Those are, of course, Perl features that - are not present in PCRE2. The nearest equivalent is the callout fea- + are not present in PCRE2. The nearest equivalent is the callout fea- ture, as for example in this pattern: a+(?C)(*FAIL) - A match with the string "aaaa" always fails, but the callout is taken + A match with the string "aaaa" always fails, but the callout is taken before each backtrack happens (in this example, 10 times). - (*ACCEPT:NAME) and (*FAIL:NAME) behave the same as (*MARK:NAME)(*AC- - CEPT) and (*MARK:NAME)(*FAIL), respectively, that is, a (*MARK) is + (*ACCEPT:NAME) and (*FAIL:NAME) behave the same as (*MARK:NAME)(*AC- + CEPT) and (*MARK:NAME)(*FAIL), respectively, that is, a (*MARK) is recorded just before the verb acts. Recording which path was taken - There is one verb whose main purpose is to track how a match was ar- - rived at, though it also has a secondary use in conjunction with ad- + There is one verb whose main purpose is to track how a match was ar- + rived at, though it also has a secondary use in conjunction with ad- vancing the match starting point (see (*SKIP) below). (*MARK:NAME) or (*:NAME) - A name is always required with this verb. For all the other backtrack- + A name is always required with this verb. For all the other backtrack- ing control verbs, a NAME argument is optional. - When a match succeeds, the name of the last-encountered mark name on + When a match succeeds, the name of the last-encountered mark name on the matching path is passed back to the caller as described in the sec- tion entitled "Other information about the match" in the pcre2api docu- - mentation. This applies to all instances of (*MARK) and other verbs, + mentation. This applies to all instances of (*MARK) and other verbs, including those inside assertions and atomic groups. However, there are - differences in those cases when (*MARK) is used in conjunction with + differences in those cases when (*MARK) is used in conjunction with (*SKIP) as described below. - The mark name that was last encountered on the matching path is passed - back. A verb without a NAME argument is ignored for this purpose. Here - is an example of pcre2test output, where the "mark" modifier requests + The mark name that was last encountered on the matching path is passed + back. A verb without a NAME argument is ignored for this purpose. Here + is an example of pcre2test output, where the "mark" modifier requests the retrieval and outputting of (*MARK) data: re> /X(*MARK:A)Y|X(*MARK:B)Z/mark @@ -9652,76 +9668,76 @@ BACKTRACKING CONTROL MK: B The (*MARK) name is tagged with "MK:" in this output, and in this exam- - ple it indicates which of the two alternatives matched. This is a more - efficient way of obtaining this information than putting each alterna- + ple it indicates which of the two alternatives matched. This is a more + efficient way of obtaining this information than putting each alterna- tive in its own capturing parentheses. - If a verb with a name is encountered in a positive assertion that is - true, the name is recorded and passed back if it is the last-encoun- + If a verb with a name is encountered in a positive assertion that is + true, the name is recorded and passed back if it is the last-encoun- tered. This does not happen for negative assertions or failing positive assertions. - After a partial match or a failed match, the last encountered name in + After a partial match or a failed match, the last encountered name in the entire match process is returned. For example: re> /X(*MARK:A)Y|X(*MARK:B)Z/mark data> XP No match, mark = B - Note that in this unanchored example the mark is retained from the + Note that in this unanchored example the mark is retained from the match attempt that started at the letter "X" in the subject. Subsequent match attempts starting at "P" and then with an empty string do not get as far as the (*MARK) item, but nevertheless do not reset it. - If you are interested in (*MARK) values after failed matches, you - should probably set the PCRE2_NO_START_OPTIMIZE option (see above) to + If you are interested in (*MARK) values after failed matches, you + should probably set the PCRE2_NO_START_OPTIMIZE option (see above) to ensure that the match is always attempted. Verbs that act after backtracking The following verbs do nothing when they are encountered. Matching con- - tinues with what follows, but if there is a subsequent match failure, - causing a backtrack to the verb, a failure is forced. That is, back- - tracking cannot pass to the left of the verb. However, when one of + tinues with what follows, but if there is a subsequent match failure, + causing a backtrack to the verb, a failure is forced. That is, back- + tracking cannot pass to the left of the verb. However, when one of these verbs appears inside an atomic group or in a lookaround assertion - that is true, its effect is confined to that group, because once the - group has been matched, there is never any backtracking into it. Back- + that is true, its effect is confined to that group, because once the + group has been matched, there is never any backtracking into it. Back- tracking from beyond an assertion or an atomic group ignores the entire group, and seeks a preceding backtracking point. - These verbs differ in exactly what kind of failure occurs when back- - tracking reaches them. The behaviour described below is what happens - when the verb is not in a subroutine or an assertion. Subsequent sec- + These verbs differ in exactly what kind of failure occurs when back- + tracking reaches them. The behaviour described below is what happens + when the verb is not in a subroutine or an assertion. Subsequent sec- tions cover these special cases. (*COMMIT) or (*COMMIT:NAME) - This verb causes the whole match to fail outright if there is a later + This verb causes the whole match to fail outright if there is a later matching failure that causes backtracking to reach it. Even if the pat- - tern is unanchored, no further attempts to find a match by advancing - the starting point take place. If (*COMMIT) is the only backtracking + tern is unanchored, no further attempts to find a match by advancing + the starting point take place. If (*COMMIT) is the only backtracking verb that is encountered, once it has been passed pcre2_match() is com- mitted to finding a match at the current starting point, or not at all. For example: a+(*COMMIT)b - This matches "xxaab" but not "aacaab". It can be thought of as a kind + This matches "xxaab" but not "aacaab". It can be thought of as a kind of dynamic anchor, or "I've started, so I must finish." - The behaviour of (*COMMIT:NAME) is not the same as (*MARK:NAME)(*COM- - MIT). It is like (*MARK:NAME) in that the name is remembered for pass- - ing back to the caller. However, (*SKIP:NAME) searches only for names + The behaviour of (*COMMIT:NAME) is not the same as (*MARK:NAME)(*COM- + MIT). It is like (*MARK:NAME) in that the name is remembered for pass- + ing back to the caller. However, (*SKIP:NAME) searches only for names that are set with (*MARK), ignoring those set by any of the other back- tracking verbs. - If there is more than one backtracking verb in a pattern, a different - one that follows (*COMMIT) may be triggered first, so merely passing + If there is more than one backtracking verb in a pattern, a different + one that follows (*COMMIT) may be triggered first, so merely passing (*COMMIT) during a match does not always guarantee that a match must be at this starting point. Note that (*COMMIT) at the start of a pattern is not the same as an an- - chor, unless PCRE2's start-of-match optimizations are turned off, as + chor, unless PCRE2's start-of-match optimizations are turned off, as shown in this output from pcre2test: re> /(*COMMIT)abc/ @@ -9732,68 +9748,68 @@ BACKTRACKING CONTROL data> xyzabc No match - For the first pattern, PCRE2 knows that any match must start with "a", - so the optimization skips along the subject to "a" before applying the - pattern to the first set of data. The match attempt then succeeds. The - second pattern disables the optimization that skips along to the first - character. The pattern is now applied starting at "x", and so the - (*COMMIT) causes the match to fail without trying any other starting + For the first pattern, PCRE2 knows that any match must start with "a", + so the optimization skips along the subject to "a" before applying the + pattern to the first set of data. The match attempt then succeeds. The + second pattern disables the optimization that skips along to the first + character. The pattern is now applied starting at "x", and so the + (*COMMIT) causes the match to fail without trying any other starting points. (*PRUNE) or (*PRUNE:NAME) - This verb causes the match to fail at the current starting position in + This verb causes the match to fail at the current starting position in the subject if there is a later matching failure that causes backtrack- - ing to reach it. If the pattern is unanchored, the normal "bumpalong" - advance to the next starting character then happens. Backtracking can - occur as usual to the left of (*PRUNE), before it is reached, or when - matching to the right of (*PRUNE), but if there is no match to the - right, backtracking cannot cross (*PRUNE). In simple cases, the use of - (*PRUNE) is just an alternative to an atomic group or possessive quan- + ing to reach it. If the pattern is unanchored, the normal "bumpalong" + advance to the next starting character then happens. Backtracking can + occur as usual to the left of (*PRUNE), before it is reached, or when + matching to the right of (*PRUNE), but if there is no match to the + right, backtracking cannot cross (*PRUNE). In simple cases, the use of + (*PRUNE) is just an alternative to an atomic group or possessive quan- tifier, but there are some uses of (*PRUNE) that cannot be expressed in - any other way. In an anchored pattern (*PRUNE) has the same effect as + any other way. In an anchored pattern (*PRUNE) has the same effect as (*COMMIT). The behaviour of (*PRUNE:NAME) is not the same as (*MARK:NAME)(*PRUNE). It is like (*MARK:NAME) in that the name is remembered for passing back - to the caller. However, (*SKIP:NAME) searches only for names set with + to the caller. However, (*SKIP:NAME) searches only for names set with (*MARK), ignoring those set by other backtracking verbs. (*SKIP) - This verb, when given without a name, is like (*PRUNE), except that if - the pattern is unanchored, the "bumpalong" advance is not to the next + This verb, when given without a name, is like (*PRUNE), except that if + the pattern is unanchored, the "bumpalong" advance is not to the next character, but to the position in the subject where (*SKIP) was encoun- - tered. (*SKIP) signifies that whatever text was matched leading up to - it cannot be part of a successful match if there is a later mismatch. + tered. (*SKIP) signifies that whatever text was matched leading up to + it cannot be part of a successful match if there is a later mismatch. Consider: a+(*SKIP)b - If the subject is "aaaac...", after the first match attempt fails - (starting at the first character in the string), the starting point + If the subject is "aaaac...", after the first match attempt fails + (starting at the first character in the string), the starting point skips on to start the next attempt at "c". Note that a possessive quan- tifier does not have the same effect as this example; although it would - suppress backtracking during the first match attempt, the second at- - tempt would start at the second character instead of skipping on to + suppress backtracking during the first match attempt, the second at- + tempt would start at the second character instead of skipping on to "c". - If (*SKIP) is used to specify a new starting position that is the same - as the starting position of the current match, or (by being inside a - lookbehind) earlier, the position specified by (*SKIP) is ignored, and + If (*SKIP) is used to specify a new starting position that is the same + as the starting position of the current match, or (by being inside a + lookbehind) earlier, the position specified by (*SKIP) is ignored, and instead the normal "bumpalong" occurs. (*SKIP:NAME) - When (*SKIP) has an associated name, its behaviour is modified. When - such a (*SKIP) is triggered, the previous path through the pattern is - searched for the most recent (*MARK) that has the same name. If one is - found, the "bumpalong" advance is to the subject position that corre- - sponds to that (*MARK) instead of to where (*SKIP) was encountered. If + When (*SKIP) has an associated name, its behaviour is modified. When + such a (*SKIP) is triggered, the previous path through the pattern is + searched for the most recent (*MARK) that has the same name. If one is + found, the "bumpalong" advance is to the subject position that corre- + sponds to that (*MARK) instead of to where (*SKIP) was encountered. If no (*MARK) with a matching name is found, the (*SKIP) is ignored. - The search for a (*MARK) name uses the normal backtracking mechanism, - which means that it does not see (*MARK) settings that are inside + The search for a (*MARK) name uses the normal backtracking mechanism, + which means that it does not see (*MARK) settings that are inside atomic groups or assertions, because they are never re-entered by back- tracking. Compare the following pcre2test examples: @@ -9807,105 +9823,105 @@ BACKTRACKING CONTROL 0: b 1: b - In the first example, the (*MARK) setting is in an atomic group, so it + In the first example, the (*MARK) setting is in an atomic group, so it is not seen when (*SKIP:X) triggers, causing the (*SKIP) to be ignored. - This allows the second branch of the pattern to be tried at the first - character position. In the second example, the (*MARK) setting is not - in an atomic group. This allows (*SKIP:X) to find the (*MARK) when it + This allows the second branch of the pattern to be tried at the first + character position. In the second example, the (*MARK) setting is not + in an atomic group. This allows (*SKIP:X) to find the (*MARK) when it backtracks, and this causes a new matching attempt to start at the sec- - ond character. This time, the (*MARK) is never seen because "a" does + ond character. This time, the (*MARK) is never seen because "a" does not match "b", so the matcher immediately jumps to the second branch of the pattern. - Note that (*SKIP:NAME) searches only for names set by (*MARK:NAME). It + Note that (*SKIP:NAME) searches only for names set by (*MARK:NAME). It ignores names that are set by other backtracking verbs. (*THEN) or (*THEN:NAME) - This verb causes a skip to the next innermost alternative when back- - tracking reaches it. That is, it cancels any further backtracking - within the current alternative. Its name comes from the observation + This verb causes a skip to the next innermost alternative when back- + tracking reaches it. That is, it cancels any further backtracking + within the current alternative. Its name comes from the observation that it can be used for a pattern-based if-then-else block: ( COND1 (*THEN) FOO | COND2 (*THEN) BAR | COND3 (*THEN) BAZ ) ... - If the COND1 pattern matches, FOO is tried (and possibly further items - after the end of the group if FOO succeeds); on failure, the matcher - skips to the second alternative and tries COND2, without backtracking - into COND1. If that succeeds and BAR fails, COND3 is tried. If subse- - quently BAZ fails, there are no more alternatives, so there is a back- - track to whatever came before the entire group. If (*THEN) is not in- + If the COND1 pattern matches, FOO is tried (and possibly further items + after the end of the group if FOO succeeds); on failure, the matcher + skips to the second alternative and tries COND2, without backtracking + into COND1. If that succeeds and BAR fails, COND3 is tried. If subse- + quently BAZ fails, there are no more alternatives, so there is a back- + track to whatever came before the entire group. If (*THEN) is not in- side an alternation, it acts like (*PRUNE). - The behaviour of (*THEN:NAME) is not the same as (*MARK:NAME)(*THEN). + The behaviour of (*THEN:NAME) is not the same as (*MARK:NAME)(*THEN). It is like (*MARK:NAME) in that the name is remembered for passing back - to the caller. However, (*SKIP:NAME) searches only for names set with + to the caller. However, (*SKIP:NAME) searches only for names set with (*MARK), ignoring those set by other backtracking verbs. - A group that does not contain a | character is just a part of the en- - closing alternative; it is not a nested alternation with only one al- + A group that does not contain a | character is just a part of the en- + closing alternative; it is not a nested alternation with only one al- ternative. The effect of (*THEN) extends beyond such a group to the en- - closing alternative. Consider this pattern, where A, B, etc. are com- - plex pattern fragments that do not contain any | characters at this + closing alternative. Consider this pattern, where A, B, etc. are com- + plex pattern fragments that do not contain any | characters at this level: A (B(*THEN)C) | D - If A and B are matched, but there is a failure in C, matching does not + If A and B are matched, but there is a failure in C, matching does not backtrack into A; instead it moves to the next alternative, that is, D. - However, if the group containing (*THEN) is given an alternative, it + However, if the group containing (*THEN) is given an alternative, it behaves differently: A (B(*THEN)C | (*FAIL)) | D The effect of (*THEN) is now confined to the inner group. After a fail- - ure in C, matching moves to (*FAIL), which causes the whole group to - fail because there are no more alternatives to try. In this case, + ure in C, matching moves to (*FAIL), which causes the whole group to + fail because there are no more alternatives to try. In this case, matching does backtrack into A. - Note that a conditional group is not considered as having two alterna- - tives, because only one is ever used. In other words, the | character - in a conditional group has a different meaning. Ignoring white space, + Note that a conditional group is not considered as having two alterna- + tives, because only one is ever used. In other words, the | character + in a conditional group has a different meaning. Ignoring white space, consider: ^.*? (?(?=a) a | b(*THEN)c ) If the subject is "ba", this pattern does not match. Because .*? is un- - greedy, it initially matches zero characters. The condition (?=a) then - fails, the character "b" is matched, but "c" is not. At this point, - matching does not backtrack to .*? as might perhaps be expected from - the presence of the | character. The conditional group is part of the - single alternative that comprises the whole pattern, and so the match - fails. (If there was a backtrack into .*?, allowing it to match "b", + greedy, it initially matches zero characters. The condition (?=a) then + fails, the character "b" is matched, but "c" is not. At this point, + matching does not backtrack to .*? as might perhaps be expected from + the presence of the | character. The conditional group is part of the + single alternative that comprises the whole pattern, and so the match + fails. (If there was a backtrack into .*?, allowing it to match "b", the match would succeed.) - The verbs just described provide four different "strengths" of control + The verbs just described provide four different "strengths" of control when subsequent matching fails. (*THEN) is the weakest, carrying on the - match at the next alternative. (*PRUNE) comes next, failing the match - at the current starting position, but allowing an advance to the next - character (for an unanchored pattern). (*SKIP) is similar, except that + match at the next alternative. (*PRUNE) comes next, failing the match + at the current starting position, but allowing an advance to the next + character (for an unanchored pattern). (*SKIP) is similar, except that the advance may be more than one character. (*COMMIT) is the strongest, causing the entire match to fail. More than one backtracking verb - If more than one backtracking verb is present in a pattern, the one - that is backtracked onto first acts. For example, consider this pat- + If more than one backtracking verb is present in a pattern, the one + that is backtracked onto first acts. For example, consider this pat- tern, where A, B, etc. are complex pattern fragments: (A(*COMMIT)B(*THEN)C|ABD) - If A matches but B fails, the backtrack to (*COMMIT) causes the entire + If A matches but B fails, the backtrack to (*COMMIT) causes the entire match to fail. However, if A and B match, but C fails, the backtrack to - (*THEN) causes the next alternative (ABD) to be tried. This behaviour - is consistent, but is not always the same as Perl's. It means that if - two or more backtracking verbs appear in succession, all but the last + (*THEN) causes the next alternative (ABD) to be tried. This behaviour + is consistent, but is not always the same as Perl's. It means that if + two or more backtracking verbs appear in succession, all but the last of them has no effect. Consider this example: ...(*COMMIT)(*PRUNE)... If there is a matching failure to the right, backtracking onto (*PRUNE) - causes it to be triggered, and its action is taken. There can never be + causes it to be triggered, and its action is taken. There can never be a backtrack onto (*COMMIT). Backtracking verbs in repeated groups @@ -9915,50 +9931,50 @@ BACKTRACKING CONTROL /(a(*COMMIT)b)+ac/ - If the subject is "abac", Perl matches unless its optimizations are - disabled, but PCRE2 always fails because the (*COMMIT) in the second + If the subject is "abac", Perl matches unless its optimizations are + disabled, but PCRE2 always fails because the (*COMMIT) in the second repeat of the group acts. Backtracking verbs in assertions - (*FAIL) in any assertion has its normal effect: it forces an immediate - backtrack. The behaviour of the other backtracking verbs depends on - whether or not the assertion is standalone or acting as the condition + (*FAIL) in any assertion has its normal effect: it forces an immediate + backtrack. The behaviour of the other backtracking verbs depends on + whether or not the assertion is standalone or acting as the condition in a conditional group. - (*ACCEPT) in a standalone positive assertion causes the assertion to - succeed without any further processing; captured strings and a mark - name (if set) are retained. In a standalone negative assertion, (*AC- + (*ACCEPT) in a standalone positive assertion causes the assertion to + succeed without any further processing; captured strings and a mark + name (if set) are retained. In a standalone negative assertion, (*AC- CEPT) causes the assertion to fail without any further processing; cap- tured substrings and any mark name are discarded. - If the assertion is a condition, (*ACCEPT) causes the condition to be - true for a positive assertion and false for a negative one; captured + If the assertion is a condition, (*ACCEPT) causes the condition to be + true for a positive assertion and false for a negative one; captured substrings are retained in both cases. The remaining verbs act only when a later failure causes a backtrack to - reach them. This means that, for the Perl-compatible assertions, their + reach them. This means that, for the Perl-compatible assertions, their effect is confined to the assertion, because Perl lookaround assertions are atomic. A backtrack that occurs after such an assertion is complete - does not jump back into the assertion. Note in particular that a - (*MARK) name that is set in an assertion is not "seen" by an instance + does not jump back into the assertion. Note in particular that a + (*MARK) name that is set in an assertion is not "seen" by an instance of (*SKIP:NAME) later in the pattern. - PCRE2 now supports non-atomic positive assertions, as described in the - section entitled "Non-atomic assertions" above. These assertions must - be standalone (not used as conditions). They are not Perl-compatible. - For these assertions, a later backtrack does jump back into the asser- - tion, and therefore verbs such as (*COMMIT) can be triggered by back- + PCRE2 now supports non-atomic positive assertions, as described in the + section entitled "Non-atomic assertions" above. These assertions must + be standalone (not used as conditions). They are not Perl-compatible. + For these assertions, a later backtrack does jump back into the asser- + tion, and therefore verbs such as (*COMMIT) can be triggered by back- tracks from later in the pattern. - The effect of (*THEN) is not allowed to escape beyond an assertion. If - there are no more branches to try, (*THEN) causes a positive assertion + The effect of (*THEN) is not allowed to escape beyond an assertion. If + there are no more branches to try, (*THEN) causes a positive assertion to be false, and a negative assertion to be true. - The other backtracking verbs are not treated specially if they appear - in a standalone positive assertion. In a conditional positive asser- + The other backtracking verbs are not treated specially if they appear + in a standalone positive assertion. In a conditional positive asser- tion, backtracking (from within the assertion) into (*COMMIT), (*SKIP), - or (*PRUNE) causes the condition to be false. However, for both stand- + or (*PRUNE) causes the condition to be false. However, for both stand- alone and conditional negative assertions, backtracking into (*COMMIT), (*SKIP), or (*PRUNE) causes the assertion to be true, without consider- ing any further alternative branches. @@ -9968,26 +9984,26 @@ BACKTRACKING CONTROL These behaviours occur whether or not the group is called recursively. (*ACCEPT) in a group called as a subroutine causes the subroutine match - to succeed without any further processing. Matching then continues af- - ter the subroutine call. Perl documents this behaviour. Perl's treat- + to succeed without any further processing. Matching then continues af- + ter the subroutine call. Perl documents this behaviour. Perl's treat- ment of the other verbs in subroutines is different in some cases. - (*FAIL) in a group called as a subroutine has its normal effect: it + (*FAIL) in a group called as a subroutine has its normal effect: it forces an immediate backtrack. - (*COMMIT), (*SKIP), and (*PRUNE) cause the subroutine match to fail - when triggered by being backtracked to in a group called as a subrou- + (*COMMIT), (*SKIP), and (*PRUNE) cause the subroutine match to fail + when triggered by being backtracked to in a group called as a subrou- tine. There is then a backtrack at the outer level. (*THEN), when triggered, skips to the next alternative in the innermost - enclosing group that has alternatives (its normal behaviour). However, + enclosing group that has alternatives (its normal behaviour). However, if there is no such group within the subroutine's group, the subroutine match fails and there is a backtrack at the outer level. SEE ALSO - pcre2api(3), pcre2callout(3), pcre2matching(3), pcre2syntax(3), + pcre2api(3), pcre2callout(3), pcre2matching(3), pcre2syntax(3), pcre2(3). @@ -10000,11 +10016,11 @@ AUTHOR REVISION - Last updated: 19 January 2024 + Last updated: 04 June 2024 Copyright (c) 1997-2024 University of Cambridge. -PCRE2 10.43 19 January 2024 PCRE2PATTERN(3) +PCRE2 10.44 04 June 2024 PCRE2PATTERN(3) ------------------------------------------------------------------------------ diff --git a/doc/pcre2_set_max_pattern_compiled_length.3 b/doc/pcre2_set_max_pattern_compiled_length.3 new file mode 100644 index 0000000..472a7bb --- /dev/null +++ b/doc/pcre2_set_max_pattern_compiled_length.3 @@ -0,0 +1,32 @@ +.TH PCRE2_SET_MAX_PATTERN_COMPILED_LENGTH 3 "24 April 2024" "PCRE2 10.44" +.SH NAME +PCRE2 - Perl-compatible regular expressions (revised API) +.SH SYNOPSIS +.rs +.sp +.B #include +.PP +.nf +.B int pcre2_set_max_pattern_compiled_length( +.B " pcre2_compile_context *\fIccontext\fP, PCRE2_SIZE \fIvalue\fP);" +.fi +. +.SH DESCRIPTION +.rs +.sp +This function sets, in a compile context, the maximum size (in bytes) for the +memory needed to hold the compiled version of a pattern that is compiled with +this context. The result is always zero. If a pattern that is passed to +\fBpcre2_compile()\fP with this context needs more memory, an error is +generated. The default is the largest number that a PCRE2_SIZE variable can +hold, which is effectively unlimited. +.P +There is a complete description of the PCRE2 native API in the +.\" HREF +\fBpcre2api\fP +.\" +page and a description of the POSIX API in the +.\" HREF +\fBpcre2posix\fP +.\" +page. diff --git a/doc/pcre2api.3 b/doc/pcre2api.3 index 4799005..6028d62 100644 --- a/doc/pcre2api.3 +++ b/doc/pcre2api.3 @@ -1,4 +1,4 @@ -.TH PCRE2API 3 "27 January 2024" "PCRE2 10.43" +.TH PCRE2API 3 "24 April 2024" "PCRE2 10.44" .SH NAME PCRE2 - Perl-compatible regular expressions (revised API) .sp @@ -101,6 +101,9 @@ document for an overview of all the PCRE2 documentation. .B int pcre2_set_max_pattern_length(pcre2_compile_context *\fIccontext\fP, .B " PCRE2_SIZE \fIvalue\fP);" .sp +.B int pcre2_set_max_pattern_compiled_length( +.B " pcre2_compile_context *\fIccontext\fP, PCRE2_SIZE \fIvalue\fP);" +.sp .B int pcre2_set_max_varlookbehind(pcre2_compile_contest *\fIccontext\fP, .B " uint32_t \fIvalue\fP); .sp @@ -805,6 +808,18 @@ external sources can limit their size. The default is the largest number that a PCRE2_SIZE variable can hold, which is effectively unlimited. .sp .nf +.B int pcre2_set_max_pattern_compiled_length( +.B " pcre2_compile_context *\fIccontext\fP, PCRE2_SIZE \fIvalue\fP);" +.fi +.sp +This sets a maximum size, in bytes, for the memory needed to hold the compiled +version of a pattern that is compiled with this context. If the pattern needs +more memory, an error is generated. This facility is provided so that +applications that accept patterns from external sources can limit the amount of +memory they use. The default is the largest number that a PCRE2_SIZE variable +can hold, which is effectively unlimited. +.sp +.nf .B int pcre2_set_max_varlookbehind(pcre2_compile_contest *\fIccontext\fP, .B " uint32_t \fIvalue\fP); .fi @@ -4167,6 +4182,6 @@ Cambridge, England. .rs .sp .nf -Last updated: 27 January 2024 +Last updated: 24 April 2024 Copyright (c) 1997-2024 University of Cambridge. .fi diff --git a/doc/pcre2build.3 b/doc/pcre2build.3 index 7231612..1df4ebd 100644 --- a/doc/pcre2build.3 +++ b/doc/pcre2build.3 @@ -1,4 +1,4 @@ -.TH PCRE2BUILD 3 "24 November" "PCRE2 10.43" +.TH PCRE2BUILD 3 "15 April 2024" "PCRE2 10.44" .SH NAME PCRE2 - Perl-compatible regular expressions (revised API) . @@ -16,7 +16,8 @@ Autotools. Also in the distribution are files to support building using .\" contains general information about building with Autotools (some of which is repeated below), and also has some comments about building on various operating -systems. There is a lot more information about building PCRE2 without using +systems. The files in the \fBvms\fP directory support building under OpenVMS. +There is a lot more information about building PCRE2 without using Autotools (including information about using \fBCMake\fP and building "by hand") in the text file called .\" HTML @@ -659,6 +660,6 @@ Cambridge, England. .rs .sp .nf -Last updated: 24 November 2023 -Copyright (c) 1997-2023 University of Cambridge. +Last updated: 15 April 2024 +Copyright (c) 1997-2024 University of Cambridge. .fi diff --git a/doc/pcre2demo.3 b/doc/pcre2demo.3 index 73f26e7..0453a94 100644 --- a/doc/pcre2demo.3 +++ b/doc/pcre2demo.3 @@ -1,4 +1,4 @@ -.TH PCRE2DEMO 3 "16 February 2024" "PCRE2 10.43-RC1" +.TH PCRE2DEMO 3 " 7 June 2024" "PCRE2 10.44" .\"AUTOMATICALLY GENERATED BY PrepareRelease - do not EDIT! .SH NAME PCRE2DEMO - A demonstration C program for PCRE2 diff --git a/doc/pcre2jit.3 b/doc/pcre2jit.3 index 9b40ef5..8798089 100644 --- a/doc/pcre2jit.3 +++ b/doc/pcre2jit.3 @@ -1,4 +1,4 @@ -.TH PCRE2JIT 3 "23 January 2023" "PCRE2 10.43" +.TH PCRE2JIT 3 "21 February 2024" "PCRE2 10.43" .SH NAME PCRE2 - Perl-compatible regular expressions (revised API) .SH "PCRE2 JUST-IN-TIME COMPILER SUPPORT" @@ -27,7 +27,7 @@ JIT support is an optional feature of PCRE2. The "configure" option you want to use JIT. The support is limited to the following hardware platforms: .sp - ARM 32-bit (v5, v7, and Thumb2) + ARM 32-bit (v7, and Thumb2) ARM 64-bit IBM s390x 64 bit Intel x86 32-bit and 64-bit @@ -476,6 +476,6 @@ Cambridge, England. .rs .sp .nf -Last updated: 23 January 2023 -Copyright (c) 1997-2023 University of Cambridge. +Last updated: 21 February 2024 +Copyright (c) 1997-2024 University of Cambridge. .fi diff --git a/doc/pcre2pattern.3 b/doc/pcre2pattern.3 index af107b4..c3ccb0b 100644 --- a/doc/pcre2pattern.3 +++ b/doc/pcre2pattern.3 @@ -1,4 +1,4 @@ -.TH PCRE2PATTERN 3 "19 January 2024" "PCRE2 10.43" +.TH PCRE2PATTERN 3 "04 June 2024" "PCRE2 10.44" .SH NAME PCRE2 - Perl-compatible regular expressions (revised API) .SH "PCRE2 REGULAR EXPRESSION DETAILS" @@ -1027,15 +1027,17 @@ are of five types: L, V, T, LV, and LVT. An L character may be followed by an L, V, LV, or LVT character; an LV or V character may be followed by a V or T character; an LVT or T character may be followed only by a T character. .P -4. Do not end before extending characters or spacing marks or the "zero-width -joiner" character. Characters with the "mark" property always have the +4. Do not end before extending characters or spacing marks or the zero-width +joiner (ZWJ) character. Characters with the "mark" property always have the "extend" grapheme breaking property. .P 5. Do not end after prepend characters. .P -6. Do not break within emoji modifier sequences or emoji zwj sequences. That -is, do not break between characters with the Extended_Pictographic property. -Extend and ZWJ characters are allowed between the characters. +6. Do not end within emoji modifier sequences or emoji ZWJ (zero-width +joiner) sequences. An emoji ZWJ sequence consists of a character with the +Extended_Pictographic property, optionally followed by one or more characters +with the Extend property, followed by the ZWJ character, followed by another +Extended_Pictographic character. .P 7. Do not break within emoji flag sequences. That is, do not break between regional indicator (RI) characters if there are an odd number of RI characters @@ -1844,7 +1846,7 @@ the naming of capture groups. This feature was not added to Perl until release using the Python syntax. PCRE2 supports both the Perl and the Python syntax. .P In PCRE2, a capture group can be named in one of three ways: (?...) or -(?'name'...) as in Perl, or (?P...) as in Python. Names may be up to 32 +(?'name'...) as in Perl, or (?P...) as in Python. Names may be up to 128 code units long. When PCRE2_UTF is not set, they may contain only ASCII alphanumeric characters and underscores, but must start with a non-digit. When PCRE2_UTF is set, the syntax of group names is extended to allow any Unicode @@ -3889,6 +3891,6 @@ Cambridge, England. .rs .sp .nf -Last updated: 19 January 2024 +Last updated: 04 June 2024 Copyright (c) 1997-2024 University of Cambridge. .fi diff --git a/doc/pcre2test.1 b/doc/pcre2test.1 index 5e6f36a..c7df418 100644 --- a/doc/pcre2test.1 +++ b/doc/pcre2test.1 @@ -1,4 +1,4 @@ -.TH PCRE2TEST 1 "27 January 2024" "PCRE 10.43" +.TH PCRE2TEST 1 "24 April 2024" "PCRE 10.44" .SH NAME pcre2test - a program for testing Perl-compatible regular expressions. .SH SYNOPSIS @@ -652,7 +652,9 @@ heavily used in the test files. jitfast use JIT fast path jitverify verify JIT use locale= use this locale - max_pattern_length= set maximum pattern length + max_pattern_compiled ) set maximum compiled pattern + _length= ) length (bytes) + max_pattern_length= set maximum pattern length (code units) max_varlookbehind= set maximum variable lookbehind length memory show memory used newline= set newline type @@ -976,6 +978,15 @@ causes a compilation error. The default is the largest number a PCRE2_SIZE variable can hold (essentially unlimited). . . +.SS "Limiting the size of a compiled pattern" +.rs +.sp +The \fBmax_pattern_compiled_length\fP modifier sets a limit, in bytes, to the +amount of memory used by a compiled pattern. Breaching the limit causes a +compilation error. The default is the largest number a PCRE2_SIZE variable can +hold (essentially unlimited). +. +. .\" HTML .SS "Using the POSIX wrapper API" .rs @@ -2170,6 +2181,6 @@ Cambridge, England. .rs .sp .nf -Last updated: 27 January 2024 +Last updated: 24 April 2024 Copyright (c) 1997-2024 University of Cambridge. .fi diff --git a/doc/pcre2test.txt b/doc/pcre2test.txt index d5750b4..ddb491d 100644 --- a/doc/pcre2test.txt +++ b/doc/pcre2test.txt @@ -630,7 +630,9 @@ PATTERN MODIFIERS jitfast use JIT fast path jitverify verify JIT use locale= use this locale - max_pattern_length= set maximum pattern length + max_pattern_compiled ) set maximum compiled pattern + _length= ) length (bytes) + max_pattern_length= set maximum pattern length (code units) max_varlookbehind= set maximum variable lookbehind length memory show memory used newline= set newline type @@ -913,14 +915,21 @@ PATTERN MODIFIERS causes a compilation error. The default is the largest number a PCRE2_SIZE variable can hold (essentially unlimited). + Limiting the size of a compiled pattern + + The max_pattern_compiled_length modifier sets a limit, in bytes, to the + amount of memory used by a compiled pattern. Breaching the limit causes + a compilation error. The default is the largest number a PCRE2_SIZE + variable can hold (essentially unlimited). + Using the POSIX wrapper API - The posix and posix_nosub modifiers cause pcre2test to call PCRE2 via - the POSIX wrapper API rather than its native API. When posix_nosub is - used, the POSIX option REG_NOSUB is passed to regcomp(). The POSIX - wrapper supports only the 8-bit library. Note that it does not imply + The posix and posix_nosub modifiers cause pcre2test to call PCRE2 via + the POSIX wrapper API rather than its native API. When posix_nosub is + used, the POSIX option REG_NOSUB is passed to regcomp(). The POSIX + wrapper supports only the 8-bit library. Note that it does not imply POSIX matching semantics; for more detail see the pcre2posix documenta- - tion. The following pattern modifiers set options for the regcomp() + tion. The following pattern modifiers set options for the regcomp() function: caseless REG_ICASE @@ -930,42 +939,42 @@ PATTERN MODIFIERS ucp REG_UCP ) the POSIX standard utf REG_UTF8 ) - The regerror_buffsize modifier specifies a size for the error buffer - that is passed to regerror() in the event of a compilation error. For + The regerror_buffsize modifier specifies a size for the error buffer + that is passed to regerror() in the event of a compilation error. For example: /abc/posix,regerror_buffsize=20 - This provides a means of testing the behaviour of regerror() when the - buffer is too small for the error message. If this modifier has not + This provides a means of testing the behaviour of regerror() when the + buffer is too small for the error message. If this modifier has not been set, a large buffer is used. - The aftertext and allaftertext subject modifiers work as described be- + The aftertext and allaftertext subject modifiers work as described be- low. All other modifiers are either ignored, with a warning message, or cause an error. - The pattern is passed to regcomp() as a zero-terminated string by de- + The pattern is passed to regcomp() as a zero-terminated string by de- fault, but if the use_length or hex modifiers are set, the REG_PEND ex- tension is used to pass it by length. Testing the stack guard feature - The stackguard modifier is used to test the use of pcre2_set_com- - pile_recursion_guard(), a function that is provided to enable stack - availability to be checked during compilation (see the pcre2api docu- - mentation for details). If the number specified by the modifier is + The stackguard modifier is used to test the use of pcre2_set_com- + pile_recursion_guard(), a function that is provided to enable stack + availability to be checked during compilation (see the pcre2api docu- + mentation for details). If the number specified by the modifier is greater than zero, pcre2_set_compile_recursion_guard() is called to set - up callback from pcre2_compile() to a local function. The argument it - receives is the current nesting parenthesis depth; if this is greater + up callback from pcre2_compile() to a local function. The argument it + receives is the current nesting parenthesis depth; if this is greater than the value given by the modifier, non-zero is returned, causing the compilation to be aborted. Using alternative character tables - The value specified for the tables modifier must be one of the digits + The value specified for the tables modifier must be one of the digits 0, 1, 2, or 3. It causes a specific set of built-in character tables to - be passed to pcre2_compile(). This is used in the PCRE2 tests to check - behaviour with different character tables. The digit specifies the ta- + be passed to pcre2_compile(). This is used in the PCRE2 tests to check + behaviour with different character tables. The digit specifies the ta- bles as follows: 0 do not pass any special character tables @@ -976,15 +985,15 @@ PATTERN MODIFIERS In tables 2, some characters whose codes are greater than 128 are iden- tified as letters, digits, spaces, etc. Tables 3 can be used only after - a #loadtables command has loaded them from a binary file. Setting al- + a #loadtables command has loaded them from a binary file. Setting al- ternate character tables and a locale are mutually exclusive. Setting certain match controls The following modifiers are really subject modifiers, and are described - under "Subject Modifiers" below. However, they may be included in a - pattern's modifier list, in which case they are applied to every sub- - ject line that is processed with that pattern. These modifiers do not + under "Subject Modifiers" below. However, they may be included in a + pattern's modifier list, in which case they are applied to every sub- + ject line that is processed with that pattern. These modifiers do not affect the compilation process. aftertext show text after match @@ -1010,39 +1019,39 @@ PATTERN MODIFIERS substitute_unknown_unset use PCRE2_SUBSTITUTE_UNKNOWN_UNSET substitute_unset_empty use PCRE2_SUBSTITUTE_UNSET_EMPTY - These modifiers may not appear in a #pattern command. If you want them + These modifiers may not appear in a #pattern command. If you want them as defaults, set them in a #subject command. Specifying literal subject lines - If the subject_literal modifier is present on a pattern, all the sub- + If the subject_literal modifier is present on a pattern, all the sub- ject lines that it matches are taken as literal strings, with no inter- - pretation of backslashes. It is not possible to set subject modifiers - on such lines, but any that are set as defaults by a #subject command + pretation of backslashes. It is not possible to set subject modifiers + on such lines, but any that are set as defaults by a #subject command are recognized. Saving a compiled pattern - When a pattern with the push modifier is successfully compiled, it is - pushed onto a stack of compiled patterns, and pcre2test expects the - next line to contain a new pattern (or a command) instead of a subject + When a pattern with the push modifier is successfully compiled, it is + pushed onto a stack of compiled patterns, and pcre2test expects the + next line to contain a new pattern (or a command) instead of a subject line. This facility is used when saving compiled patterns to a file, as - described in the section entitled "Saving and restoring compiled pat- - terns" below. If pushcopy is used instead of push, a copy of the com- - piled pattern is stacked, leaving the original as current, ready to - match the following input lines. This provides a way of testing the - pcre2_code_copy() function. The push and pushcopy modifiers are in- - compatible with compilation modifiers such as global that act at match + described in the section entitled "Saving and restoring compiled pat- + terns" below. If pushcopy is used instead of push, a copy of the com- + piled pattern is stacked, leaving the original as current, ready to + match the following input lines. This provides a way of testing the + pcre2_code_copy() function. The push and pushcopy modifiers are in- + compatible with compilation modifiers such as global that act at match time. Any that are specified are ignored (for the stacked copy), with a - warning message, except for replace, which causes an error. Note that - jitverify, which is allowed, does not carry through to any subsequent + warning message, except for replace, which causes an error. Note that + jitverify, which is allowed, does not carry through to any subsequent matching that uses a stacked pattern. Testing foreign pattern conversion - The experimental foreign pattern conversion functions in PCRE2 can be - tested by setting the convert modifier. Its argument is a colon-sepa- - rated list of options, which set the equivalent option for the + The experimental foreign pattern conversion functions in PCRE2 can be + tested by setting the convert modifier. Its argument is a colon-sepa- + rated list of options, which set the equivalent option for the pcre2_pattern_convert() function: glob PCRE2_CONVERT_GLOB @@ -1054,19 +1063,19 @@ PATTERN MODIFIERS The "unset" value is useful for turning off a default that has been set by a #pattern command. When one of these options is set, the input pat- - tern is passed to pcre2_pattern_convert(). If the conversion is suc- - cessful, the result is reflected in the output and then passed to + tern is passed to pcre2_pattern_convert(). If the conversion is suc- + cessful, the result is reflected in the output and then passed to pcre2_compile(). The normal utf and no_utf_check options, if set, cause - the PCRE2_CONVERT_UTF and PCRE2_CONVERT_NO_UTF_CHECK options to be + the PCRE2_CONVERT_UTF and PCRE2_CONVERT_NO_UTF_CHECK options to be passed to pcre2_pattern_convert(). By default, the conversion function is allowed to allocate a buffer for - its output. However, if the convert_length modifier is set to a value - greater than zero, pcre2test passes a buffer of the given length. This + its output. However, if the convert_length modifier is set to a value + greater than zero, pcre2test passes a buffer of the given length. This makes it possible to test the length check. - The convert_glob_escape and convert_glob_separator modifiers can be - used to specify the escape and separator characters for glob process- + The convert_glob_escape and convert_glob_separator modifiers can be + used to specify the escape and separator characters for glob process- ing, overriding the defaults, which are operating-system dependent. @@ -1077,7 +1086,7 @@ SUBJECT MODIFIERS Setting match options - The following modifiers set options for pcre2_match() or + The following modifiers set options for pcre2_match() or pcre2_dfa_match(). See pcreapi for a description of their effects. anchored set PCRE2_ANCHORED @@ -1094,35 +1103,35 @@ SUBJECT MODIFIERS partial_hard (or ph) set PCRE2_PARTIAL_HARD partial_soft (or ps) set PCRE2_PARTIAL_SOFT - The partial matching modifiers are provided with abbreviations because + The partial matching modifiers are provided with abbreviations because they appear frequently in tests. - If the posix or posix_nosub modifier was present on the pattern, caus- + If the posix or posix_nosub modifier was present on the pattern, caus- ing the POSIX wrapper API to be used, the only option-setting modifiers that have any effect are notbol, notempty, and noteol, causing REG_NOT- - BOL, REG_NOTEMPTY, and REG_NOTEOL, respectively, to be passed to + BOL, REG_NOTEMPTY, and REG_NOTEOL, respectively, to be passed to regexec(). The other modifiers are ignored, with a warning message. - There is one additional modifier that can be used with the POSIX wrap- + There is one additional modifier that can be used with the POSIX wrap- per. It is ignored (with a warning) if used for non-POSIX matching. posix_startend=[:] - This causes the subject string to be passed to regexec() using the - REG_STARTEND option, which uses offsets to specify which part of the - string is searched. If only one number is given, the end offset is - passed as the end of the subject string. For more detail of REG_STAR- - TEND, see the pcre2posix documentation. If the subject string contains - binary zeros (coded as escapes such as \x{00} because pcre2test does + This causes the subject string to be passed to regexec() using the + REG_STARTEND option, which uses offsets to specify which part of the + string is searched. If only one number is given, the end offset is + passed as the end of the subject string. For more detail of REG_STAR- + TEND, see the pcre2posix documentation. If the subject string contains + binary zeros (coded as escapes such as \x{00} because pcre2test does not support actual binary zeros in its input), you must use posix_star- tend to specify its length. Setting match controls - The following modifiers affect the matching process or request addi- - tional information. Some of them may also be specified on a pattern - line (see above), in which case they apply to every subject line that - is matched against that pattern, but can be overridden by modifiers on + The following modifiers affect the matching process or request addi- + tional information. Some of them may also be specified on a pattern + line (see above), in which case they apply to every subject line that + is matched against that pattern, but can be overridden by modifiers on the subject. aftertext show text after match @@ -1175,29 +1184,29 @@ SUBJECT MODIFIERS zero_terminate pass the subject as zero-terminated The effects of these modifiers are described in the following sections. - When matching via the POSIX wrapper API, the aftertext, allaftertext, - and ovector subject modifiers work as described below. All other modi- + When matching via the POSIX wrapper API, the aftertext, allaftertext, + and ovector subject modifiers work as described below. All other modi- fiers are either ignored, with a warning message, or cause an error. Showing more text - The aftertext modifier requests that as well as outputting the part of + The aftertext modifier requests that as well as outputting the part of the subject string that matched the entire pattern, pcre2test should in addition output the remainder of the subject string. This is useful for tests where the subject contains multiple copies of the same substring. - The allaftertext modifier requests the same action for captured sub- + The allaftertext modifier requests the same action for captured sub- strings as well as the main matched substring. In each case the remain- der is output on the following line with a plus character following the capture number. - The allusedtext modifier requests that all the text that was consulted - during a successful pattern match by the interpreter should be shown, - for both full and partial matches. This feature is not supported for - JIT matching, and if requested with JIT it is ignored (with a warning - message). Setting this modifier affects the output if there is a look- - behind at the start of a match, or, for a complete match, a lookahead + The allusedtext modifier requests that all the text that was consulted + during a successful pattern match by the interpreter should be shown, + for both full and partial matches. This feature is not supported for + JIT matching, and if requested with JIT it is ignored (with a warning + message). Setting this modifier affects the output if there is a look- + behind at the start of a match, or, for a complete match, a lookahead at the end, or if \K is used in the pattern. Characters that precede or - follow the start and end of the actual match are indicated in the out- + follow the start and end of the actual match are indicated in the out- put by '<' or '>' characters underneath them. Here is an example: re> /(?<=pqr)abc(?=xyz)/ @@ -1208,16 +1217,16 @@ SUBJECT MODIFIERS Partial match: pqrabcxy <<< - The first, complete match shows that the matched string is "abc", with - the preceding and following strings "pqr" and "xyz" having been con- - sulted during the match (when processing the assertions). The partial + The first, complete match shows that the matched string is "abc", with + the preceding and following strings "pqr" and "xyz" having been con- + sulted during the match (when processing the assertions). The partial match can indicate only the preceding string. - The startchar modifier requests that the starting character for the - match be indicated, if it is different to the start of the matched + The startchar modifier requests that the starting character for the + match be indicated, if it is different to the start of the matched string. The only time when this occurs is when \K has been processed as part of the match. In this situation, the output for the matched string - is displayed from the starting character instead of from the match + is displayed from the starting character instead of from the match point, with circumflex characters under the earlier characters. For ex- ample: @@ -1226,7 +1235,7 @@ SUBJECT MODIFIERS 0: abcxyz ^^^ - Unlike allusedtext, the startchar modifier can be used with JIT. How- + Unlike allusedtext, the startchar modifier can be used with JIT. How- ever, these two modifiers are mutually exclusive. Showing the value of all capture groups @@ -1234,104 +1243,104 @@ SUBJECT MODIFIERS The allcaptures modifier requests that the values of all potential cap- tured parentheses be output after a match. By default, only those up to the highest one actually used in the match are output (corresponding to - the return code from pcre2_match()). Groups that did not take part in - the match are output as "". This modifier is not relevant for - DFA matching (which does no capturing) and does not apply when replace + the return code from pcre2_match()). Groups that did not take part in + the match are output as "". This modifier is not relevant for + DFA matching (which does no capturing) and does not apply when replace is specified; it is ignored, with a warning message, if present. Showing the entire ovector, for all outcomes The allvector modifier requests that the entire ovector be shown, what- ever the outcome of the match. Compare allcaptures, which shows only up - to the maximum number of capture groups for the pattern, and then only - for a successful complete non-DFA match. This modifier, which acts af- - ter any match result, and also for DFA matching, provides a means of - checking that there are no unexpected modifications to ovector fields. - Before each match attempt, the ovector is filled with a special value, - and if this is found in both elements of a capturing pair, "" is output. After a successful match, this applies to all - groups after the maximum capture group for the pattern. In other cases - it applies to the entire ovector. After a partial match, the first two - elements are the only ones that should be set. After a DFA match, the - amount of ovector that is used depends on the number of matches that + to the maximum number of capture groups for the pattern, and then only + for a successful complete non-DFA match. This modifier, which acts af- + ter any match result, and also for DFA matching, provides a means of + checking that there are no unexpected modifications to ovector fields. + Before each match attempt, the ovector is filled with a special value, + and if this is found in both elements of a capturing pair, "" is output. After a successful match, this applies to all + groups after the maximum capture group for the pattern. In other cases + it applies to the entire ovector. After a partial match, the first two + elements are the only ones that should be set. After a DFA match, the + amount of ovector that is used depends on the number of matches that were found. Testing pattern callouts - A callout function is supplied when pcre2test calls the library match- - ing functions, unless callout_none is specified. Its behaviour can be - controlled by various modifiers listed above whose names begin with - callout_. Details are given in the section entitled "Callouts" below. - Testing callouts from pcre2_substitute() is described separately in + A callout function is supplied when pcre2test calls the library match- + ing functions, unless callout_none is specified. Its behaviour can be + controlled by various modifiers listed above whose names begin with + callout_. Details are given in the section entitled "Callouts" below. + Testing callouts from pcre2_substitute() is described separately in "Testing the substitution function" below. Finding all matches in a string Searching for all possible matches within a subject can be requested by - the global or altglobal modifier. After finding a match, the matching - function is called again to search the remainder of the subject. The - difference between global and altglobal is that the former uses the - start_offset argument to pcre2_match() or pcre2_dfa_match() to start - searching at a new point within the entire string (which is what Perl + the global or altglobal modifier. After finding a match, the matching + function is called again to search the remainder of the subject. The + difference between global and altglobal is that the former uses the + start_offset argument to pcre2_match() or pcre2_dfa_match() to start + searching at a new point within the entire string (which is what Perl does), whereas the latter passes over a shortened subject. This makes a difference to the matching process if the pattern begins with a lookbe- hind assertion (including \b or \B). - If an empty string is matched, the next match is done with the + If an empty string is matched, the next match is done with the PCRE2_NOTEMPTY_ATSTART and PCRE2_ANCHORED flags set, in order to search for another, non-empty, match at the same point in the subject. If this - match fails, the start offset is advanced, and the normal match is re- - tried. This imitates the way Perl handles such cases when using the /g - modifier or the split() function. Normally, the start offset is ad- - vanced by one character, but if the newline convention recognizes CRLF - as a newline, and the current character is CR followed by LF, an ad- + match fails, the start offset is advanced, and the normal match is re- + tried. This imitates the way Perl handles such cases when using the /g + modifier or the split() function. Normally, the start offset is ad- + vanced by one character, but if the newline convention recognizes CRLF + as a newline, and the current character is CR followed by LF, an ad- vance of two characters occurs. Testing substring extraction functions - The copy and get modifiers can be used to test the pcre2_sub- + The copy and get modifiers can be used to test the pcre2_sub- string_copy_xxx() and pcre2_substring_get_xxx() functions. They can be given more than once, and each can specify a capture group name or num- ber, for example: abcd\=copy=1,copy=3,get=G1 - If the #subject command is used to set default copy and/or get lists, - these can be unset by specifying a negative number to cancel all num- + If the #subject command is used to set default copy and/or get lists, + these can be unset by specifying a negative number to cancel all num- bered groups and an empty name to cancel all named groups. - The getall modifier tests pcre2_substring_list_get(), which extracts + The getall modifier tests pcre2_substring_list_get(), which extracts all captured substrings. - If the subject line is successfully matched, the substrings extracted - by the convenience functions are output with C, G, or L after the - string number instead of a colon. This is in addition to the normal - full list. The string length (that is, the return from the extraction + If the subject line is successfully matched, the substrings extracted + by the convenience functions are output with C, G, or L after the + string number instead of a colon. This is in addition to the normal + full list. The string length (that is, the return from the extraction function) is given in parentheses after each substring, followed by the name when the extraction was by name. Testing the substitution function - If the replace modifier is set, the pcre2_substitute() function is - called instead of one of the matching functions (or after one call of - pcre2_match() in the case of PCRE2_SUBSTITUTE_MATCHED). Note that re- - placement strings cannot contain commas, because a comma signifies the - end of a modifier. This is not thought to be an issue in a test pro- + If the replace modifier is set, the pcre2_substitute() function is + called instead of one of the matching functions (or after one call of + pcre2_match() in the case of PCRE2_SUBSTITUTE_MATCHED). Note that re- + placement strings cannot contain commas, because a comma signifies the + end of a modifier. This is not thought to be an issue in a test pro- gram. - Specifying a completely empty replacement string disables this modi- - fier. However, it is possible to specify an empty replacement by pro- - viding a buffer length, as described below, for an otherwise empty re- + Specifying a completely empty replacement string disables this modi- + fier. However, it is possible to specify an empty replacement by pro- + viding a buffer length, as described below, for an otherwise empty re- placement. - Unlike subject strings, pcre2test does not process replacement strings - for escape sequences. In UTF mode, a replacement string is checked to - see if it is a valid UTF-8 string. If so, it is correctly converted to - a UTF string of the appropriate code unit width. If it is not a valid - UTF-8 string, the individual code units are copied directly. This pro- + Unlike subject strings, pcre2test does not process replacement strings + for escape sequences. In UTF mode, a replacement string is checked to + see if it is a valid UTF-8 string. If so, it is correctly converted to + a UTF string of the appropriate code unit width. If it is not a valid + UTF-8 string, the individual code units are copied directly. This pro- vides a means of passing an invalid UTF-8 string for testing purposes. - The following modifiers set options (in additional to the normal match + The following modifiers set options (in additional to the normal match options) for pcre2_substitute(): global PCRE2_SUBSTITUTE_GLOBAL @@ -1345,8 +1354,8 @@ SUBJECT MODIFIERS See the pcre2api documentation for details of these options. - After a successful substitution, the modified string is output, pre- - ceded by the number of replacements. This may be zero if there were no + After a successful substitution, the modified string is output, pre- + ceded by the number of replacements. This may be zero if there were no matches. Here is a simple example of a substitution test: /abc/replace=xxx @@ -1355,12 +1364,12 @@ SUBJECT MODIFIERS =abc=abc=\=global 2: =xxx=xxx= - Subject and replacement strings should be kept relatively short (fewer - than 256 characters) for substitution tests, as fixed-size buffers are - used. To make it easy to test for buffer overflow, if the replacement - string starts with a number in square brackets, that number is passed - to pcre2_substitute() as the size of the output buffer, with the re- - placement string starting at the next character. Here is an example + Subject and replacement strings should be kept relatively short (fewer + than 256 characters) for substitution tests, as fixed-size buffers are + used. To make it easy to test for buffer overflow, if the replacement + string starts with a number in square brackets, that number is passed + to pcre2_substitute() as the size of the output buffer, with the re- + placement string starting at the next character. Here is an example that tests the edge case: /abc/ @@ -1370,12 +1379,12 @@ SUBJECT MODIFIERS Failed: error -47: no more memory The default action of pcre2_substitute() is to return PCRE2_ER- - ROR_NOMEMORY when the output buffer is too small. However, if the - PCRE2_SUBSTITUTE_OVERFLOW_LENGTH option is set (by using the substi- + ROR_NOMEMORY when the output buffer is too small. However, if the + PCRE2_SUBSTITUTE_OVERFLOW_LENGTH option is set (by using the substi- tute_overflow_length modifier), pcre2_substitute() continues to go - through the motions of matching and substituting (but not doing any - callouts), in order to compute the size of buffer that is required. - When this happens, pcre2test shows the required buffer length (which + through the motions of matching and substituting (but not doing any + callouts), in order to compute the size of buffer that is required. + When this happens, pcre2test shows the required buffer length (which includes space for the trailing zero) as part of the error message. For example: @@ -1384,15 +1393,15 @@ SUBJECT MODIFIERS Failed: error -47: no more memory: 10 code units are needed A replacement string is ignored with POSIX and DFA matching. Specifying - partial matching provokes an error return ("bad option value") from + partial matching provokes an error return ("bad option value") from pcre2_substitute(). Testing substitute callouts If the substitute_callout modifier is set, a substitution callout func- - tion is set up. The null_context modifier must not be set, because the - address of the callout function is passed in a match context. When the - callout function is called (after each substitution), details of the + tion is set up. The null_context modifier must not be set, because the + address of the callout function is passed in a match context. When the + callout function is called (after each substitution), details of the input and output strings are output. For example: /abc/g,replace=<$0>,substitute_callout @@ -1401,19 +1410,19 @@ SUBJECT MODIFIERS 2(1) Old 6 9 "abc" New 8 13 "" 2: defpqr - The first number on each callout line is the count of matches. The + The first number on each callout line is the count of matches. The parenthesized number is the number of pairs that are set in the ovector - (that is, one more than the number of capturing groups that were set). + (that is, one more than the number of capturing groups that were set). Then are listed the offsets of the old substring, its contents, and the same for the replacement. - By default, the substitution callout function returns zero, which ac- - cepts the replacement and causes matching to continue if /g was used. - Two further modifiers can be used to test other return values. If sub- - stitute_skip is set to a value greater than zero the callout function - returns +1 for the match of that number, and similarly substitute_stop - returns -1. These cause the replacement to be rejected, and -1 causes - no further matching to take place. If either of them are set, substi- + By default, the substitution callout function returns zero, which ac- + cepts the replacement and causes matching to continue if /g was used. + Two further modifiers can be used to test other return values. If sub- + stitute_skip is set to a value greater than zero the callout function + returns +1 for the match of that number, and similarly substitute_stop + returns -1. These cause the replacement to be rejected, and -1 causes + no further matching to take place. If either of them are set, substi- tute_callout is assumed. For example: /abc/g,replace=<$0>,substitute_skip=1 @@ -1431,181 +1440,181 @@ SUBJECT MODIFIERS Setting the JIT stack size - The jitstack modifier provides a way of setting the maximum stack size - that is used by the just-in-time optimization code. It is ignored if - JIT optimization is not being used. The value is a number of kibibytes - (units of 1024 bytes). Setting zero reverts to the default of 32KiB. + The jitstack modifier provides a way of setting the maximum stack size + that is used by the just-in-time optimization code. It is ignored if + JIT optimization is not being used. The value is a number of kibibytes + (units of 1024 bytes). Setting zero reverts to the default of 32KiB. Providing a stack that is larger than the default is necessary only for - very complicated patterns. If jitstack is set non-zero on a subject + very complicated patterns. If jitstack is set non-zero on a subject line it overrides any value that was set on the pattern. Setting heap, match, and depth limits - The heap_limit, match_limit, and depth_limit modifiers set the appro- - priate limits in the match context. These values are ignored when the + The heap_limit, match_limit, and depth_limit modifiers set the appro- + priate limits in the match context. These values are ignored when the find_limits or find_limits_noheap modifier is specified. Finding minimum limits - If the find_limits modifier is present on a subject line, pcre2test - calls the relevant matching function several times, setting different - values in the match context via pcre2_set_heap_limit(), - pcre2_set_match_limit(), or pcre2_set_depth_limit() until it finds the - smallest value for each parameter that allows the match to complete + If the find_limits modifier is present on a subject line, pcre2test + calls the relevant matching function several times, setting different + values in the match context via pcre2_set_heap_limit(), + pcre2_set_match_limit(), or pcre2_set_depth_limit() until it finds the + smallest value for each parameter that allows the match to complete without a "limit exceeded" error. The match itself may succeed or fail. An alternative modifier, find_limits_noheap, omits the heap limit. This - is used in the standard tests, because the minimum heap limit varies - between systems. If JIT is being used, only the match limit is rele- + is used in the standard tests, because the minimum heap limit varies + between systems. If JIT is being used, only the match limit is rele- vant, and the other two are automatically omitted. When using this modifier, the pattern should not contain any limit set- - tings such as (*LIMIT_MATCH=...) within it. If such a setting is + tings such as (*LIMIT_MATCH=...) within it. If such a setting is present and is lower than the minimum matching value, the minimum value - cannot be found because pcre2_set_match_limit() etc. are only able to + cannot be found because pcre2_set_match_limit() etc. are only able to reduce the value of an in-pattern limit; they cannot increase it. - For non-DFA matching, the minimum depth_limit number is a measure of + For non-DFA matching, the minimum depth_limit number is a measure of how much nested backtracking happens (that is, how deeply the pattern's - tree is searched). In the case of DFA matching, depth_limit controls - the depth of recursive calls of the internal function that is used for + tree is searched). In the case of DFA matching, depth_limit controls + the depth of recursive calls of the internal function that is used for handling pattern recursion, lookaround assertions, and atomic groups. For non-DFA matching, the match_limit number is a measure of the amount of backtracking that takes place, and learning the minimum value can be - instructive. For most simple matches, the number is quite small, but - for patterns with very large numbers of matching possibilities, it can - become large very quickly with increasing length of subject string. In - the case of DFA matching, match_limit controls the total number of + instructive. For most simple matches, the number is quite small, but + for patterns with very large numbers of matching possibilities, it can + become large very quickly with increasing length of subject string. In + the case of DFA matching, match_limit controls the total number of calls, both recursive and non-recursive, to the internal matching func- tion, thus controlling the overall amount of computing resource that is used. - For both kinds of matching, the heap_limit number, which is in - kibibytes (units of 1024 bytes), limits the amount of heap memory used + For both kinds of matching, the heap_limit number, which is in + kibibytes (units of 1024 bytes), limits the amount of heap memory used for matching. Showing MARK names The mark modifier causes the names from backtracking control verbs that - are returned from calls to pcre2_match() to be displayed. If a mark is - returned for a match, non-match, or partial match, pcre2test shows it. - For a match, it is on a line by itself, tagged with "MK:". Otherwise, + are returned from calls to pcre2_match() to be displayed. If a mark is + returned for a match, non-match, or partial match, pcre2test shows it. + For a match, it is on a line by itself, tagged with "MK:". Otherwise, it is added to the non-match message. Showing memory usage - The memory modifier causes pcre2test to log the sizes of all heap mem- - ory allocation and freeing calls that occur during a call to - pcre2_match() or pcre2_dfa_match(). In the latter case, heap memory is - used only when a match requires more internal workspace that the de- - fault allocation on the stack, so in many cases there will be no out- - put. No heap memory is allocated during matching with JIT. For this + The memory modifier causes pcre2test to log the sizes of all heap mem- + ory allocation and freeing calls that occur during a call to + pcre2_match() or pcre2_dfa_match(). In the latter case, heap memory is + used only when a match requires more internal workspace that the de- + fault allocation on the stack, so in many cases there will be no out- + put. No heap memory is allocated during matching with JIT. For this modifier to work, the null_context modifier must not be set on both the pattern and the subject, though it can be set on one or the other. Showing the heap frame overall vector size - The heapframes_size modifier is relevant for matches using + The heapframes_size modifier is relevant for matches using pcre2_match() without JIT. After a match has run (whether successful or - not) the size, in bytes, of the allocated heap frames vector that is - left attached to the match data block is shown. If the matching action - involved several calls to pcre2_match() (for example, global matching + not) the size, in bytes, of the allocated heap frames vector that is + left attached to the match data block is shown. If the matching action + involved several calls to pcre2_match() (for example, global matching or for timing) only the final value is shown. - This modifier is ignored, with a warning, for POSIX or DFA matching. + This modifier is ignored, with a warning, for POSIX or DFA matching. JIT matching does not use the heap frames vector, so the size is always - zero, unless there was a previous non-JIT match. Note that specifing a + zero, unless there was a previous non-JIT match. Note that specifing a size of zero for the output vector (see below) causes pcre2test to free its match data block (and associated heap frames vector) and allocate a new one. Setting a starting offset - The offset modifier sets an offset in the subject string at which + The offset modifier sets an offset in the subject string at which matching starts. Its value is a number of code units, not characters. Setting an offset limit - The offset_limit modifier sets a limit for unanchored matches. If a + The offset_limit modifier sets a limit for unanchored matches. If a match cannot be found starting at or before this offset in the subject, a "no match" return is given. The data value is a number of code units, - not characters. When this modifier is used, the use_offset_limit modi- + not characters. When this modifier is used, the use_offset_limit modi- fier must have been set for the pattern; if not, an error is generated. Setting the size of the output vector - The ovector modifier applies only to the subject line in which it ap- + The ovector modifier applies only to the subject line in which it ap- pears, though of course it can also be used to set a default in a #sub- - ject command. It specifies the number of pairs of offsets that are + ject command. It specifies the number of pairs of offsets that are available for storing matching information. The default is 15. - A value of zero is useful when testing the POSIX API because it causes + A value of zero is useful when testing the POSIX API because it causes regexec() to be called with a NULL capture vector. When not testing the - POSIX API, a value of zero is used to cause pcre2_match_data_cre- - ate_from_pattern() to be called, in order to create a new match block - of exactly the right size for the pattern. (It is not possible to cre- - ate a match block with a zero-length ovector; there is always at least + POSIX API, a value of zero is used to cause pcre2_match_data_cre- + ate_from_pattern() to be called, in order to create a new match block + of exactly the right size for the pattern. (It is not possible to cre- + ate a match block with a zero-length ovector; there is always at least one pair of offsets.) The old match data block is freed. Passing the subject as zero-terminated By default, the subject string is passed to a native API matching func- tion with its correct length. In order to test the facility for passing - a zero-terminated string, the zero_terminate modifier is provided. It - causes the length to be passed as PCRE2_ZERO_TERMINATED. When matching + a zero-terminated string, the zero_terminate modifier is provided. It + causes the length to be passed as PCRE2_ZERO_TERMINATED. When matching via the POSIX interface, this modifier is ignored, with a warning. - When testing pcre2_substitute(), this modifier also has the effect of + When testing pcre2_substitute(), this modifier also has the effect of passing the replacement string as zero-terminated. Passing a NULL context, subject, or replacement - Normally, pcre2test passes a context block to pcre2_match(), - pcre2_dfa_match(), pcre2_jit_match() or pcre2_substitute(). If the - null_context modifier is set, however, NULL is passed. This is for - testing that the matching and substitution functions behave correctly - in this case (they use default values). This modifier cannot be used - with the find_limits, find_limits_noheap, or substitute_callout modi- + Normally, pcre2test passes a context block to pcre2_match(), + pcre2_dfa_match(), pcre2_jit_match() or pcre2_substitute(). If the + null_context modifier is set, however, NULL is passed. This is for + testing that the matching and substitution functions behave correctly + in this case (they use default values). This modifier cannot be used + with the find_limits, find_limits_noheap, or substitute_callout modi- fiers. - Similarly, for testing purposes, if the null_subject or null_replace- - ment modifier is set, the subject or replacement string pointers are + Similarly, for testing purposes, if the null_subject or null_replace- + ment modifier is set, the subject or replacement string pointers are passed as NULL, respectively, to the relevant functions. THE ALTERNATIVE MATCHING FUNCTION - By default, pcre2test uses the standard PCRE2 matching function, + By default, pcre2test uses the standard PCRE2 matching function, pcre2_match() to match each subject line. PCRE2 also supports an alter- - native matching function, pcre2_dfa_match(), which operates in a dif- - ferent way, and has some restrictions. The differences between the two + native matching function, pcre2_dfa_match(), which operates in a dif- + ferent way, and has some restrictions. The differences between the two functions are described in the pcre2matching documentation. - If the dfa modifier is set, the alternative matching function is used. - This function finds all possible matches at a given point in the sub- - ject. If, however, the dfa_shortest modifier is set, processing stops - after the first match is found. This is always the shortest possible + If the dfa modifier is set, the alternative matching function is used. + This function finds all possible matches at a given point in the sub- + ject. If, however, the dfa_shortest modifier is set, processing stops + after the first match is found. This is always the shortest possible match. DEFAULT OUTPUT FROM pcre2test - This section describes the output when the normal matching function, + This section describes the output when the normal matching function, pcre2_match(), is being used. - When a match succeeds, pcre2test outputs the list of captured sub- - strings, starting with number 0 for the string that matched the whole + When a match succeeds, pcre2test outputs the list of captured sub- + strings, starting with number 0 for the string that matched the whole pattern. Otherwise, it outputs "No match" when the return is PCRE2_ER- - ROR_NOMATCH, or "Partial match:" followed by the partially matching - substring when the return is PCRE2_ERROR_PARTIAL. (Note that this is - the entire substring that was inspected during the partial match; it - may include characters before the actual match start if a lookbehind + ROR_NOMATCH, or "Partial match:" followed by the partially matching + substring when the return is PCRE2_ERROR_PARTIAL. (Note that this is + the entire substring that was inspected during the partial match; it + may include characters before the actual match start if a lookbehind assertion, \K, \b, or \B was involved.) For any other return, pcre2test outputs the PCRE2 negative error number - and a short descriptive phrase. If the error is a failed UTF string - check, the code unit offset of the start of the failing character is + and a short descriptive phrase. If the error is a failed UTF string + check, the code unit offset of the start of the failing character is also output. Here is an example of an interactive pcre2test run. $ pcre2test @@ -1621,8 +1630,8 @@ DEFAULT OUTPUT FROM pcre2test Unset capturing substrings that are not followed by one that is set are not shown by pcre2test unless the allcaptures modifier is specified. In the following example, there are two capturing substrings, but when the - first data line is matched, the second, unset substring is not shown. - An "internal" unset substring is shown as "", as for the second + first data line is matched, the second, unset substring is not shown. + An "internal" unset substring is shown as "", as for the second data line. re> /(a)|(b)/ @@ -1634,11 +1643,11 @@ DEFAULT OUTPUT FROM pcre2test 1: 2: b - If the strings contain any non-printing characters, they are output as - \xhh escapes if the value is less than 256 and UTF mode is not set. + If the strings contain any non-printing characters, they are output as + \xhh escapes if the value is less than 256 and UTF mode is not set. Otherwise they are output as \x{hh...} escapes. See below for the defi- - nition of non-printing characters. If the aftertext modifier is set, - the output for substring 0 is followed by the rest of the subject + nition of non-printing characters. If the aftertext modifier is set, + the output for substring 0 is followed by the rest of the subject string, identified by "0+" like this: re> /cat/aftertext @@ -1658,8 +1667,8 @@ DEFAULT OUTPUT FROM pcre2test 0: ipp 1: pp - "No match" is output only if the first match attempt fails. Here is an - example of a failure message (the offset 4 that is specified by the + "No match" is output only if the first match attempt fails. Here is an + example of a failure message (the offset 4 that is specified by the offset modifier is past the end of the subject string): re> /xyz/ @@ -1667,7 +1676,7 @@ DEFAULT OUTPUT FROM pcre2test Error -24 (bad offset value) Note that whereas patterns can be continued over several lines (a plain - ">" prompt is used for continuations), subject lines may not. However + ">" prompt is used for continuations), subject lines may not. However newlines can be included in a subject by means of the \n escape (or \r, \r\n, etc., depending on the newline sequence setting). @@ -1675,7 +1684,7 @@ DEFAULT OUTPUT FROM pcre2test OUTPUT FROM THE ALTERNATIVE MATCHING FUNCTION When the alternative matching function, pcre2_dfa_match(), is used, the - output consists of a list of all the matches that start at the first + output consists of a list of all the matches that start at the first point in the subject where there is at least one match. For example: re> /(tang|tangerine|tan)/ @@ -1684,11 +1693,11 @@ OUTPUT FROM THE ALTERNATIVE MATCHING FUNCTION 1: tang 2: tan - Using the normal matching function on this data finds only "tang". The - longest matching string is always given first (and numbered zero). Af- - ter a PCRE2_ERROR_PARTIAL return, the output is "Partial match:", fol- + Using the normal matching function on this data finds only "tang". The + longest matching string is always given first (and numbered zero). Af- + ter a PCRE2_ERROR_PARTIAL return, the output is "Partial match:", fol- lowed by the partially matching substring. Note that this is the entire - substring that was inspected during the partial match; it may include + substring that was inspected during the partial match; it may include characters before the actual match start if a lookbehind assertion, \b, or \B was involved. (\K is not supported for DFA matching.) @@ -1704,16 +1713,16 @@ OUTPUT FROM THE ALTERNATIVE MATCHING FUNCTION 1: tan 0: tan - The alternative matching function does not support substring capture, - so the modifiers that are concerned with captured substrings are not + The alternative matching function does not support substring capture, + so the modifiers that are concerned with captured substrings are not relevant. RESTARTING AFTER A PARTIAL MATCH - When the alternative matching function has given the PCRE2_ERROR_PAR- + When the alternative matching function has given the PCRE2_ERROR_PAR- TIAL return, indicating that the subject partially matched the pattern, - you can restart the match with additional subject data by means of the + you can restart the match with additional subject data by means of the dfa_restart modifier. For example: re> /^\d?\d(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)\d\d$/ @@ -1722,37 +1731,37 @@ RESTARTING AFTER A PARTIAL MATCH data> n05\=dfa,dfa_restart 0: n05 - For further information about partial matching, see the pcre2partial + For further information about partial matching, see the pcre2partial documentation. CALLOUTS If the pattern contains any callout requests, pcre2test's callout func- - tion is called during matching unless callout_none is specified. This + tion is called during matching unless callout_none is specified. This works with both matching functions, and with JIT, though there are some - differences in behaviour. The output for callouts with numerical argu- + differences in behaviour. The output for callouts with numerical argu- ments and those with string arguments is slightly different. Callouts with numerical arguments By default, the callout function displays the callout number, the start - and current positions in the subject text at the callout time, and the + and current positions in the subject text at the callout time, and the next pattern item to be tested. For example: --->pqrabcdef 0 ^ ^ \d - This output indicates that callout number 0 occurred for a match at- - tempt starting at the fourth character of the subject string, when the - pointer was at the seventh character, and when the next pattern item - was \d. Just one circumflex is output if the start and current posi- + This output indicates that callout number 0 occurred for a match at- + tempt starting at the fourth character of the subject string, when the + pointer was at the seventh character, and when the next pattern item + was \d. Just one circumflex is output if the start and current posi- tions are the same, or if the current position precedes the start posi- tion, which can happen if the callout is in a lookbehind assertion. Callouts numbered 255 are assumed to be automatic callouts, inserted as a result of the auto_callout pattern modifier. In this case, instead of - showing the callout number, the offset in the pattern, preceded by a + showing the callout number, the offset in the pattern, preceded by a plus, is output. For example: re> /\d?[A-E]\*/auto_callout @@ -1779,17 +1788,17 @@ CALLOUTS +12 ^ ^ 0: abc - The mark changes between matching "a" and "b", but stays the same for - the rest of the match, so nothing more is output. If, as a result of - backtracking, the mark reverts to being unset, the text "" is + The mark changes between matching "a" and "b", but stays the same for + the rest of the match, so nothing more is output. If, as a result of + backtracking, the mark reverts to being unset, the text "" is output. Callouts with string arguments The output for a callout with a string argument is similar, except that - instead of outputting a callout number before the position indicators, - the callout string and its offset in the pattern string are output be- - fore the reflection of the subject string, and the subject string is + instead of outputting a callout number before the position indicators, + the callout string and its offset in the pattern string are output be- + fore the reflection of the subject string, and the subject string is reflected for each callout. For example: re> /^ab(?C'first')cd(?C"second")ef/ @@ -1805,26 +1814,26 @@ CALLOUTS Callout modifiers - The callout function in pcre2test returns zero (carry on matching) by - default, but you can use a callout_fail modifier in a subject line to + The callout function in pcre2test returns zero (carry on matching) by + default, but you can use a callout_fail modifier in a subject line to change this and other parameters of the callout (see below). If the callout_capture modifier is set, the current captured groups are output when a callout occurs. This is useful only for non-DFA matching, - as pcre2_dfa_match() does not support capturing, so no captures are + as pcre2_dfa_match() does not support capturing, so no captures are ever shown. The normal callout output, showing the callout number or pattern offset - (as described above) is suppressed if the callout_no_where modifier is + (as described above) is suppressed if the callout_no_where modifier is set. - When using the interpretive matching function pcre2_match() without - JIT, setting the callout_extra modifier causes additional output from - pcre2test's callout function to be generated. For the first callout in - a match attempt at a new starting position in the subject, "New match - attempt" is output. If there has been a backtrack since the last call- + When using the interpretive matching function pcre2_match() without + JIT, setting the callout_extra modifier causes additional output from + pcre2test's callout function to be generated. For the first callout in + a match attempt at a new starting position in the subject, "New match + attempt" is output. If there has been a backtrack since the last call- out (or start of matching if this is the first callout), "Backtrack" is - output, followed by "No other matching paths" if the backtrack ended + output, followed by "No other matching paths" if the backtrack ended the previous match attempt. For example: re> /(a+)b/auto_callout,no_start_optimize,no_auto_possess @@ -1861,86 +1870,86 @@ CALLOUTS +1 ^ a+ No match - Notice that various optimizations must be turned off if you want all - possible matching paths to be scanned. If no_start_optimize is not - used, there is an immediate "no match", without any callouts, because - the starting optimization fails to find "b" in the subject, which it - knows must be present for any match. If no_auto_possess is not used, - the "a+" item is turned into "a++", which reduces the number of back- + Notice that various optimizations must be turned off if you want all + possible matching paths to be scanned. If no_start_optimize is not + used, there is an immediate "no match", without any callouts, because + the starting optimization fails to find "b" in the subject, which it + knows must be present for any match. If no_auto_possess is not used, + the "a+" item is turned into "a++", which reduces the number of back- tracks. - The callout_extra modifier has no effect if used with the DFA matching + The callout_extra modifier has no effect if used with the DFA matching function, or with JIT. Return values from callouts - The default return from the callout function is zero, which allows + The default return from the callout function is zero, which allows matching to continue. The callout_fail modifier can be given one or two numbers. If there is only one number, 1 is returned instead of 0 (caus- ing matching to backtrack) when a callout of that number is reached. If - two numbers (:) are given, 1 is returned when callout is - reached and there have been at least callouts. The callout_error + two numbers (:) are given, 1 is returned when callout is + reached and there have been at least callouts. The callout_error modifier is similar, except that PCRE2_ERROR_CALLOUT is returned, caus- - ing the entire matching process to be aborted. If both these modifiers - are set for the same callout number, callout_error takes precedence. - Note that callouts with string arguments are always given the number + ing the entire matching process to be aborted. If both these modifiers + are set for the same callout number, callout_error takes precedence. + Note that callouts with string arguments are always given the number zero. - The callout_data modifier can be given an unsigned or a negative num- - ber. This is set as the "user data" that is passed to the matching - function, and passed back when the callout function is invoked. Any - value other than zero is used as a return from pcre2test's callout + The callout_data modifier can be given an unsigned or a negative num- + ber. This is set as the "user data" that is passed to the matching + function, and passed back when the callout function is invoked. Any + value other than zero is used as a return from pcre2test's callout function. Inserting callouts can be helpful when using pcre2test to check compli- - cated regular expressions. For further information about callouts, see + cated regular expressions. For further information about callouts, see the pcre2callout documentation. NON-PRINTING CHARACTERS When pcre2test is outputting text in the compiled version of a pattern, - bytes other than 32-126 are always treated as non-printing characters + bytes other than 32-126 are always treated as non-printing characters and are therefore shown as hex escapes. - When pcre2test is outputting text that is a matched part of a subject - string, it behaves in the same way, unless a different locale has been - set for the pattern (using the locale modifier). In this case, the is- + When pcre2test is outputting text that is a matched part of a subject + string, it behaves in the same way, unless a different locale has been + set for the pattern (using the locale modifier). In this case, the is- print() function is used to distinguish printing and non-printing char- acters. SAVING AND RESTORING COMPILED PATTERNS - It is possible to save compiled patterns on disc or elsewhere, and re- - load them later, subject to a number of restrictions. JIT data cannot - be saved. The host on which the patterns are reloaded must be running + It is possible to save compiled patterns on disc or elsewhere, and re- + load them later, subject to a number of restrictions. JIT data cannot + be saved. The host on which the patterns are reloaded must be running the same version of PCRE2, with the same code unit width, and must also - have the same endianness, pointer width and PCRE2_SIZE type. Before - compiled patterns can be saved they must be serialized, that is, con- - verted to a stream of bytes. A single byte stream may contain any num- - ber of compiled patterns, but they must all use the same character ta- - bles. A single copy of the tables is included in the byte stream (its + have the same endianness, pointer width and PCRE2_SIZE type. Before + compiled patterns can be saved they must be serialized, that is, con- + verted to a stream of bytes. A single byte stream may contain any num- + ber of compiled patterns, but they must all use the same character ta- + bles. A single copy of the tables is included in the byte stream (its size is 1088 bytes). - The functions whose names begin with pcre2_serialize_ are used for se- - rializing and de-serializing. They are described in the pcre2serialize - documentation. In this section we describe the features of pcre2test + The functions whose names begin with pcre2_serialize_ are used for se- + rializing and de-serializing. They are described in the pcre2serialize + documentation. In this section we describe the features of pcre2test that can be used to test these functions. - Note that "serialization" in PCRE2 does not convert compiled patterns - to an abstract format like Java or .NET. It just makes a reloadable + Note that "serialization" in PCRE2 does not convert compiled patterns + to an abstract format like Java or .NET. It just makes a reloadable byte code stream. Hence the restrictions on reloading mentioned above. - In pcre2test, when a pattern with push modifier is successfully com- - piled, it is pushed onto a stack of compiled patterns, and pcre2test - expects the next line to contain a new pattern (or command) instead of + In pcre2test, when a pattern with push modifier is successfully com- + piled, it is pushed onto a stack of compiled patterns, and pcre2test + expects the next line to contain a new pattern (or command) instead of a subject line. By contrast, the pushcopy modifier causes a copy of the - compiled pattern to be stacked, leaving the original available for im- - mediate matching. By using push and/or pushcopy, a number of patterns - can be compiled and retained. These modifiers are incompatible with + compiled pattern to be stacked, leaving the original available for im- + mediate matching. By using push and/or pushcopy, a number of patterns + can be compiled and retained. These modifiers are incompatible with posix, and control modifiers that act at match time are ignored (with a - message) for the stacked patterns. The jitverify modifier applies only + message) for the stacked patterns. The jitverify modifier applies only at compile time. The command @@ -1948,21 +1957,21 @@ SAVING AND RESTORING COMPILED PATTERNS #save causes all the stacked patterns to be serialized and the result written - to the named file. Afterwards, all the stacked patterns are freed. The + to the named file. Afterwards, all the stacked patterns are freed. The command #load - reads the data in the file, and then arranges for it to be de-serial- - ized, with the resulting compiled patterns added to the pattern stack. - The pattern on the top of the stack can be retrieved by the #pop com- - mand, which must be followed by lines of subjects that are to be - matched with the pattern, terminated as usual by an empty line or end - of file. This command may be followed by a modifier list containing - only control modifiers that act after a pattern has been compiled. In - particular, hex, posix, posix_nosub, push, and pushcopy are not al- - lowed, nor are any option-setting modifiers. The JIT modifiers are, - however permitted. Here is an example that saves and reloads two pat- + reads the data in the file, and then arranges for it to be de-serial- + ized, with the resulting compiled patterns added to the pattern stack. + The pattern on the top of the stack can be retrieved by the #pop com- + mand, which must be followed by lines of subjects that are to be + matched with the pattern, terminated as usual by an empty line or end + of file. This command may be followed by a modifier list containing + only control modifiers that act after a pattern has been compiled. In + particular, hex, posix, posix_nosub, push, and pushcopy are not al- + lowed, nor are any option-setting modifiers. The JIT modifiers are, + however permitted. Here is an example that saves and reloads two pat- terns. /abc/push @@ -1975,10 +1984,10 @@ SAVING AND RESTORING COMPILED PATTERNS #pop jit,bincode abc - If jitverify is used with #pop, it does not automatically imply jit, + If jitverify is used with #pop, it does not automatically imply jit, which is different behaviour from when it is used on a pattern. - The #popcopy command is analogous to the pushcopy modifier in that it + The #popcopy command is analogous to the pushcopy modifier in that it makes current a copy of the topmost stack pattern, leaving the original still on the stack. @@ -1998,8 +2007,8 @@ AUTHOR REVISION - Last updated: 27 January 2024 + Last updated: 24 April 2024 Copyright (c) 1997-2024 University of Cambridge. -PCRE 10.43 27 January 2024 PCRE2TEST(1) +PCRE 10.44 24 April 2024 PCRE2TEST(1) diff --git a/ltmain.sh b/ltmain.sh index 5506693..51e57e3 100644 --- a/ltmain.sh +++ b/ltmain.sh @@ -2,11 +2,11 @@ ## DO NOT EDIT - This file generated from ./build-aux/ltmain.in ## by inline-source v2019-02-19.15 -# libtool (GNU libtool) 2.4.7.4-1ec8f-dirty +# libtool (GNU libtool) 2.5.0.1-38c1-dirty # Provide generalized library-building support services. # Written by Gordon Matzigkeit , 1996 -# Copyright (C) 1996-2019, 2021-2022 Free Software Foundation, Inc. +# Copyright (C) 1996-2019, 2021-2024 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. @@ -31,8 +31,8 @@ PROGRAM=libtool PACKAGE=libtool -VERSION=2.4.7.4-1ec8f-dirty -package_revision=2.4.7.4 +VERSION=2.5.0.1-38c1-dirty +package_revision=2.5.0.1 ## ------ ## @@ -72,11 +72,11 @@ scriptversion=2019-02-19.15; # UTC # This is free software. There is NO warranty; not even for # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # -# Copyright (C) 2004-2019, 2021 Bootstrap Authors +# Copyright (C) 2004-2019, 2021, 2023 Bootstrap Authors # # This file is dual licensed under the terms of the MIT license -# , and GPL version 2 or later -# . You must apply one of +# , and GPL version 2 or later +# . You must apply one of # these licenses when using or redistributing this software or any of # the files within it. See the URLs above, or the file `LICENSE` # included in the Bootstrap distribution for the full license texts. @@ -143,7 +143,7 @@ nl=' ' IFS="$sp $nl" -# There are apparently some retarded systems that use ';' as a PATH separator! +# There are apparently some systems that use ';' as a PATH separator! if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { @@ -1536,11 +1536,11 @@ func_lt_ver () # This is free software. There is NO warranty; not even for # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # -# Copyright (C) 2010-2019, 2021 Bootstrap Authors +# Copyright (C) 2010-2019, 2021, 2023 Bootstrap Authors # # This file is dual licensed under the terms of the MIT license -# , and GPL version 2 or later -# . You must apply one of +# , and GPL version 2 or later +# . You must apply one of # these licenses when using or redistributing this software or any of # the files within it. See the URLs above, or the file `LICENSE` # included in the Bootstrap distribution for the full license texts. @@ -2215,7 +2215,7 @@ func_version () # End: # Set a version string. -scriptversion='(GNU libtool) 2.4.7.4-1ec8f-dirty' +scriptversion='(GNU libtool) 2.5.0.1-38c1-dirty' # func_echo ARG... @@ -2306,13 +2306,13 @@ include the following information: compiler: $LTCC compiler flags: $LTCFLAGS linker: $LD (gnu? $with_gnu_ld) - version: $progname (GNU libtool) 2.4.7.4-1ec8f-dirty + version: $progname (GNU libtool) 2.5.0.1-38c1-dirty automake: `($AUTOMAKE --version) 2>/dev/null |$SED 1q` autoconf: `($AUTOCONF --version) 2>/dev/null |$SED 1q` Report bugs to . -GNU libtool home page: . -General help using GNU software: ." +GNU libtool home page: . +General help using GNU software: ." exit 0 } @@ -2668,10 +2668,10 @@ libtool_validate_options () # preserve --debug test : = "$debug_cmd" || func_append preserve_args " --debug" - case $host in + case $host_os in # Solaris2 added to fix http://debbugs.gnu.org/cgi/bugreport.cgi?bug=16452 # see also: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59788 - *cygwin* | *mingw* | *pw32* | *cegcc* | *solaris2* | *os2*) + cygwin* | mingw* | windows* | pw32* | cegcc* | solaris2* | os2*) # don't eliminate duplications in $postdeps and $predeps opt_duplicate_compiler_generated_deps=: ;; @@ -3003,7 +3003,7 @@ EOF # func_convert_core_file_wine_to_w32 ARG # Helper function used by file name conversion functions when $build is *nix, -# and $host is mingw, cygwin, or some other w32 environment. Relies on a +# and $host is mingw, windows, cygwin, or some other w32 environment. Relies on a # correctly configured wine environment available, with the winepath program # in $build's $PATH. # @@ -3035,9 +3035,10 @@ func_convert_core_file_wine_to_w32 () # func_convert_core_path_wine_to_w32 ARG # Helper function used by path conversion functions when $build is *nix, and -# $host is mingw, cygwin, or some other w32 environment. Relies on a correctly -# configured wine environment available, with the winepath program in $build's -# $PATH. Assumes ARG has no leading or trailing path separator characters. +# $host is mingw, windows, cygwin, or some other w32 environment. Relies on a +# correctly configured wine environment available, with the winepath program +# in $build's $PATH. Assumes ARG has no leading or trailing path separator +# characters. # # ARG is path to be converted from $build format to win32. # Result is available in $func_convert_core_path_wine_to_w32_result. @@ -3692,7 +3693,7 @@ func_mode_compile () # On Cygwin there's no "real" PIC flag so we must build both object types case $host_os in - cygwin* | mingw* | pw32* | os2* | cegcc*) + cygwin* | mingw* | windows* | pw32* | os2* | cegcc*) pic_mode=default ;; esac @@ -4569,7 +4570,7 @@ func_mode_install () 'exit $?' tstripme=$stripme case $host_os in - cygwin* | mingw* | pw32* | cegcc*) + cygwin* | mingw* | windows* | pw32* | cegcc*) case $realname in *.dll.a) tstripme= @@ -4682,7 +4683,7 @@ func_mode_install () # Do a test to see if this is really a libtool program. case $host in - *cygwin* | *mingw*) + *cygwin* | *mingw* | *windows*) if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" wrapper=$func_ltwrapper_scriptname_result @@ -4910,7 +4911,7 @@ extern \"C\" { $RM $export_symbols eval "$SED -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' case $host in - *cygwin* | *mingw* | *cegcc* ) + *cygwin* | *mingw* | *windows* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' ;; @@ -4922,7 +4923,7 @@ extern \"C\" { eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' case $host in - *cygwin* | *mingw* | *cegcc* ) + *cygwin* | *mingw* | *windows* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' ;; @@ -4936,7 +4937,7 @@ extern \"C\" { func_basename "$dlprefile" name=$func_basename_result case $host in - *cygwin* | *mingw* | *cegcc* ) + *cygwin* | *mingw* | *windows* | *cegcc* ) # if an import library, we need to obtain dlname if func_win32_import_lib_p "$dlprefile"; then func_tr_sh "$dlprefile" @@ -5111,7 +5112,7 @@ static const void *lt_preloaded_setup() { # Transform the symbol file into the correct name. symfileobj=$output_objdir/${my_outputname}S.$objext case $host in - *cygwin* | *mingw* | *cegcc* ) + *cygwin* | *mingw* | *windows* | *cegcc* ) if test -f "$output_objdir/$my_outputname.def"; then compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` @@ -5454,7 +5455,7 @@ func_extract_archives () # # Emit a libtool wrapper script on stdout. # Don't directly open a file because we may want to -# incorporate the script contents within a cygwin/mingw +# incorporate the script contents within a cygwin/mingw/windows # wrapper executable. Must ONLY be called from within # func_mode_link because it depends on a number of variables # set therein. @@ -5462,7 +5463,7 @@ func_extract_archives () # ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR # variable will take. If 'yes', then the emitted script # will assume that the directory where it is stored is -# the $objdir directory. This is a cygwin/mingw-specific +# the $objdir directory. This is a cygwin/mingw/windows-specific # behavior. func_emit_wrapper () { @@ -5587,7 +5588,7 @@ func_exec_program_core () " case $host in # Backslashes separate directories on plain windows - *-*-mingw | *-*-os2* | *-cegcc*) + *-*-mingw* | *-*-windows* | *-*-os2* | *-cegcc*) $ECHO "\ if test -n \"\$lt_option_debug\"; then \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir\\\\\$program\" 1>&2 @@ -5655,7 +5656,7 @@ func_exec_program () file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\` done - # Usually 'no', except on cygwin/mingw when embedded into + # Usually 'no', except on cygwin/mingw/windows when embedded into # the cwrapper. WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1 if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then @@ -5787,7 +5788,7 @@ EOF #endif #include #include -#ifdef _MSC_VER +#if defined _WIN32 && !defined __GNUC__ # include # include # include @@ -5812,7 +5813,7 @@ EOF /* declarations of non-ANSI functions */ #if defined __MINGW32__ # ifdef __STRICT_ANSI__ -int _putenv (const char *); +_CRTIMP int __cdecl _putenv (const char *); # endif #elif defined __CYGWIN__ # ifdef __STRICT_ANSI__ @@ -6010,7 +6011,7 @@ main (int argc, char *argv[]) { EOF case $host in - *mingw* | *cygwin* ) + *mingw* | *windows* | *cygwin* ) # make stdout use "unix" line endings echo " setmode(1,_O_BINARY);" ;; @@ -6029,7 +6030,7 @@ EOF { /* however, if there is an option in the LTWRAPPER_OPTION_PREFIX namespace, but it is not one of the ones we know about and - have already dealt with, above (inluding dump-script), then + have already dealt with, above (including dump-script), then report an error. Otherwise, targets might begin to believe they are allowed to use options in the LTWRAPPER_OPTION_PREFIX namespace. The first time any user complains about this, we'll @@ -6113,7 +6114,7 @@ EOF EOF case $host_os in - mingw*) + mingw* | windows*) cat <<"EOF" { char* p; @@ -6155,7 +6156,7 @@ EOF EOF case $host_os in - mingw*) + mingw* | windows*) cat <<"EOF" /* execv doesn't actually work on mingw as expected on unix */ newargz = prepare_spawn (newargz); @@ -6574,7 +6575,7 @@ lt_update_lib_path (const char *name, const char *value) EOF case $host_os in - mingw*) + mingw* | windows*) cat <<"EOF" /* Prepares an argument vector before calling spawn(). @@ -6749,7 +6750,7 @@ func_mode_link () $debug_cmd case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + *-*-cygwin* | *-*-mingw* | *-*-windows* | *-*-pw32* | *-*-os2* | *-cegcc*) # It is impossible to link a dll without this setting, and # we shouldn't force the makefile maintainer to figure out # what system we are compiling for in order to pass an extra @@ -7255,7 +7256,7 @@ func_mode_link () ;; esac case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + *-*-cygwin* | *-*-mingw* | *-*-windows* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'` case :$dllsearchpath: in *":$dir:"*) ;; @@ -7275,7 +7276,7 @@ func_mode_link () -l*) if test X-lc = "X$arg" || test X-lm = "X$arg"; then case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) + *-*-cygwin* | *-*-mingw* | *-*-windows* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) # These systems don't actually have a C or math library (as such) continue ;; @@ -7283,7 +7284,7 @@ func_mode_link () # These systems don't actually have a C library (as such) test X-lc = "X$arg" && continue ;; - *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig* | *-*-midnightbsd*) + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-midnightbsd*) # Do not include libc due to us having libc/libc_r. test X-lc = "X$arg" && continue ;; @@ -7303,7 +7304,7 @@ func_mode_link () esac elif test X-lc_r = "X$arg"; then case $host in - *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig* | *-*-midnightbsd*) + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-midnightbsd*) # Do not include libc_r directly, use -pthread flag. continue ;; @@ -7347,7 +7348,7 @@ func_mode_link () continue ;; -mt|-mthreads|-kthread|-Kthread|-pthreads|--thread-safe \ - |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) + |-threads|-fopenmp|-fopenmp=*|-openmp|-mp|-xopenmp|-omp|-qsmp=*) func_append compiler_flags " $arg" func_append compile_command " $arg" func_append finalize_command " $arg" @@ -7370,7 +7371,7 @@ func_mode_link () -no-install) case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) + *-*-cygwin* | *-*-mingw* | *-*-windows* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) # The PATH hackery in wrapper scripts is required on Windows # and Darwin in order for the loader to find any dlls it needs. func_warning "'-no-install' is ignored for $host" @@ -7555,14 +7556,27 @@ func_mode_link () # -O*, -g*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization # -specs=* GCC specs files # -stdlib=* select c++ std lib with clang + # -fdiagnostics-color* simply affects output + # -frecord-gcc-switches used to verify flags were respected # -fsanitize=* Clang/GCC memory and address sanitizer + # -fno-sanitize* Clang/GCC memory and address sanitizer + # -shared-libsan Link with shared sanitizer runtimes (Clang) + # -static-libsan Link with static sanitizer runtimes (Clang) + # -no-canonical-prefixes Do not expand any symbolic links # -fuse-ld=* Linker select flags for GCC + # -rtlib=* select c runtime lib with clang + # --unwindlib=* select unwinder library with clang + # -f{file|debug|macro|profile}-prefix-map=* needed for lto linking # -Wa,* Pass flags directly to the assembler # -Werror, -Werror=* Report (specified) warnings as errors -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \ - -O*|-g*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*|-stdlib=*| \ - -specs=*|-fsanitize=*|-fuse-ld=*|-Wa,*|-Werror|-Werror=*) + -O*|-g*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*|-no-canonical-prefixes| \ + -stdlib=*|-rtlib=*|--unwindlib=*| \ + -specs=*|-fsanitize=*|-fno-sanitize*|-shared-libsan|-static-libsan| \ + -ffile-prefix-map=*|-fdebug-prefix-map=*|-fmacro-prefix-map=*|-fprofile-prefix-map=*| \ + -fdiagnostics-color*|-frecord-gcc-switches| \ + -fuse-ld=*|-Wa,*|-Werror|-Werror=*) func_quote_arg pretty "$arg" arg=$func_quote_arg_result func_append compile_command " $arg" @@ -7892,7 +7906,7 @@ func_mode_link () found=false case $deplib in -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ - |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) + |-threads|-fopenmp|-fopenmp=*|-openmp|-mp|-xopenmp|-omp|-qsmp=*) if test prog,link = "$linkmode,$pass"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" @@ -8069,18 +8083,15 @@ func_mode_link () ;; esac if $valid_a_lib; then - echo - $ECHO "*** Warning: Linking the shared library $output against the" - $ECHO "*** static library $deplib is not portable!" + func_warning "Linking the shared library $output against the static library $deplib is not portable!" deplibs="$deplib $deplibs" else - echo - $ECHO "*** Warning: Trying to link with static lib archive $deplib." - echo "*** I have the capability to make that library automatically link in when" - echo "*** you link to this library. But I can only do this if you have a" - echo "*** shared version of the library, which you do not appear to have" - echo "*** because the file extensions .$libext of this argument makes me believe" - echo "*** that it is just a static archive that I should not use here." + func_warning "Trying to link with static lib archive $deplib." + func_warning "I have the capability to make that library automatically link in when" + func_warning "you link to this library. But I can only do this if you have a" + func_warning "shared version of the library, which you do not appear to have" + func_warning "because the file extensions .$libext of this argument makes me believe" + func_warning "that it is just a static archive that I should not use here." fi ;; esac @@ -8275,7 +8286,7 @@ func_mode_link () fi case $host in # special handling for platforms with PE-DLLs. - *cygwin* | *mingw* | *cegcc* ) + *cygwin* | *mingw* | *windows* | *cegcc* ) # Linker will automatically link against shared library if both # static and shared are present. Therefore, ensure we extract # symbols from the import library if a shared library is present @@ -8418,8 +8429,8 @@ func_mode_link () fi if test -n "$library_names" && { test no = "$use_static_libs" || test -z "$old_library"; }; then - case $host in - *cygwin* | *mingw* | *cegcc* | *os2*) + case $host_os in + cygwin* | mingw* | windows* | cegcc* | os2*) # No point in relinking DLLs because paths are not encoded func_append notinst_deplibs " $lib" need_relink=no @@ -8445,11 +8456,11 @@ func_mode_link () if test -z "$dlopenmodule" && test yes = "$shouldnotlink" && test link = "$pass"; then echo if test prog = "$linkmode"; then - $ECHO "*** Warning: Linking the executable $output against the loadable module" + func_warning "Linking the executable $output against the loadable module" else - $ECHO "*** Warning: Linking the shared library $output against the loadable module" + func_warning "Linking the shared library $output against the loadable module" fi - $ECHO "*** $linklib is not portable!" + func_warning "$linklib is not portable!" fi if test lib = "$linkmode" && test yes = "$hardcode_into_libs"; then @@ -8488,8 +8499,8 @@ func_mode_link () soname=$dlname elif test -n "$soname_spec"; then # bleh windows - case $host in - *cygwin* | mingw* | *cegcc* | *os2*) + case $host_os in + cygwin* | mingw* | windows* | cegcc* | os2*) func_arith $current - $age major=$func_arith_result versuffix=-$major @@ -8544,11 +8555,10 @@ func_mode_link () if /usr/bin/file -L $add 2> /dev/null | $GREP ": [^:]* bundle" >/dev/null; then if test "X$dlopenmodule" != "X$lib"; then - $ECHO "*** Warning: lib $linklib is a module, not a shared library" + func_warning "lib $linklib is a module, not a shared library" if test -z "$old_library"; then - echo - echo "*** And there doesn't seem to be a static archive available" - echo "*** The link will probably fail, sorry" + func_warning "And there doesn't seem to be a static archive available" + func_warning "The link will probably fail, sorry" else add=$dir/$old_library fi @@ -8688,21 +8698,19 @@ func_mode_link () # Just print a warning and add the library to dependency_libs so # that the program can be linked against the static library. - echo - $ECHO "*** Warning: This system cannot link to static lib archive $lib." - echo "*** I have the capability to make that library automatically link in when" - echo "*** you link to this library. But I can only do this if you have a" - echo "*** shared version of the library, which you do not appear to have." + func_warning "This system cannot link to static lib archive $lib." + func_warning "I have the capability to make that library automatically link in when" + func_warning "you link to this library. But I can only do this if you have a" + func_warning "shared version of the library, which you do not appear to have." if test yes = "$module"; then - echo "*** But as you try to build a module library, libtool will still create " - echo "*** a static module, that should work as long as the dlopening application" - echo "*** is linked with the -dlopen flag to resolve symbols at runtime." + func_warning "But as you try to build a module library, libtool will still create " + func_warning "a static module, that should work as long as the dlopening application" + func_warning "is linked with the -dlopen flag to resolve symbols at runtime." if test -z "$global_symbol_pipe"; then - echo - echo "*** However, this would only work if libtool was able to extract symbol" - echo "*** lists from a program, using 'nm' or equivalent, but libtool could" - echo "*** not find such a program. So, this module is probably useless." - echo "*** 'nm' from GNU binutils and a full rebuild may help." + func_warning "However, this would only work if libtool was able to extract symbol" + func_warning "lists from a program, using 'nm' or equivalent, but libtool could" + func_warning "not find such a program. So, this module is probably useless." + func_warning "'nm' from GNU binutils and a full rebuild may help." fi if test no = "$build_old_libs"; then build_libtool_libs=module @@ -9029,9 +9037,7 @@ func_mode_link () if test pass_all != "$deplibs_check_method"; then func_fatal_error "cannot build libtool library '$output' from non-libtool objects on this host:$objs" else - echo - $ECHO "*** Warning: Linking the shared library $output against the non-libtool" - $ECHO "*** objects $objs is not portable!" + func_warning "Linking the shared library $output against the non-libtool objects $objs is not portable!" func_append libobjs " $objs" fi fi @@ -9092,13 +9098,13 @@ func_mode_link () # case $version_type in # correct linux to gnu/linux during the next big refactor - darwin|freebsd-elf|linux|midnightbsd-elf|osf|windows|none) + darwin|freebsd-elf|linux|midnightbsd-elf|osf|qnx|windows|none) func_arith $number_major + $number_minor current=$func_arith_result age=$number_minor revision=$number_revision ;; - freebsd-aout|qnx|sunos) + freebsd-aout|sco|sunos) current=$number_major revision=$number_minor age=0 @@ -9245,8 +9251,9 @@ func_mode_link () ;; qnx) - major=.$current - versuffix=.$current + func_arith $current - $age + major=.$func_arith_result + versuffix=$major.$age.$revision ;; sco) @@ -9399,7 +9406,7 @@ func_mode_link () if test yes = "$build_libtool_libs"; then if test -n "$rpath"; then case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*) + *-*-cygwin* | *-*-mingw* | *-*-windows* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*) # these systems don't actually have a c library (as such)! ;; *-*-rhapsody* | *-*-darwin1.[012]) @@ -9450,108 +9457,6 @@ func_mode_link () # implementing what was already the behavior. newdeplibs=$deplibs ;; - test_compile) - # This code stresses the "libraries are programs" paradigm to its - # limits. Maybe even breaks it. We compile a program, linking it - # against the deplibs as a proxy for the library. Then we can check - # whether they linked in statically or dynamically with ldd. - $opt_dry_run || $RM conftest.c - cat > conftest.c <. ]) -# serial 59 LT_INIT +# serial 61 LT_INIT # LT_PREREQ(VERSION) @@ -616,7 +616,7 @@ m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT # LT_OUTPUT # --------- # This macro allows early generation of the libtool script (before -# AC_OUTPUT is called), incase it is used in configure for compilation +# AC_OUTPUT is called), in case it is used in configure for compilation # tests. AC_DEFUN([LT_OUTPUT], [: ${CONFIG_LT=./config.lt} @@ -651,9 +651,9 @@ m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) configured by $[0], generated by m4_PACKAGE_STRING. -Copyright (C) 2011 Free Software Foundation, Inc. +Copyright (C) 2024 Free Software Foundation, Inc. This config.lt script is free software; the Free Software Foundation -gives unlimited permision to copy, distribute and modify it." +gives unlimited permission to copy, distribute and modify it." while test 0 != $[#] do @@ -1255,7 +1255,9 @@ lt_sysroot= case $with_sysroot in #( yes) if test yes = "$GCC"; then - lt_sysroot=`$CC --print-sysroot 2>/dev/null` + # Trim trailing / since we'll always append absolute paths and we want + # to avoid //, if only for less confusing output for the user. + lt_sysroot=`$CC --print-sysroot 2>/dev/null | $SED 's:/\+$::'` fi ;; #( /*) @@ -1367,7 +1369,7 @@ mips64*-*linux*) ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ -s390*-*linux*|s390*-*tpf*|sparc*-*linux*) +s390*-*linux*|s390*-*tpf*|sparc*-*linux*|x86_64-gnu*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. Note that the listed cases only cover the # situations where additional linker options are needed (such as when @@ -1382,7 +1384,7 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; - x86_64-*linux*) + x86_64-*linux*|x86_64-gnu*) case `$FILECMD conftest.o` in *x86-64*) LD="${LD-ld} -m elf32_x86_64" @@ -1411,7 +1413,7 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; - x86_64-*linux*) + x86_64-*linux*|x86_64-gnu*) LD="${LD-ld} -m elf_x86_64" ;; powerpcle-*linux*) @@ -1494,7 +1496,7 @@ _LT_DECL([], [AR], [1], [The archiver]) # Use ARFLAGS variable as AR's operation code to sync the variable naming with # Automake. If both AR_FLAGS and ARFLAGS are specified, AR_FLAGS should have -# higher priority because thats what people were doing historically (setting +# higher priority because that's what people were doing historically (setting # ARFLAGS for automake and AR_FLAGS for libtool). FIXME: Make the AR_FLAGS # variable obsoleted/removed. @@ -1555,15 +1557,8 @@ old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then - case $host_os in - bitrig* | openbsd*) - old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" - ;; - *) - old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" - ;; - esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" fi case $host_os in @@ -1702,7 +1697,7 @@ AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl lt_cv_sys_max_cmd_len=-1; ;; - cygwin* | mingw* | cegcc*) + cygwin* | mingw* | windows* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, @@ -1724,7 +1719,7 @@ AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl lt_cv_sys_max_cmd_len=8192; ;; - bitrig* | darwin* | dragonfly* | freebsd* | midnightbsd* | netbsd* | openbsd*) + darwin* | dragonfly* | freebsd* | midnightbsd* | netbsd* | openbsd*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` @@ -1945,7 +1940,7 @@ else lt_cv_dlopen_self=yes ;; - mingw* | pw32* | cegcc*) + mingw* | windows* | pw32* | cegcc*) lt_cv_dlopen=LoadLibrary lt_cv_dlopen_libs= ;; @@ -2313,7 +2308,7 @@ if test yes = "$GCC"; then *) lt_awk_arg='/^libraries:/' ;; esac case $host_os in - mingw* | cegcc*) lt_sed_strip_eq='s|=\([[A-Za-z]]:\)|\1|g' ;; + mingw* | windows* | cegcc*) lt_sed_strip_eq='s|=\([[A-Za-z]]:\)|\1|g' ;; *) lt_sed_strip_eq='s|=/|/|g' ;; esac lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` @@ -2371,7 +2366,7 @@ BEGIN {RS = " "; FS = "/|\n";} { # AWK program above erroneously prepends '/' to C:/dos/paths # for these hosts. case $host_os in - mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ + mingw* | windows* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ $SED 's|/\([[A-Za-z]]:\)|\1|g'` ;; esac sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` @@ -2540,7 +2535,7 @@ bsdi[[45]]*) # libtool to hard-code these into programs ;; -cygwin* | mingw* | pw32* | cegcc*) +cygwin* | mingw* | windows* | pw32* | cegcc*) version_type=windows shrext_cmds=.dll need_version=no @@ -2572,7 +2567,7 @@ cygwin* | mingw* | pw32* | cegcc*) m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"]) ;; - mingw* | cegcc*) + mingw* | windows* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' ;; @@ -2591,7 +2586,7 @@ m4_if([$1], [],[ library_names_spec='$libname.dll.lib' case $build_os in - mingw*) + mingw* | windows*) sys_lib_search_path_spec= lt_save_ifs=$IFS IFS=';' @@ -2839,7 +2834,7 @@ linux*android*) version_type=none # Android doesn't support versioned libraries. need_lib_prefix=no need_version=no - library_names_spec='$libname$release$shared_ext' + library_names_spec='$libname$release$shared_ext $libname$shared_ext' soname_spec='$libname$release$shared_ext' finish_cmds= shlibpath_var=LD_LIBRARY_PATH @@ -2851,8 +2846,9 @@ linux*android*) hardcode_into_libs=yes dynamic_linker='Android linker' - # Don't embed -rpath directories since the linker doesn't support them. - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + # -rpath works at least for libraries that are not overridden by + # libraries installed in system locations. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' ;; # This must be glibc/ELF. @@ -2886,7 +2882,7 @@ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) # before this can be enabled. hardcode_into_libs=yes - # Ideally, we could use ldconfig to report *all* directores which are + # Ideally, we could use ldconfig to report *all* directories which are # searched for libraries, however this is still not possible. Aside from not # being certain /sbin/ldconfig is available, command # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64, @@ -2943,7 +2939,7 @@ newsos6) dynamic_linker='ldqnx.so' ;; -openbsd* | bitrig*) +openbsd*) version_type=sunos sys_lib_dlsearch_path_spec=/usr/lib need_lib_prefix=no @@ -3275,7 +3271,7 @@ if test yes = "$GCC"; then # Check if gcc -print-prog-name=ld gives a path. AC_MSG_CHECKING([for ld used by $CC]) case $host in - *-*-mingw*) + *-*-mingw* | *-*-windows*) # gcc leaves a trailing carriage return, which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) @@ -3384,7 +3380,7 @@ case $reload_flag in esac reload_cmds='$LD$reload_flag -o $output$reload_objs' case $host_os in - cygwin* | mingw* | pw32* | cegcc*) + cygwin* | mingw* | windows* | pw32* | cegcc*) if test yes != "$GCC"; then reload_cmds=false fi @@ -3456,7 +3452,6 @@ lt_cv_deplibs_check_method='unknown' # 'none' -- dependencies not supported. # 'unknown' -- same as none, but documents that we really don't know. # 'pass_all' -- all dependencies passed with no checks. -# 'test_compile' -- check by making test program. # 'file_magic [[regex]]' -- check by looking for files in library path # that responds to the $file_magic_cmd with a given extended regex. # If you have 'file' or equivalent on your system and you're not sure @@ -3483,7 +3478,7 @@ cygwin*) lt_cv_file_magic_cmd='func_win32_libid' ;; -mingw* | pw32*) +mingw* | windows* | pw32*) # Base MSYS/MinGW do not provide the 'file' command needed by # func_win32_libid shell function, so use a weaker test based on 'objdump', # unless we find 'file', for example because we are cross-compiling. @@ -3583,7 +3578,7 @@ newos6*) lt_cv_deplibs_check_method=pass_all ;; -openbsd* | bitrig*) +openbsd*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' else @@ -3647,7 +3642,7 @@ file_magic_glob= want_nocaseglob=no if test "$build" = "$host"; then case $host_os in - mingw* | pw32*) + mingw* | windows* | pw32*) if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then want_nocaseglob=yes else @@ -3699,7 +3694,7 @@ else # Tru64's nm complains that /dev/null is an invalid object file # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty case $build_os in - mingw*) lt_bad_file=conftest.nm/nofile ;; + mingw* | windows*) lt_bad_file=conftest.nm/nofile ;; *) lt_bad_file=/dev/null ;; esac case `"$tmp_nm" -B $lt_bad_file 2>&1 | $SED '1q'` in @@ -3790,7 +3785,7 @@ lt_cv_sharedlib_from_linklib_cmd, [lt_cv_sharedlib_from_linklib_cmd='unknown' case $host_os in -cygwin* | mingw* | pw32* | cegcc*) +cygwin* | mingw* | windows* | pw32* | cegcc*) # two different shell functions defined in ltmain.sh; # decide which one to use based on capabilities of $DLLTOOL case `$DLLTOOL --help 2>&1` in @@ -3822,16 +3817,16 @@ _LT_DECL([], [sharedlib_from_linklib_cmd], [1], m4_defun([_LT_PATH_MANIFEST_TOOL], [AC_CHECK_TOOL(MANIFEST_TOOL, mt, :) test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt -AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool], - [lt_cv_path_mainfest_tool=no +AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_manifest_tool], + [lt_cv_path_manifest_tool=no echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out cat conftest.err >&AS_MESSAGE_LOG_FD if $GREP 'Manifest Tool' conftest.out > /dev/null; then - lt_cv_path_mainfest_tool=yes + lt_cv_path_manifest_tool=yes fi rm -f conftest*]) -if test yes != "$lt_cv_path_mainfest_tool"; then +if test yes != "$lt_cv_path_manifest_tool"; then MANIFEST_TOOL=: fi _LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl @@ -3860,7 +3855,7 @@ AC_DEFUN([LT_LIB_M], [AC_REQUIRE([AC_CANONICAL_HOST])dnl LIBM= case $host in -*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*) +*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-mingw* | *-*-pw32* | *-*-darwin*) # These system don't have libm, or don't need it ;; *-ncr-sysv4.3*) @@ -3935,7 +3930,7 @@ case $host_os in aix*) symcode='[[BCDT]]' ;; -cygwin* | mingw* | pw32* | cegcc*) +cygwin* | mingw* | windows* | pw32* | cegcc*) symcode='[[ABCDGISTW]]' ;; hpux*) @@ -3950,7 +3945,7 @@ osf*) symcode='[[BCDEGQRST]]' ;; solaris*) - symcode='[[BDRT]]' + symcode='[[BCDRT]]' ;; sco3.2v5*) symcode='[[DT]]' @@ -4014,7 +4009,7 @@ $lt_c_name_lib_hook\ # Handle CRLF in mingw tool chain opt_cr= case $build_os in -mingw*) +mingw* | windows*) opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac @@ -4241,7 +4236,7 @@ m4_if([$1], [CXX], [ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; - mingw* | cygwin* | os2* | pw32* | cegcc*) + mingw* | windows* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style @@ -4317,7 +4312,7 @@ m4_if([$1], [CXX], [ ;; esac ;; - mingw* | cygwin* | os2* | pw32* | cegcc*) + mingw* | windows* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], @@ -4565,7 +4560,7 @@ m4_if([$1], [CXX], [ # PIC is the default for these OSes. ;; - mingw* | cygwin* | pw32* | os2* | cegcc*) + mingw* | windows* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style @@ -4669,7 +4664,7 @@ m4_if([$1], [CXX], [ esac ;; - mingw* | cygwin* | pw32* | os2* | cegcc*) + mingw* | windows* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], @@ -4711,6 +4706,12 @@ m4_if([$1], [CXX], [ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; + *flang) + # Flang compiler. + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; # icc used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. icc* | ifort*) @@ -4944,7 +4945,7 @@ m4_if([$1], [CXX], [ pw32*) _LT_TAGVAR(export_symbols_cmds, $1)=$ltdll_cmds ;; - cygwin* | mingw* | cegcc*) + cygwin* | mingw* | windows* | cegcc*) case $cc_basename in cl* | icl*) _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' @@ -5002,7 +5003,7 @@ dnl Note also adjust exclude_expsyms for C++ above. extract_expsyms_cmds= case $host_os in - cygwin* | mingw* | pw32* | cegcc*) + cygwin* | mingw* | windows* | pw32* | cegcc*) # FIXME: the MSVC++ and ICC port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++ or Intel C++ Compiler. @@ -5014,7 +5015,7 @@ dnl Note also adjust exclude_expsyms for C++ above. # we just hope/assume this is gcc and not c89 (= MSVC++ or ICC) with_gnu_ld=yes ;; - openbsd* | bitrig*) + openbsd*) with_gnu_ld=no ;; esac @@ -5117,7 +5118,7 @@ _LT_EOF fi ;; - cygwin* | mingw* | pw32* | cegcc*) + cygwin* | mingw* | windows* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' @@ -5173,7 +5174,7 @@ _LT_EOF cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' - _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' + _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' ;; @@ -5574,7 +5575,7 @@ _LT_EOF _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic ;; - cygwin* | mingw* | pw32* | cegcc*) + cygwin* | mingw* | windows* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++ or Intel C++ Compiler. # hardcode_libdir_flag_spec is actually meaningless, as there is @@ -5591,14 +5592,14 @@ _LT_EOF # Tell ltmain to make .dll files, not .so files. shrext_cmds=.dll # FIXME: Setting linknames here is a bad hack. - _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' + _LT_TAGVAR(archive_cmds, $1)='$CC -Fe $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then cp "$export_symbols" "$output_objdir/$soname.def"; echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; else $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; fi~ - $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + $CC -Fe $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' @@ -5836,7 +5837,7 @@ _LT_EOF *nto* | *qnx*) ;; - openbsd* | bitrig*) + openbsd*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no @@ -5879,7 +5880,7 @@ _LT_EOF cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' - _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' + _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' ;; @@ -6173,7 +6174,7 @@ _LT_TAGDECL([], [hardcode_direct], [0], _LT_TAGDECL([], [hardcode_direct_absolute], [0], [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes DIR into the resulting binary and the resulting library dependency is - "absolute", i.e impossible to change by setting $shlibpath_var if the + "absolute", i.e. impossible to change by setting $shlibpath_var if the library is relocated]) _LT_TAGDECL([], [hardcode_minus_L], [0], [Set to "yes" if using the -LDIR flag during linking hardcodes DIR @@ -6420,8 +6421,7 @@ if test yes != "$_lt_caught_CXX_error"; then wlarc='$wl' # ancient GNU ld didn't support --whole-archive et. al. - if eval "`$CC -print-prog-name=ld` --help 2>&1" | - $GREP 'no-whole-archive' > /dev/null; then + if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= @@ -6441,7 +6441,7 @@ if test yes != "$_lt_caught_CXX_error"; then # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. - output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "[[-]]L"' else GXX=no @@ -6650,7 +6650,7 @@ if test yes != "$_lt_caught_CXX_error"; then esac ;; - cygwin* | mingw* | pw32* | cegcc*) + cygwin* | mingw* | windows* | pw32* | cegcc*) case $GXX,$cc_basename in ,cl* | no,cl* | ,icl* | no,icl*) # Native MSVC or ICC @@ -6749,7 +6749,7 @@ if test yes != "$_lt_caught_CXX_error"; then cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' - _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' + _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' ;; @@ -6817,7 +6817,7 @@ if test yes != "$_lt_caught_CXX_error"; then # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. - output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "[[-]]L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test yes = "$GXX"; then @@ -6882,7 +6882,7 @@ if test yes != "$_lt_caught_CXX_error"; then # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. - output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "[[-]]L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test yes = "$GXX"; then @@ -7130,7 +7130,7 @@ if test yes != "$_lt_caught_CXX_error"; then _LT_TAGVAR(ld_shlibs, $1)=yes ;; - openbsd* | bitrig*) + openbsd*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no @@ -7221,7 +7221,7 @@ if test yes != "$_lt_caught_CXX_error"; then # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. - output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "[[-]]L"' else # FIXME: insert proper C++ library support @@ -7305,7 +7305,7 @@ if test yes != "$_lt_caught_CXX_error"; then # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. - output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "[[-]]L"' else # g++ 2.7 appears to require '-G' NOT '-shared' on this # platform. @@ -7316,7 +7316,7 @@ if test yes != "$_lt_caught_CXX_error"; then # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. - output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "[[-]]L"' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $wl$libdir' @@ -7554,10 +7554,11 @@ if AC_TRY_EVAL(ac_compile); then case $prev$p in -L* | -R* | -l*) - # Some compilers place space between "-{L,R}" and the path. + # Some compilers place space between "-{L,R,l}" and the path. # Remove the space. - if test x-L = "$p" || - test x-R = "$p"; then + if test x-L = x"$p" || + test x-R = x"$p" || + test x-l = x"$p"; then prev=$p continue fi @@ -8215,7 +8216,7 @@ AC_SUBST([DLLTOOL]) # ---------------- # Check for a file(cmd) program that can be used to detect file type and magic m4_defun([_LT_DECL_FILECMD], -[AC_CHECK_TOOL([FILECMD], [file], [:]) +[AC_CHECK_PROG([FILECMD], [file], [:]) _LT_DECL([], [FILECMD], [1], [A file(cmd) program that detects file types]) ])# _LD_DECL_FILECMD @@ -8231,73 +8232,6 @@ _LT_DECL([], [SED], [1], [A sed program that does not truncate output]) _LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], [Sed that helps us avoid accidentally triggering echo(1) options like -n]) ])# _LT_DECL_SED - -m4_ifndef([AC_PROG_SED], [ -############################################################ -# NOTE: This macro has been submitted for inclusion into # -# GNU Autoconf as AC_PROG_SED. When it is available in # -# a released version of Autoconf we should remove this # -# macro and use it instead. # -############################################################ - -m4_defun([AC_PROG_SED], -[AC_MSG_CHECKING([for a sed that does not truncate output]) -AC_CACHE_VAL(lt_cv_path_SED, -[# Loop through the user's path and test for sed and gsed. -# Then use that list of sed's as ones to test for truncation. -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for lt_ac_prog in sed gsed; do - for ac_exec_ext in '' $ac_executable_extensions; do - if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then - lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" - fi - done - done -done -IFS=$as_save_IFS -lt_ac_max=0 -lt_ac_count=0 -# Add /usr/xpg4/bin/sed as it is typically found on Solaris -# along with /bin/sed that truncates output. -for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do - test ! -f "$lt_ac_sed" && continue - cat /dev/null > conftest.in - lt_ac_count=0 - echo $ECHO_N "0123456789$ECHO_C" >conftest.in - # Check for GNU sed and select it if it is found. - if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then - lt_cv_path_SED=$lt_ac_sed - break - fi - while true; do - cat conftest.in conftest.in >conftest.tmp - mv conftest.tmp conftest.in - cp conftest.in conftest.nl - echo >>conftest.nl - $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break - cmp -s conftest.out conftest.nl || break - # 10000 chars as input seems more than enough - test 10 -lt "$lt_ac_count" && break - lt_ac_count=`expr $lt_ac_count + 1` - if test "$lt_ac_count" -gt "$lt_ac_max"; then - lt_ac_max=$lt_ac_count - lt_cv_path_SED=$lt_ac_sed - fi - done -done -]) -SED=$lt_cv_path_SED -AC_SUBST([SED]) -AC_MSG_RESULT([$SED]) -])#AC_PROG_SED -])#m4_ifndef - -# Old name: -AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_SED], []) @@ -8344,7 +8278,7 @@ AC_CACHE_VAL(lt_cv_to_host_file_cmd, [case $host in *-*-mingw* ) case $build in - *-*-mingw* ) # actually msys + *-*-mingw* | *-*-windows* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 ;; *-*-cygwin* ) @@ -8357,7 +8291,7 @@ AC_CACHE_VAL(lt_cv_to_host_file_cmd, ;; *-*-cygwin* ) case $build in - *-*-mingw* ) # actually msys + *-*-mingw* | *-*-windows* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin ;; *-*-cygwin* ) @@ -8383,9 +8317,9 @@ AC_CACHE_VAL(lt_cv_to_tool_file_cmd, [#assume ordinary cross tools, or native build. lt_cv_to_tool_file_cmd=func_convert_file_noop case $host in - *-*-mingw* ) + *-*-mingw* | *-*-windows* ) case $build in - *-*-mingw* ) # actually msys + *-*-mingw* | *-*-windows* ) # actually msys lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 ;; esac diff --git a/m4/ltoptions.m4 b/m4/ltoptions.m4 index b0b5e9c..6dfe99f 100644 --- a/m4/ltoptions.m4 +++ b/m4/ltoptions.m4 @@ -1,6 +1,6 @@ # Helper functions for option handling. -*- Autoconf -*- # -# Copyright (C) 2004-2005, 2007-2009, 2011-2019, 2021-2022 Free +# Copyright (C) 2004-2005, 2007-2009, 2011-2019, 2021-2024 Free # Software Foundation, Inc. # Written by Gary V. Vaughan, 2004 # @@ -8,7 +8,7 @@ # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. -# serial 8 ltoptions.m4 +# serial 9 ltoptions.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) @@ -128,7 +128,7 @@ LT_OPTION_DEFINE([LT_INIT], [win32-dll], [enable_win32_dll=yes case $host in -*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) +*-*-cygwin* | *-*-mingw* | *-*-windows* | *-*-pw32* | *-*-cegcc*) AC_CHECK_TOOL(AS, as, false) AC_CHECK_TOOL(DLLTOOL, dlltool, false) AC_CHECK_TOOL(OBJDUMP, objdump, false) diff --git a/m4/ltsugar.m4 b/m4/ltsugar.m4 index 902508b..5b5c80a 100644 --- a/m4/ltsugar.m4 +++ b/m4/ltsugar.m4 @@ -1,6 +1,6 @@ # ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- # -# Copyright (C) 2004-2005, 2007-2008, 2011-2019, 2021-2022 Free Software +# Copyright (C) 2004-2005, 2007-2008, 2011-2019, 2021-2024 Free Software # Foundation, Inc. # Written by Gary V. Vaughan, 2004 # diff --git a/m4/ltversion.m4 b/m4/ltversion.m4 index 0026c21..82887f7 100644 --- a/m4/ltversion.m4 +++ b/m4/ltversion.m4 @@ -1,6 +1,6 @@ # ltversion.m4 -- version numbers -*- Autoconf -*- # -# Copyright (C) 2004, 2011-2019, 2021-2022 Free Software Foundation, +# Copyright (C) 2004, 2011-2019, 2021-2024 Free Software Foundation, # Inc. # Written by Scott James Remnant, 2004 # @@ -10,15 +10,15 @@ # @configure_input@ -# serial 4249 ltversion.m4 +# serial 4337 ltversion.m4 # This file is part of GNU Libtool -m4_define([LT_PACKAGE_VERSION], [2.4.7.4-1ec8f-dirty]) -m4_define([LT_PACKAGE_REVISION], [2.4.7.4]) +m4_define([LT_PACKAGE_VERSION], [2.5.0.1-38c1-dirty]) +m4_define([LT_PACKAGE_REVISION], [2.5.0.1]) AC_DEFUN([LTVERSION_VERSION], -[macro_version='2.4.7.4-1ec8f-dirty' -macro_revision='2.4.7.4' +[macro_version='2.5.0.1-38c1-dirty' +macro_revision='2.5.0.1' _LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) _LT_DECL(, macro_revision, 0) ]) diff --git a/m4/lt~obsolete.m4 b/m4/lt~obsolete.m4 index 0f7a875..22b5346 100644 --- a/m4/lt~obsolete.m4 +++ b/m4/lt~obsolete.m4 @@ -1,6 +1,6 @@ # lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- # -# Copyright (C) 2004-2005, 2007, 2009, 2011-2019, 2021-2022 Free +# Copyright (C) 2004-2005, 2007, 2009, 2011-2019, 2021-2024 Free # Software Foundation, Inc. # Written by Scott James Remnant, 2004. # diff --git a/m4/pcre2_visibility.m4 b/m4/pcre2_visibility.m4 index ae00de0..c025d5f 100644 --- a/m4/pcre2_visibility.m4 +++ b/m4/pcre2_visibility.m4 @@ -77,6 +77,8 @@ AC_DEFUN([PCRE2_VISIBILITY], else AC_DEFINE(PCRE2_EXPORT, [], [to make a symbol visible]) fi + else + AC_DEFINE(PCRE2_EXPORT, [], [to make a symbol visible]) fi AC_SUBST([VISIBILITY_CFLAGS]) AC_SUBST([VISIBILITY_CXXFLAGS]) diff --git a/src/config.h.generic b/src/config.h.generic index e8779b5..0092948 100644 --- a/src/config.h.generic +++ b/src/config.h.generic @@ -215,7 +215,7 @@ sure both macros are undefined; an emulation function will then be used. */ Care must be taken if it is increased, because it guards against integer overflow caused by enormously large patterns. */ #ifndef MAX_NAME_SIZE -#define MAX_NAME_SIZE 32 +#define MAX_NAME_SIZE 128 #endif /* The value of MAX_VARLOOKBEHIND specifies the default maximum length, in @@ -245,7 +245,7 @@ sure both macros are undefined; an emulation function will then be used. */ #define PACKAGE_NAME "PCRE2" /* Define to the full name and version of this package. */ -#define PACKAGE_STRING "PCRE2 10.43" +#define PACKAGE_STRING "PCRE2 10.44" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "pcre2" @@ -254,7 +254,7 @@ sure both macros are undefined; an emulation function will then be used. */ #define PACKAGE_URL "" /* Define to the version of this package. */ -#define PACKAGE_VERSION "10.43" +#define PACKAGE_VERSION "10.44" /* 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 @@ -458,7 +458,7 @@ sure both macros are undefined; an emulation function will then be used. */ #endif /* Version number of package */ -#define VERSION "10.43" +#define VERSION "10.44" /* Number of bits in a file offset, on hosts where this is settable. */ /* #undef _FILE_OFFSET_BITS */ diff --git a/src/pcre2.h.generic b/src/pcre2.h.generic index d7a8ff5..a322d9f 100644 --- a/src/pcre2.h.generic +++ b/src/pcre2.h.generic @@ -42,9 +42,9 @@ POSSIBILITY OF SUCH DAMAGE. /* The current PCRE version information. */ #define PCRE2_MAJOR 10 -#define PCRE2_MINOR 43 +#define PCRE2_MINOR 44 #define PCRE2_PRERELEASE -#define PCRE2_DATE 2024-02-16 +#define PCRE2_DATE 2024-06-07 /* When an application links to a PCRE DLL in Windows, the symbols that are imported have to be identified as such. When building PCRE2, the appropriate @@ -603,6 +603,8 @@ PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ pcre2_set_compile_extra_options(pcre2_compile_context *, uint32_t); \ PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ pcre2_set_max_pattern_length(pcre2_compile_context *, PCRE2_SIZE); \ +PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ + pcre2_set_max_pattern_compiled_length(pcre2_compile_context *, PCRE2_SIZE); \ PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ pcre2_set_max_varlookbehind(pcre2_compile_context *, uint32_t); \ PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ @@ -901,6 +903,7 @@ pcre2_compile are called by application code. */ #define pcre2_set_match_limit PCRE2_SUFFIX(pcre2_set_match_limit_) #define pcre2_set_max_varlookbehind PCRE2_SUFFIX(pcre2_set_max_varlookbehind_) #define pcre2_set_max_pattern_length PCRE2_SUFFIX(pcre2_set_max_pattern_length_) +#define pcre2_set_max_pattern_compiled_length PCRE2_SUFFIX(pcre2_set_max_pattern_compiled_length_) #define pcre2_set_newline PCRE2_SUFFIX(pcre2_set_newline_) #define pcre2_set_parens_nest_limit PCRE2_SUFFIX(pcre2_set_parens_nest_limit_) #define pcre2_set_offset_limit PCRE2_SUFFIX(pcre2_set_offset_limit_) diff --git a/src/pcre2.h.in b/src/pcre2.h.in index 1e7e5eb..b43534b 100644 --- a/src/pcre2.h.in +++ b/src/pcre2.h.in @@ -603,6 +603,8 @@ PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ pcre2_set_compile_extra_options(pcre2_compile_context *, uint32_t); \ PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ pcre2_set_max_pattern_length(pcre2_compile_context *, PCRE2_SIZE); \ +PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ + pcre2_set_max_pattern_compiled_length(pcre2_compile_context *, PCRE2_SIZE); \ PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ pcre2_set_max_varlookbehind(pcre2_compile_context *, uint32_t); \ PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ @@ -901,6 +903,7 @@ pcre2_compile are called by application code. */ #define pcre2_set_match_limit PCRE2_SUFFIX(pcre2_set_match_limit_) #define pcre2_set_max_varlookbehind PCRE2_SUFFIX(pcre2_set_max_varlookbehind_) #define pcre2_set_max_pattern_length PCRE2_SUFFIX(pcre2_set_max_pattern_length_) +#define pcre2_set_max_pattern_compiled_length PCRE2_SUFFIX(pcre2_set_max_pattern_compiled_length_) #define pcre2_set_newline PCRE2_SUFFIX(pcre2_set_newline_) #define pcre2_set_parens_nest_limit PCRE2_SUFFIX(pcre2_set_parens_nest_limit_) #define pcre2_set_offset_limit PCRE2_SUFFIX(pcre2_set_offset_limit_) diff --git a/src/pcre2_compile.c b/src/pcre2_compile.c index 8b36497..8e6787a 100644 --- a/src/pcre2_compile.c +++ b/src/pcre2_compile.c @@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Original API code Copyright (c) 1997-2012 University of Cambridge - New API code Copyright (c) 2016-2023 University of Cambridge + New API code Copyright (c) 2016-2024 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -808,7 +808,8 @@ enum { ERR0 = COMPILE_ERROR_BASE, ERR61, ERR62, ERR63, ERR64, ERR65, ERR66, ERR67, ERR68, ERR69, ERR70, ERR71, ERR72, ERR73, ERR74, ERR75, ERR76, ERR77, ERR78, ERR79, ERR80, ERR81, ERR82, ERR83, ERR84, ERR85, ERR86, ERR87, ERR88, ERR89, ERR90, - ERR91, ERR92, ERR93, ERR94, ERR95, ERR96, ERR97, ERR98, ERR99, ERR100 }; + ERR91, ERR92, ERR93, ERR94, ERR95, ERR96, ERR97, ERR98, ERR99, ERR100, + ERR101 }; /* This is a table of start-of-pattern options such as (*UTF) and settings such as (*LIMIT_MATCH=nnnn) and (*CRLF). For completeness and backward @@ -7549,7 +7550,8 @@ for (;; pptr++) if (lengthptr != NULL) { PCRE2_SIZE delta; - if (PRIV(ckd_smul)(&delta, repeat_min - 1, length_prevgroup) || + if (PRIV(ckd_smul)(&delta, repeat_min - 1, + (int)length_prevgroup) || OFLOW_MAX - *lengthptr < delta) { *errorcodeptr = ERR20; @@ -7599,7 +7601,7 @@ for (;; pptr++) { PCRE2_SIZE delta; if (PRIV(ckd_smul)(&delta, repeat_max, - length_prevgroup + 1 + 2 + 2*LINK_SIZE) || + (int)length_prevgroup + 1 + 2 + 2*LINK_SIZE) || OFLOW_MAX + (2 + 2*LINK_SIZE) - *lengthptr < delta) { *errorcodeptr = ERR20; @@ -9908,7 +9910,7 @@ do *bptr |= branchlength; /* branchlength never more than 65535 */ bptr = *pptrptr; } -while (*bptr == META_ALT); +while (META_CODE(*bptr) == META_ALT); /* If any branch is of variable length, the whole lookbehind is of variable length. If the maximum length of any branch exceeds the maximum for variable @@ -10601,14 +10603,21 @@ if (length > MAX_PATTERN_SIZE) goto HAD_CB_ERROR; } -/* Compute the size of, and then get and initialize, the data block for storing -the compiled pattern and names table. Integer overflow should no longer be -possible because nowadays we limit the maximum value of cb.names_found and -cb.name_entry_size. */ +/* Compute the size of, then, if not too large, get and initialize the data +block for storing the compiled pattern and names table. Integer overflow should +no longer be possible because nowadays we limit the maximum value of +cb.names_found and cb.name_entry_size. */ re_blocksize = sizeof(pcre2_real_code) + CU2BYTES(length + (PCRE2_SIZE)cb.names_found * (PCRE2_SIZE)cb.name_entry_size); + +if (re_blocksize > ccontext->max_pattern_compiled_length) + { + errorcode = ERR101; + goto HAD_CB_ERROR; + } + re = (pcre2_real_code *) ccontext->memctl.malloc(re_blocksize, ccontext->memctl.memory_data); if (re == NULL) diff --git a/src/pcre2_context.c b/src/pcre2_context.c index 0bc2ea0..9edbd1b 100644 --- a/src/pcre2_context.c +++ b/src/pcre2_context.c @@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Original API code Copyright (c) 1997-2012 University of Cambridge - New API code Copyright (c) 2016-2023 University of Cambridge + New API code Copyright (c) 2016-2024 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -136,6 +136,7 @@ const pcre2_compile_context PRIV(default_compile_context) = { NULL, /* Stack guard data */ PRIV(default_tables), /* Character tables */ PCRE2_UNSET, /* Max pattern length */ + PCRE2_UNSET, /* Max pattern compiled length */ BSR_DEFAULT, /* Backslash R default */ NEWLINE_DEFAULT, /* Newline convention */ PARENS_NEST_LIMIT, /* As it says */ @@ -352,6 +353,13 @@ ccontext->max_pattern_length = length; return 0; } +PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION +pcre2_set_max_pattern_compiled_length(pcre2_compile_context *ccontext, PCRE2_SIZE length) +{ +ccontext->max_pattern_compiled_length = length; +return 0; +} + PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION pcre2_set_newline(pcre2_compile_context *ccontext, uint32_t newline) { diff --git a/src/pcre2_error.c b/src/pcre2_error.c index 1569f63..7fa997a 100644 --- a/src/pcre2_error.c +++ b/src/pcre2_error.c @@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Original API code Copyright (c) 1997-2012 University of Cambridge - New API code Copyright (c) 2016-2023 University of Cambridge + New API code Copyright (c) 2016-2024 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -189,6 +189,7 @@ static const unsigned char compile_error_texts[] = "\\K is not allowed in lookarounds (but see PCRE2_EXTRA_ALLOW_LOOKAROUND_BSK)\0" /* 100 */ "branch too long in variable-length lookbehind assertion\0" + "compiled pattern would be longer than the limit set by the application\0" ; /* Match-time and UTF error texts are in the same format. */ diff --git a/src/pcre2_extuni.c b/src/pcre2_extuni.c index b23946b..4ed9f00 100644 --- a/src/pcre2_extuni.c +++ b/src/pcre2_extuni.c @@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Original API code Copyright (c) 1997-2012 University of Cambridge - New API code Copyright (c) 2016-2021 University of Cambridge + New API code Copyright (c) 2016-2024 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -75,7 +75,11 @@ return NULL; * Match an extended grapheme sequence * *************************************************/ -/* +/* NOTE: The logic contained in this function is replicated in three special- +purpose functions in the pcre2_jit_compile.c module. If the logic below is +changed, they must be kept in step so that the interpreter and the JIT have the +same behaviour. + Arguments: c the first character eptr pointer to next character @@ -92,6 +96,7 @@ PCRE2_SPTR PRIV(extuni)(uint32_t c, PCRE2_SPTR eptr, PCRE2_SPTR start_subject, PCRE2_SPTR end_subject, BOOL utf, int *xcount) { +BOOL was_ep_ZWJ = FALSE; int lgb = UCD_GRAPHBREAK(c); while (eptr < end_subject) @@ -102,6 +107,12 @@ while (eptr < end_subject) rgb = UCD_GRAPHBREAK(c); if ((PRIV(ucp_gbtable)[lgb] & (1u << rgb)) == 0) break; + /* ZWJ followed by Extended Pictographic is allowed only if the ZWJ was + preceded by Extended Pictographic. */ + + if (lgb == ucp_gbZWJ && rgb == ucp_gbExtended_Pictographic && !was_ep_ZWJ) + break; + /* Not breaking between Regional Indicators is allowed only if there are an even number of preceding RIs. */ @@ -129,12 +140,15 @@ while (eptr < end_subject) if ((ricount & 1) != 0) break; /* Grapheme break required */ } - /* If Extend or ZWJ follows Extended_Pictographic, do not update lgb; this - allows any number of them before a following Extended_Pictographic. */ + /* Set a flag when ZWJ follows Extended Pictographic (with optional Extend in + between; see next statement). */ + + was_ep_ZWJ = (lgb == ucp_gbExtended_Pictographic && rgb == ucp_gbZWJ); + + /* If Extend follows Extended_Pictographic, do not update lgb; this allows + any number of them before a following ZWJ. */ - if ((rgb != ucp_gbExtend && rgb != ucp_gbZWJ) || - lgb != ucp_gbExtended_Pictographic) - lgb = rgb; + if (rgb != ucp_gbExtend || lgb != ucp_gbExtended_Pictographic) lgb = rgb; eptr += len; if (xcount != NULL) *xcount += 1; diff --git a/src/pcre2_fuzzsupport.c b/src/pcre2_fuzzsupport.c index f364832..cd78435 100644 --- a/src/pcre2_fuzzsupport.c +++ b/src/pcre2_fuzzsupport.c @@ -8,9 +8,11 @@ rather than a file name. This allows easy testing of short strings. Written by Philip Hazel, October 2016 Updated February 2024 (Addison Crump added 16-bit/32-bit and JIT support) +Further updates March/April/May 2024 by PH ***************************************************************************/ #include +#include #include #include #include @@ -21,6 +23,7 @@ Updated February 2024 (Addison Crump added 16-bit/32-bit and JIT support) #include #define STACK_SIZE_MB 256 +#define JIT_SIZE_LIMIT (200 * 1024) #ifndef PCRE2_CODE_UNIT_WIDTH #define PCRE2_CODE_UNIT_WIDTH 8 @@ -28,15 +31,20 @@ Updated February 2024 (Addison Crump added 16-bit/32-bit and JIT support) #include "config.h" #include "pcre2.h" +#include "pcre2_internal.h" #define MAX_MATCH_SIZE 1000 #define DFA_WORKSPACE_COUNT 100 +/* When adding new compile or match options, remember to update the functions +below that output them. */ + #define ALLOWED_COMPILE_OPTIONS \ (PCRE2_ANCHORED|PCRE2_ALLOW_EMPTY_CLASS|PCRE2_ALT_BSUX|PCRE2_ALT_CIRCUMFLEX| \ PCRE2_ALT_VERBNAMES|PCRE2_AUTO_CALLOUT|PCRE2_CASELESS|PCRE2_DOLLAR_ENDONLY| \ - PCRE2_DOTALL|PCRE2_DUPNAMES|PCRE2_ENDANCHORED|PCRE2_EXTENDED|PCRE2_FIRSTLINE| \ + PCRE2_DOTALL|PCRE2_DUPNAMES|PCRE2_ENDANCHORED|PCRE2_EXTENDED| \ + PCRE2_EXTENDED_MORE|PCRE2_FIRSTLINE| \ PCRE2_MATCH_UNSET_BACKREF|PCRE2_MULTILINE|PCRE2_NEVER_BACKSLASH_C| \ PCRE2_NO_AUTO_CAPTURE| \ PCRE2_NO_AUTO_POSSESS|PCRE2_NO_DOTSTAR_ANCHOR|PCRE2_NO_START_OPTIMIZE| \ @@ -48,62 +56,89 @@ Updated February 2024 (Addison Crump added 16-bit/32-bit and JIT support) PCRE2_NOTEMPTY_ATSTART|PCRE2_PARTIAL_HARD| \ PCRE2_PARTIAL_SOFT) +#define BASE_MATCH_OPTIONS \ + (PCRE2_NO_JIT|PCRE2_DISABLE_RECURSELOOP_CHECK) + + #if defined(SUPPORT_DIFF_FUZZ) || defined(STANDALONE) static void print_compile_options(FILE *stream, uint32_t compile_options) { -fprintf(stream, "Compile options %.8x never_backslash_c", compile_options); -fprintf(stream, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", - ((compile_options & PCRE2_ALT_BSUX) != 0)? ",alt_bsux" : "", - ((compile_options & PCRE2_ALT_CIRCUMFLEX) != 0)? ",alt_circumflex" : "", - ((compile_options & PCRE2_ALT_VERBNAMES) != 0)? ",alt_verbnames" : "", - ((compile_options & PCRE2_ALLOW_EMPTY_CLASS) != 0)? ",allow_empty_class" : "", - ((compile_options & PCRE2_ANCHORED) != 0)? ",anchored" : "", - ((compile_options & PCRE2_AUTO_CALLOUT) != 0)? ",auto_callout" : "", - ((compile_options & PCRE2_CASELESS) != 0)? ",caseless" : "", - ((compile_options & PCRE2_DOLLAR_ENDONLY) != 0)? ",dollar_endonly" : "", - ((compile_options & PCRE2_DOTALL) != 0)? ",dotall" : "", - ((compile_options & PCRE2_DUPNAMES) != 0)? ",dupnames" : "", - ((compile_options & PCRE2_ENDANCHORED) != 0)? ",endanchored" : "", - ((compile_options & PCRE2_EXTENDED) != 0)? ",extended" : "", - ((compile_options & PCRE2_FIRSTLINE) != 0)? ",firstline" : "", - ((compile_options & PCRE2_MATCH_UNSET_BACKREF) != 0)? ",match_unset_backref" : "", - ((compile_options & PCRE2_MULTILINE) != 0)? ",multiline" : "", - ((compile_options & PCRE2_NEVER_UCP) != 0)? ",never_ucp" : "", - ((compile_options & PCRE2_NEVER_UTF) != 0)? ",never_utf" : "", - ((compile_options & PCRE2_NO_AUTO_CAPTURE) != 0)? ",no_auto_capture" : "", - ((compile_options & PCRE2_NO_AUTO_POSSESS) != 0)? ",no_auto_possess" : "", - ((compile_options & PCRE2_NO_DOTSTAR_ANCHOR) != 0)? ",no_dotstar_anchor" : "", - ((compile_options & PCRE2_NO_UTF_CHECK) != 0)? ",no_utf_check" : "", - ((compile_options & PCRE2_NO_START_OPTIMIZE) != 0)? ",no_start_optimize" : "", - ((compile_options & PCRE2_UCP) != 0)? ",ucp" : "", - ((compile_options & PCRE2_UNGREEDY) != 0)? ",ungreedy" : "", - ((compile_options & PCRE2_USE_OFFSET_LIMIT) != 0)? ",use_offset_limit" : "", - ((compile_options & PCRE2_UTF) != 0)? ",utf" : ""); +fprintf(stream, "Compile options %s%.8x =", + (compile_options == PCRE2_NEVER_BACKSLASH_C)? "(base) " : "", + compile_options); + +fprintf(stream, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", + ((compile_options & PCRE2_ALT_BSUX) != 0)? " alt_bsux" : "", + ((compile_options & PCRE2_ALT_CIRCUMFLEX) != 0)? " alt_circumflex" : "", + ((compile_options & PCRE2_ALT_VERBNAMES) != 0)? " alt_verbnames" : "", + ((compile_options & PCRE2_ALLOW_EMPTY_CLASS) != 0)? " allow_empty_class" : "", + ((compile_options & PCRE2_ANCHORED) != 0)? " anchored" : "", + ((compile_options & PCRE2_AUTO_CALLOUT) != 0)? " auto_callout" : "", + ((compile_options & PCRE2_CASELESS) != 0)? " caseless" : "", + ((compile_options & PCRE2_DOLLAR_ENDONLY) != 0)? " dollar_endonly" : "", + ((compile_options & PCRE2_DOTALL) != 0)? " dotall" : "", + ((compile_options & PCRE2_DUPNAMES) != 0)? " dupnames" : "", + ((compile_options & PCRE2_ENDANCHORED) != 0)? " endanchored" : "", + ((compile_options & PCRE2_EXTENDED) != 0)? " extended" : "", + ((compile_options & PCRE2_EXTENDED_MORE) != 0)? " extended_more" : "", + ((compile_options & PCRE2_FIRSTLINE) != 0)? " firstline" : "", + ((compile_options & PCRE2_MATCH_UNSET_BACKREF) != 0)? " match_unset_backref" : "", + ((compile_options & PCRE2_MULTILINE) != 0)? " multiline" : "", + ((compile_options & PCRE2_NEVER_BACKSLASH_C) != 0)? " never_backslash_c" : "", + ((compile_options & PCRE2_NEVER_UCP) != 0)? " never_ucp" : "", + ((compile_options & PCRE2_NEVER_UTF) != 0)? " never_utf" : "", + ((compile_options & PCRE2_NO_AUTO_CAPTURE) != 0)? " no_auto_capture" : "", + ((compile_options & PCRE2_NO_AUTO_POSSESS) != 0)? " no_auto_possess" : "", + ((compile_options & PCRE2_NO_DOTSTAR_ANCHOR) != 0)? " no_dotstar_anchor" : "", + ((compile_options & PCRE2_NO_UTF_CHECK) != 0)? " no_utf_check" : "", + ((compile_options & PCRE2_NO_START_OPTIMIZE) != 0)? " no_start_optimize" : "", + ((compile_options & PCRE2_UCP) != 0)? " ucp" : "", + ((compile_options & PCRE2_UNGREEDY) != 0)? " ungreedy" : "", + ((compile_options & PCRE2_USE_OFFSET_LIMIT) != 0)? " use_offset_limit" : "", + ((compile_options & PCRE2_UTF) != 0)? " utf" : ""); } static void print_match_options(FILE *stream, uint32_t match_options) { -fprintf(stream, "Match options %.8x", match_options); -fprintf(stream, "%s%s%s%s%s%s%s%s%s\n", - ((match_options & PCRE2_ANCHORED) != 0)? ",anchored" : "", - ((match_options & PCRE2_ENDANCHORED) != 0)? ",endanchored" : "", - ((match_options & PCRE2_NO_UTF_CHECK) != 0)? ",no_utf_check" : "", - ((match_options & PCRE2_NOTBOL) != 0)? ",notbol" : "", - ((match_options & PCRE2_NOTEMPTY) != 0)? ",notempty" : "", - ((match_options & PCRE2_NOTEMPTY_ATSTART) != 0)? ",notempty_atstart" : "", - ((match_options & PCRE2_NOTEOL) != 0)? ",noteol" : "", - ((match_options & PCRE2_PARTIAL_HARD) != 0)? ",partial_hard" : "", - ((match_options & PCRE2_PARTIAL_SOFT) != 0)? ",partial_soft" : ""); +fprintf(stream, "Match options %s%.8x =", + (match_options == BASE_MATCH_OPTIONS)? "(base) " : "", match_options); + +fprintf(stream, "%s%s%s%s%s%s%s%s%s%s%s\n", + ((match_options & PCRE2_ANCHORED) != 0)? " anchored" : "", + ((match_options & PCRE2_DISABLE_RECURSELOOP_CHECK) != 0)? " disable_recurseloop_check" : "", + ((match_options & PCRE2_ENDANCHORED) != 0)? " endanchored" : "", + ((match_options & PCRE2_NO_JIT) != 0)? " no_jit" : "", + ((match_options & PCRE2_NO_UTF_CHECK) != 0)? " no_utf_check" : "", + ((match_options & PCRE2_NOTBOL) != 0)? " notbol" : "", + ((match_options & PCRE2_NOTEMPTY) != 0)? " notempty" : "", + ((match_options & PCRE2_NOTEMPTY_ATSTART) != 0)? " notempty_atstart" : "", + ((match_options & PCRE2_NOTEOL) != 0)? " noteol" : "", + ((match_options & PCRE2_PARTIAL_HARD) != 0)? " partial_hard" : "", + ((match_options & PCRE2_PARTIAL_SOFT) != 0)? " partial_soft" : ""); +} + + +/* This function can print an error message at all code unit widths. */ + +static void print_error(FILE *f, int errorcode, const char *text, ...) +{ +PCRE2_UCHAR buffer[256]; +PCRE2_UCHAR *p = buffer; +va_list ap; +va_start(ap, text); +vfprintf(f, text, ap); +va_end(ap); +pcre2_get_error_message(errorcode, buffer, 256); +while (*p != 0) fprintf(f, "%c", *p++); +printf("\n"); } #endif /* defined(SUPPORT_DIFF_FUZZ || defined(STANDALONE) */ + #ifdef SUPPORT_JIT #ifdef SUPPORT_DIFF_FUZZ static void dump_matches(FILE *stream, int count, pcre2_match_data *match_data) { -#if PCRE2_CODE_UNIT_WIDTH == 8 -PCRE2_UCHAR error_buf[256]; -#endif int errorcode; for (int index = 0; index < count; index++) @@ -111,7 +146,8 @@ for (int index = 0; index < count; index++) PCRE2_UCHAR *bufferptr = NULL; PCRE2_SIZE bufflen = 0; - errorcode = pcre2_substring_get_bynumber(match_data, index, &bufferptr, &bufflen); + errorcode = pcre2_substring_get_bynumber(match_data, index, &bufferptr, + &bufflen); if (errorcode >= 0) { @@ -124,12 +160,7 @@ for (int index = 0; index < count; index++) } else { -#if PCRE2_CODE_UNIT_WIDTH == 8 - pcre2_get_error_message(errorcode, error_buf, 256); - fprintf(stream, "Match %d failed: %s\n", index, error_buf); -#else - fprintf(stream, "Match %d failed: %d\n", index, errorcode); -#endif + print_error(stream, errorcode, "Match %d failed: ", index); } } } @@ -149,9 +180,6 @@ static void describe_failure( pcre2_match_data *match_data, pcre2_match_data *match_data_jit ) { -#if PCRE2_CODE_UNIT_WIDTH == 8 -PCRE2_UCHAR buffer[256]; -#endif fprintf(stderr, "Encountered failure while performing %s; context:\n", task); @@ -167,13 +195,9 @@ print_match_options(stderr, match_options); if (errorcode < 0) { -#if PCRE2_CODE_UNIT_WIDTH == 8 - pcre2_get_error_message(errorcode, buffer, 256); - fprintf(stderr, "Non-JIT'd operation emitted an error: %s (%d)\n", buffer, errorcode); -#else - fprintf(stderr, "Non-JIT'd operation emitted an error: %d\n", errorcode); -#endif + print_error(stderr, errorcode, "Non-JIT'd operation emitted an error: "); } + if (matches >= 0) { fprintf(stderr, "Non-JIT'd operation did not emit an error.\n"); @@ -187,13 +211,10 @@ if (matches >= 0) if (errorcode_jit < 0) { -#if PCRE2_CODE_UNIT_WIDTH == 8 - pcre2_get_error_message(errorcode_jit, buffer, 256); - fprintf(stderr, "JIT'd operation emitted an error: %s (%d)\n", buffer, errorcode_jit); -#else - fprintf(stderr, "JIT'd operation emitted an error: %d\n", errorcode); -#endif + print_error(stderr, errorcode_jit, "JIT'd operation emitted error %d:", + errorcode_jit); } + if (matches_jit >= 0) { fprintf(stderr, "JIT'd operation did not emit an error.\n"); @@ -207,7 +228,7 @@ if (matches_jit >= 0) abort(); } -#endif /* SUPPORRT_DIFF_FUZZ */ +#endif /* SUPPORT_DIFF_FUZZ */ #endif /* SUPPORT_JIT */ /* This is the callout function. Its only purpose is to halt matching if there @@ -226,7 +247,7 @@ return (*((uint32_t *)callout_data) > 100)? PCRE2_ERROR_CALLOUT : 0; int LLVMFuzzerInitialize(int *, char ***); -int LLVMFuzzerTestOneInput(const unsigned char *, size_t); +int LLVMFuzzerTestOneInput(unsigned char *, size_t); int LLVMFuzzerInitialize(int *argc, char ***argv) { @@ -236,13 +257,13 @@ getrlimit(RLIMIT_STACK, &rlim); rlim.rlim_cur = STACK_SIZE_MB * 1024 * 1024; if (rlim.rlim_cur > rlim.rlim_max) { - fprintf(stderr, "hard stack size limit is too small (needed 8MiB)!\n"); + fprintf(stderr, "Hard stack size limit is too small (needed 8MiB)!\n"); _exit(1); } rc = setrlimit(RLIMIT_STACK, &rlim); if (rc != 0) { - fprintf(stderr, "failed to expand stack size\n"); + fprintf(stderr, "Failed to expand stack size\n"); _exit(1); } @@ -253,8 +274,10 @@ return 0; /* Here's the driving function. */ -int LLVMFuzzerTestOneInput(const unsigned char *data, size_t size) +int LLVMFuzzerTestOneInput(unsigned char *data, size_t size) { +PCRE2_UCHAR *wdata; +PCRE2_UCHAR *newwdata = NULL; uint32_t compile_options; uint32_t match_options; uint64_t random_options; @@ -262,34 +285,149 @@ pcre2_match_data *match_data = NULL; #ifdef SUPPORT_JIT pcre2_match_data *match_data_jit = NULL; #endif +pcre2_compile_context *compile_context = NULL; pcre2_match_context *match_context = NULL; size_t match_size; int dfa_workspace[DFA_WORKSPACE_COUNT]; -int i; if (size < sizeof(random_options)) return -1; -/* Limiting the length of the subject for matching stops fruitless searches -in large trees taking too much time. */ - random_options = *(uint64_t *)(data); data += sizeof(random_options); +wdata = (PCRE2_UCHAR *)data; size -= sizeof(random_options); size /= PCRE2_CODE_UNIT_WIDTH / 8; +/* PCRE2 compiles quantified groups by replicating them. In certain cases of +very large quantifiers this can lead to unacceptably long JIT compile times. To +get around this, we scan the data string for large quantifiers that follow a +closing parenthesis, and reduce the value of the quantifier to 10, assuming +that this will make minimal difference to the detection of bugs. + +Do the same for quantifiers that follow a closing square bracket, because +classes that contain a number of non-ascii characters can take a lot of time +when matching. + +We have to make a copy of the input because oss-fuzz complains if we overwrite +the original. Start the scan at the second character so there can be a +lookbehind for a backslash, and end it before the end so that the next +character can be checked for an opening brace. */ + +if (size > 3) + { + newwdata = malloc(size * sizeof(PCRE2_UCHAR)); + memcpy(newwdata, wdata, size * sizeof(PCRE2_UCHAR)); + wdata = newwdata; + + for (size_t i = 1; i < size - 2; i++) + { + size_t j; + + if ((wdata[i] != ')' && wdata[i] != ']') || wdata[i-1] == '\\' || + wdata[i+1] != '{') + continue; + i++; /* Points to '{' */ + + /* Loop for two values a quantifier. Offset i points to brace or comma at the + start of the loop.*/ + + for (int ii = 0; ii < 2; ii++) + { + int q = 0; + + if (i >= size - 1) goto END_QSCAN; /* Can happen for , */ + + /* Ignore leading spaces */ + + while (wdata[i+1] == ' ' || wdata[i+1] == '\t') + { + i++; + if (i >= size - 1) goto END_QSCAN; + } + + /* Scan for a number ending in brace or comma in the first iteration, + optionally preceded by space. */ + + for (j = i + 1; j < size && j < i + 7; j++) + { + if (wdata[j] == ' ' || wdata[j] == '\t') + { + j++; + while (j < size && (wdata[j] == ' ' || wdata[j] == '\t')) j++; + if (j >= size) goto OUTERLOOP; + if (wdata[j] != '}' && wdata[j] != ',') goto OUTERLOOP; + } + if (wdata[j] == '}' || (ii == 0 && wdata[j] == ',')) break; + if (wdata[j] < '0' || wdata[j] > '9') + { + j--; /* Ensure this character is checked next. The */ + goto OUTERLOOP; /* string might be (e.g.) "){9){234}" */ + } + q = q * 10 + wdata[j] - '0'; + } + + if (j >= size) goto END_QSCAN; /* End of data */ + + /* Hit ',' or '}' or read 6 digits. Six digits is a number > 65536 which is + the maximum quantifier. Leave such numbers alone. */ + + if (j >= i + 7 || q > 65535) goto OUTERLOOP; + + /* Limit the quantifier size to 10 */ + + if (q > 10) + { +#ifdef STANDALONE + printf("Reduced quantifier value %d to 10.\n", q); +#endif + for (size_t k = i + 1; k < j; k++) wdata[k] = '0'; + wdata[j - 2] = '1'; + } + + /* Advance to end of number and break if reached closing brace (continue + after comma, which is only valid in the first time round this loop). */ + + i = j; + if (wdata[i] == '}') break; + } + + /* Continue along the data string */ + + OUTERLOOP: + i = j; + continue; + } + } +END_QSCAN: + +/* Limiting the length of the subject for matching stops fruitless searches +in large trees taking too much time. */ + match_size = (size > MAX_MATCH_SIZE)? MAX_MATCH_SIZE : size; +/* Create a compile context, and set a limit on the size of the compiled +pattern. This stops the fuzzer using vast amounts of memory. */ + +compile_context = pcre2_compile_context_create(NULL); +if (compile_context == NULL) + { +#ifdef STANDALONE + fprintf(stderr, "** Failed to create compile context block\n"); +#endif + abort(); + } +pcre2_set_max_pattern_compiled_length(compile_context, 10*1024*1024); + /* Ensure that all undefined option bits are zero (waste of time trying them) and also that PCRE2_NO_UTF_CHECK is unset, as there is no guarantee that the -input is UTF-8. Also unset PCRE2_NEVER_UTF and PCRE2_NEVER_UCP as there is no -reason to disallow UTF and UCP. Force PCRE2_NEVER_BACKSLASH_C to be set because -\C in random patterns is highly likely to cause a crash. */ +input is valid UTF. Also unset PCRE2_NEVER_UTF and PCRE2_NEVER_UCP as there is +no reason to disallow UTF and UCP. Force PCRE2_NEVER_BACKSLASH_C to be set +because \C in random patterns is highly likely to cause a crash. */ compile_options = ((random_options >> 32) & ALLOWED_COMPILE_OPTIONS) | PCRE2_NEVER_BACKSLASH_C; match_options = (((uint32_t)random_options) & ALLOWED_MATCH_OPTIONS) | - PCRE2_NO_JIT | - PCRE2_DISABLE_RECURSELOOP_CHECK; + BASE_MATCH_OPTIONS; /* Discard partial matching if PCRE2_ENDANCHORED is set, because they are not allowed together and just give an immediate error return. */ @@ -300,13 +438,13 @@ if (((compile_options|match_options) & PCRE2_ENDANCHORED) != 0) /* Do the compile with and without the options, and after a successful compile, likewise do the match with and without the options. */ -for (i = 0; i < 2; i++) +for (int i = 0; i < 2; i++) { uint32_t callout_count; int errorcode; #ifdef SUPPORT_JIT int errorcode_jit; -#ifdef SUPPORT_JIT_FUZZ +#ifdef SUPPORT_DIFF_FUZZ int matches = 0; int matches_jit = 0; #endif @@ -315,11 +453,12 @@ for (i = 0; i < 2; i++) pcre2_code *code; #ifdef STANDALONE + printf("\n"); print_compile_options(stdout, compile_options); #endif - code = pcre2_compile((PCRE2_SPTR)data, (PCRE2_SIZE)size, compile_options, - &errorcode, &erroroffset, NULL); + code = pcre2_compile((PCRE2_SPTR)wdata, (PCRE2_SIZE)size, compile_options, + &errorcode, &erroroffset, compile_context); /* Compilation succeeded */ @@ -328,9 +467,29 @@ for (i = 0; i < 2; i++) int j; uint32_t save_match_options = match_options; + /* Call JIT compile only if the compiled pattern is not too big. */ + #ifdef SUPPORT_JIT - int jit_ret = pcre2_jit_compile(code, PCRE2_JIT_COMPLETE); + int jit_ret = -1; + if (((struct pcre2_real_code *)code)->blocksize <= JIT_SIZE_LIMIT) + { +#ifdef STANDALONE + printf("Compile succeeded; calling JIT compile\n"); +#endif + jit_ret = pcre2_jit_compile(code, PCRE2_JIT_COMPLETE); +#ifdef STANDALONE + if (jit_ret < 0) printf("JIT compile error %d\n", jit_ret); #endif + } + else + { +#ifdef STANDALONE + printf("Not calling JIT: compiled pattern is too long " + "(%ld bytes; limit=%d)\n", + ((struct pcre2_real_code *)code)->blocksize, JIT_SIZE_LIMIT); +#endif + } +#endif /* SUPPORT_JIT */ /* Create match data and context blocks only when we first need them. Set low match and depth limits to avoid wasting too much searching large @@ -370,6 +529,9 @@ for (i = 0; i < 2; i++) /* Match twice, with and without options. */ +#ifdef STANDALONE + printf("\n"); +#endif for (j = 0; j < 2; j++) { #ifdef STANDALONE @@ -377,33 +539,40 @@ for (i = 0; i < 2; i++) #endif callout_count = 0; - errorcode = pcre2_match(code, (PCRE2_SPTR)data, (PCRE2_SIZE)match_size, 0, + errorcode = pcre2_match(code, (PCRE2_SPTR)wdata, (PCRE2_SIZE)match_size, 0, match_options, match_data, match_context); #ifdef STANDALONE if (errorcode >= 0) printf("Match returned %d\n", errorcode); else - { -#if PCRE2_CODE_UNIT_WIDTH == 8 - unsigned char buffer[256]; - pcre2_get_error_message(errorcode, buffer, 256); - printf("Match failed: error %d: %s\n", errorcode, buffer); -#else - printf("Match failed: error %d\n", errorcode); -#endif - } + print_error(stdout, errorcode, "Match failed: error %d: ", errorcode); #endif +/* If JIT is enabled, do a JIT match and, if appropriately compiled, compare +with the interpreter. */ + #ifdef SUPPORT_JIT if (jit_ret >= 0) { +#ifdef STANDALONE + printf("Matching with JIT\n"); +#endif callout_count = 0; - errorcode_jit = pcre2_match(code, (PCRE2_SPTR)data, (PCRE2_SIZE)match_size, 0, + errorcode_jit = pcre2_match(code, (PCRE2_SPTR)wdata, (PCRE2_SIZE)match_size, 0, match_options & ~PCRE2_NO_JIT, match_data_jit, match_context); -#ifndef SUPPORT_DIFF_FUZZ - (void)errorcode_jit; /* Avoid compiler warning */ +#ifdef STANDALONE + if (errorcode_jit >= 0) + printf("Match returned %d\n", errorcode_jit); + else + print_error(stdout, errorcode_jit, "JIT match failed: error %d: ", + errorcode_jit); #else + (void)errorcode_jit; /* Avoid compiler warning */ +#endif /* STANDALONE */ + +/* With differential matching enabled, compare with interpreter. */ +#ifdef SUPPORT_DIFF_FUZZ matches = errorcode; matches_jit = errorcode_jit; @@ -413,7 +582,7 @@ for (i = 0; i < 2; i++) errorcode != PCRE2_ERROR_MATCHLIMIT && errorcode != PCRE2_ERROR_CALLOUT && errorcode_jit != PCRE2_ERROR_MATCHLIMIT && errorcode_jit != PCRE2_ERROR_JIT_STACKLIMIT && errorcode_jit != PCRE2_ERROR_CALLOUT) { - describe_failure("match errorcode comparison", data, size, compile_options, match_options, errorcode, errorcode_jit, matches, matches_jit, match_data, match_data_jit); + describe_failure("match errorcode comparison", wdata, size, compile_options, match_options, errorcode, errorcode_jit, matches, matches_jit, match_data, match_data_jit); } } else @@ -431,7 +600,7 @@ for (i = 0; i < 2; i++) if (errorcode != errorcode_jit) { - describe_failure("match entry errorcode comparison", data, size, + describe_failure("match entry errorcode comparison", wdata, size, compile_options, match_options, errorcode, errorcode_jit, matches, matches_jit, match_data, match_data_jit); } @@ -440,14 +609,14 @@ for (i = 0; i < 2; i++) { if (bufflen != bufflen_jit) { - describe_failure("match entry length comparison", data, size, + describe_failure("match entry length comparison", wdata, size, compile_options, match_options, errorcode, errorcode_jit, matches, matches_jit, match_data, match_data_jit); } if (memcmp(bufferptr, bufferptr_jit, bufflen) != 0) { - describe_failure("match entry content comparison", data, size, + describe_failure("match entry content comparison", wdata, size, compile_options, match_options, errorcode, errorcode_jit, matches, matches_jit, match_data, match_data_jit); } @@ -457,52 +626,53 @@ for (i = 0; i < 2; i++) pcre2_substring_free(bufferptr_jit); } } -#endif /* SUPPORT_JIT_FUZZ */ +#endif /* SUPPORT_DIFF_FUZZ */ } #endif /* SUPPORT_JIT */ - match_options = PCRE2_NO_JIT; /* For second time */ + if (match_options == BASE_MATCH_OPTIONS) break; /* Don't do same twice */ + match_options = BASE_MATCH_OPTIONS; /* For second time */ } - /* Match with DFA twice, with and without options. */ + /* Match with DFA twice, with and without options, but remove options that + are not allowed with DFA. */ - match_options = save_match_options & ~PCRE2_NO_JIT; /* Not valid for DFA */ + match_options = save_match_options & ~BASE_MATCH_OPTIONS; + +#ifdef STANDALONE + printf("\n"); +#endif for (j = 0; j < 2; j++) { #ifdef STANDALONE - printf("DFA match options %.8x", match_options); + printf("DFA match options %.8x =", match_options); printf("%s%s%s%s%s%s%s%s%s\n", - ((match_options & PCRE2_ANCHORED) != 0)? ",anchored" : "", - ((match_options & PCRE2_ENDANCHORED) != 0)? ",endanchored" : "", - ((match_options & PCRE2_NO_UTF_CHECK) != 0)? ",no_utf_check" : "", - ((match_options & PCRE2_NOTBOL) != 0)? ",notbol" : "", - ((match_options & PCRE2_NOTEMPTY) != 0)? ",notempty" : "", - ((match_options & PCRE2_NOTEMPTY_ATSTART) != 0)? ",notempty_atstart" : "", - ((match_options & PCRE2_NOTEOL) != 0)? ",noteol" : "", - ((match_options & PCRE2_PARTIAL_HARD) != 0)? ",partial_hard" : "", - ((match_options & PCRE2_PARTIAL_SOFT) != 0)? ",partial_soft" : ""); + ((match_options & PCRE2_ANCHORED) != 0)? " anchored" : "", + ((match_options & PCRE2_ENDANCHORED) != 0)? " endanchored" : "", + ((match_options & PCRE2_NO_UTF_CHECK) != 0)? " no_utf_check" : "", + ((match_options & PCRE2_NOTBOL) != 0)? " notbol" : "", + ((match_options & PCRE2_NOTEMPTY) != 0)? " notempty" : "", + ((match_options & PCRE2_NOTEMPTY_ATSTART) != 0)? " notempty_atstart" : "", + ((match_options & PCRE2_NOTEOL) != 0)? " noteol" : "", + ((match_options & PCRE2_PARTIAL_HARD) != 0)? " partial_hard" : "", + ((match_options & PCRE2_PARTIAL_SOFT) != 0)? " partial_soft" : ""); #endif callout_count = 0; - errorcode = pcre2_dfa_match(code, (PCRE2_SPTR)data, - (PCRE2_SIZE)match_size, 0, match_options, match_data, match_context, - dfa_workspace, DFA_WORKSPACE_COUNT); + errorcode = pcre2_dfa_match(code, (PCRE2_SPTR)wdata, + (PCRE2_SIZE)match_size, 0, match_options, match_data, + match_context, dfa_workspace, DFA_WORKSPACE_COUNT); #ifdef STANDALONE - if (errorcode >= 0) printf("Match returned %d\n", errorcode); else - { -#if PCRE2_CODE_UNIT_WIDTH == 8 - unsigned char buffer[256]; - pcre2_get_error_message(errorcode, buffer, 256); - printf("Match failed: error %d: %s\n", errorcode, buffer); -#else - printf("Match failed: error %d\n", errorcode); -#endif - } + if (errorcode >= 0) + printf("Match returned %d\n", errorcode); + else + print_error(stdout, errorcode, "DFA match failed: error %d: ", errorcode); #endif - match_options = 0; /* For second time */ + if (match_options == 0) break; /* No point doing same twice */ + match_options = 0; /* For second time */ } match_options = save_match_options; /* Reset for the second compile */ @@ -514,28 +684,26 @@ for (i = 0; i < 2; i++) else { #ifdef STANDALONE -#if PCRE2_CODE_UNIT_WIDTH == 8 - unsigned char buffer[256]; - pcre2_get_error_message(errorcode, buffer, 256); - printf("Error %d at offset %lu: %s\n", errorcode, erroroffset, buffer); -#else - printf("Error %d at offset %lu\n", errorcode, erroroffset); -#endif - + print_error(stdout, errorcode, "Error %d at offset %lu: ", errorcode, + erroroffset); #else if (errorcode == PCRE2_ERROR_INTERNAL) abort(); #endif } - compile_options = PCRE2_NEVER_BACKSLASH_C; /* For second time */ + if (compile_options == PCRE2_NEVER_BACKSLASH_C) break; /* Avoid same twice */ + compile_options = PCRE2_NEVER_BACKSLASH_C; /* For second time */ } +/* Tidy up before exiting */ + if (match_data != NULL) pcre2_match_data_free(match_data); #ifdef SUPPORT_JIT if (match_data_jit != NULL) pcre2_match_data_free(match_data_jit); +free(newwdata); #endif if (match_context != NULL) pcre2_match_context_free(match_context); - +if (compile_context != NULL) pcre2_compile_context_free(compile_context); return 0; } @@ -545,8 +713,6 @@ return 0; #ifdef STANDALONE int main(int argc, char **argv) { -int i; - LLVMFuzzerInitialize(&argc, &argv); if (argc < 2) @@ -555,7 +721,7 @@ if (argc < 2) return 0; } -for (i = 1; i < argc; i++) +for (int i = 1; i < argc; i++) { size_t filelen; size_t readsize; diff --git a/src/pcre2_intmodedep.h b/src/pcre2_intmodedep.h index 5fcddce..9bd9e69 100644 --- a/src/pcre2_intmodedep.h +++ b/src/pcre2_intmodedep.h @@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Original API code Copyright (c) 1997-2012 University of Cambridge - New API code Copyright (c) 2016-2023 University of Cambridge + New API code Copyright (c) 2016-2024 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -568,6 +568,7 @@ typedef struct pcre2_real_compile_context { void *stack_guard_data; const uint8_t *tables; PCRE2_SIZE max_pattern_length; + PCRE2_SIZE max_pattern_compiled_length; uint16_t bsr_convention; uint16_t newline_convention; uint32_t parens_nest_limit; diff --git a/src/pcre2_jit_compile.c b/src/pcre2_jit_compile.c index 050063e..92f4fb8 100644 --- a/src/pcre2_jit_compile.c +++ b/src/pcre2_jit_compile.c @@ -8,7 +8,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel This module by Zoltan Herczeg Original API code Copyright (c) 1997-2012 University of Cambridge - New API code Copyright (c) 2016-2021 University of Cambridge + New API code Copyright (c) 2016-2024 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -288,7 +288,7 @@ typedef struct bracket_backtrack { /* For OP_ONCE. Less than 0 if not needed. */ int framesize; /* For brackets with >3 alternatives. */ - struct sljit_put_label *matching_put_label; + struct sljit_jump *matching_mov_addr; } u; /* Points to our private memory word on the stack. */ int private_data_ptr; @@ -5891,7 +5891,7 @@ while (TRUE) chr++; } while (byte != 0); - chr = (chr + 7) & ~7; + chr = (chr + 7) & (sljit_u32)(~7); } } while (chars->count != 255 && bytes < bytes_end); @@ -5951,7 +5951,10 @@ while (TRUE) chr = *cc; #ifdef SUPPORT_UNICODE if (common->ucp && chr > 127) - othercase[0] = UCD_OTHERCASE(chr); + { + chr = UCD_OTHERCASE(chr); + othercase[0] = (chr == (PCRE2_UCHAR)chr) ? chr : *cc; + } else #endif othercase[0] = TABLE_GET(chr, common->fcc, chr); @@ -6183,25 +6186,34 @@ if (max < 1) /* Convert last_count to priority. */ for (i = 0; i < max; i++) { - SLJIT_ASSERT(chars[i].count > 0 && chars[i].last_count <= chars[i].count); + SLJIT_ASSERT(chars[i].last_count <= chars[i].count); - if (chars[i].count == 1) + switch (chars[i].count) { + case 0: + chars[i].count = 255; + chars[i].last_count = 0; + break; + + case 1: chars[i].last_count = (chars[i].last_count == 1) ? 7 : 5; /* Simplifies algorithms later. */ chars[i].chars[1] = chars[i].chars[0]; - } - else if (chars[i].count == 2) - { + break; + + case 2: SLJIT_ASSERT(chars[i].chars[0] != chars[i].chars[1]); if (is_powerof2(chars[i].chars[0] ^ chars[i].chars[1])) chars[i].last_count = (chars[i].last_count == 2) ? 6 : 4; else chars[i].last_count = (chars[i].last_count == 2) ? 3 : 2; - } - else + break; + + default: chars[i].last_count = (chars[i].count == 255) ? 0 : 1; + break; + } } #ifdef JIT_HAS_FAST_FORWARD_CHAR_PAIR_SIMD @@ -6941,7 +6953,7 @@ int i, byte, length = 0; bit = bits[0] & 0x1; /* All bits will be zero or one (since bit is zero or one). */ -all = -bit; +all = (sljit_u8)-bit; for (i = 0; i < 256; ) { @@ -6958,7 +6970,7 @@ for (i = 0; i < 256; ) ranges[length] = i; length++; bit = cbit; - all = -cbit; + all = (sljit_u8)-cbit; /* sign extend bit into byte */ } i++; } @@ -7102,7 +7114,7 @@ for (i = 0; i < 32; i++) byte = bits[i]; if (nclass) - byte = ~byte; + byte = (sljit_u8)~byte; j = 0; while (byte != 0) @@ -8003,7 +8015,7 @@ if (unicode_status & XCLASS_NEEDS_UCD) if (cc[-1] == XCL_NOTPROP) invertcmp ^= 0x1; - OP2U(SLJIT_AND32 | SLJIT_SET_Z, SLJIT_MEM1(TMP1), (sljit_sw)(PRIV(ucd_boolprop_sets) + (cc[1] >> 5)), SLJIT_IMM, (sljit_sw)1 << (cc[1] & 0x1f)); + OP2U(SLJIT_AND32 | SLJIT_SET_Z, SLJIT_MEM1(TMP1), (sljit_sw)(PRIV(ucd_boolprop_sets) + (cc[1] >> 5)), SLJIT_IMM, (sljit_sw)(1u << (cc[1] & 0x1f))); add_jump(compiler, compares > 0 ? list : backtracks, JUMP(SLJIT_NOT_ZERO ^ invertcmp)); } cc += 2; @@ -8114,7 +8126,7 @@ if (unicode_status & XCLASS_NEEDS_UCD) invertcmp ^= 0x1; } - OP2U(SLJIT_AND32 | SLJIT_SET_Z, SLJIT_MEM1(TMP1), (sljit_sw)(PRIV(ucd_script_sets) + (cc[1] >> 5)), SLJIT_IMM, (sljit_sw)1 << (cc[1] & 0x1f)); + OP2U(SLJIT_AND32 | SLJIT_SET_Z, SLJIT_MEM1(TMP1), (sljit_sw)(PRIV(ucd_script_sets) + (cc[1] >> 5)), SLJIT_IMM, (sljit_sw)(1u << (cc[1] & 0x1f))); add_jump(compiler, compares > 0 ? list : backtracks, JUMP(SLJIT_NOT_ZERO ^ invertcmp)); if (jump != NULL) @@ -8685,6 +8697,10 @@ return cc; #if PCRE2_CODE_UNIT_WIDTH != 32 +/* The code in this function copies the logic of the interpreter function that +is defined in the pcre2_extuni.c source. If that code is updated, this +function, and those below it, must be kept in step (note by PH, June 2024). */ + static PCRE2_SPTR SLJIT_FUNC do_extuni_utf(jit_arguments *args, PCRE2_SPTR cc) { PCRE2_SPTR start_subject = args->begin; @@ -8692,6 +8708,7 @@ PCRE2_SPTR end_subject = args->end; int lgb, rgb, ricount; PCRE2_SPTR prevcc, endcc, bptr; BOOL first = TRUE; +BOOL was_ep_ZWJ = FALSE; uint32_t c; prevcc = cc; @@ -8712,6 +8729,12 @@ do if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0) break; + /* ZWJ followed by Extended Pictographic is allowed only if the ZWJ was + preceded by Extended Pictographic. */ + + if (lgb == ucp_gbZWJ && rgb == ucp_gbExtended_Pictographic && !was_ep_ZWJ) + break; + /* Not breaking between Regional Indicators is allowed only if there are an even number of preceding RIs. */ @@ -8736,11 +8759,15 @@ do if ((ricount & 1) != 0) break; /* Grapheme break required */ } - /* If Extend or ZWJ follows Extended_Pictographic, do not update lgb; this - allows any number of them before a following Extended_Pictographic. */ + /* Set a flag when ZWJ follows Extended Pictographic (with optional Extend in + between; see next statement). */ + + was_ep_ZWJ = (lgb == ucp_gbExtended_Pictographic && rgb == ucp_gbZWJ); - if ((rgb != ucp_gbExtend && rgb != ucp_gbZWJ) || - lgb != ucp_gbExtended_Pictographic) + /* If Extend follows Extended_Pictographic, do not update lgb; this allows + any number of them before a following ZWJ. */ + + if (rgb != ucp_gbExtend || lgb != ucp_gbExtended_Pictographic) lgb = rgb; prevcc = endcc; @@ -8753,6 +8780,10 @@ return endcc; #endif /* PCRE2_CODE_UNIT_WIDTH != 32 */ +/* The code in this function copies the logic of the interpreter function that +is defined in the pcre2_extuni.c source. If that code is updated, this +function, and the one below it, must be kept in step (note by PH, June 2024). */ + static PCRE2_SPTR SLJIT_FUNC do_extuni_utf_invalid(jit_arguments *args, PCRE2_SPTR cc) { PCRE2_SPTR start_subject = args->begin; @@ -8760,6 +8791,7 @@ PCRE2_SPTR end_subject = args->end; int lgb, rgb, ricount; PCRE2_SPTR prevcc, endcc, bptr; BOOL first = TRUE; +BOOL was_ep_ZWJ = FALSE; uint32_t c; prevcc = cc; @@ -8780,6 +8812,12 @@ do if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0) break; + /* ZWJ followed by Extended Pictographic is allowed only if the ZWJ was + preceded by Extended Pictographic. */ + + if (lgb == ucp_gbZWJ && rgb == ucp_gbExtended_Pictographic && !was_ep_ZWJ) + break; + /* Not breaking between Regional Indicators is allowed only if there are an even number of preceding RIs. */ @@ -8803,11 +8841,15 @@ do break; /* Grapheme break required */ } - /* If Extend or ZWJ follows Extended_Pictographic, do not update lgb; this - allows any number of them before a following Extended_Pictographic. */ + /* Set a flag when ZWJ follows Extended Pictographic (with optional Extend in + between; see next statement). */ + + was_ep_ZWJ = (lgb == ucp_gbExtended_Pictographic && rgb == ucp_gbZWJ); - if ((rgb != ucp_gbExtend && rgb != ucp_gbZWJ) || - lgb != ucp_gbExtended_Pictographic) + /* If Extend follows Extended_Pictographic, do not update lgb; this allows + any number of them before a following ZWJ. */ + + if (rgb != ucp_gbExtend || lgb != ucp_gbExtended_Pictographic) lgb = rgb; prevcc = endcc; @@ -8818,6 +8860,10 @@ while (cc < end_subject); return endcc; } +/* The code in this function copies the logic of the interpreter function that +is defined in the pcre2_extuni.c source. If that code is updated, this +function must be kept in step (note by PH, June 2024). */ + static PCRE2_SPTR SLJIT_FUNC do_extuni_no_utf(jit_arguments *args, PCRE2_SPTR cc) { PCRE2_SPTR start_subject = args->begin; @@ -8825,6 +8871,7 @@ PCRE2_SPTR end_subject = args->end; int lgb, rgb, ricount; PCRE2_SPTR bptr; uint32_t c; +BOOL was_ep_ZWJ = FALSE; /* Patch by PH */ /* GETCHARINC(c, cc); */ @@ -8848,6 +8895,12 @@ while (cc < end_subject) if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0) break; + /* ZWJ followed by Extended Pictographic is allowed only if the ZWJ was + preceded by Extended Pictographic. */ + + if (lgb == ucp_gbZWJ && rgb == ucp_gbExtended_Pictographic && !was_ep_ZWJ) + break; + /* Not breaking between Regional Indicators is allowed only if there are an even number of preceding RIs. */ @@ -8875,11 +8928,15 @@ while (cc < end_subject) break; /* Grapheme break required */ } - /* If Extend or ZWJ follows Extended_Pictographic, do not update lgb; this - allows any number of them before a following Extended_Pictographic. */ + /* Set a flag when ZWJ follows Extended Pictographic (with optional Extend in + between; see next statement). */ + + was_ep_ZWJ = (lgb == ucp_gbExtended_Pictographic && rgb == ucp_gbZWJ); - if ((rgb != ucp_gbExtend && rgb != ucp_gbZWJ) || - lgb != ucp_gbExtended_Pictographic) + /* If Extend follows Extended_Pictographic, do not update lgb; this allows + any number of them before a following ZWJ. */ + + if (rgb != ucp_gbExtend || lgb != ucp_gbExtended_Pictographic) lgb = rgb; cc++; @@ -9836,7 +9893,7 @@ BACKTRACK_AS(recurse_backtrack)->matchingpath = LABEL(); return cc + 1 + LINK_SIZE; } -static sljit_s32 SLJIT_FUNC SLJIT_FUNC_ATTRIBUTE do_callout_jit(struct jit_arguments *arguments, pcre2_callout_block *callout_block, PCRE2_SPTR *jit_ovector) +static sljit_s32 SLJIT_FUNC do_callout_jit(struct jit_arguments *arguments, pcre2_callout_block *callout_block, PCRE2_SPTR *jit_ovector) { PCRE2_SPTR begin; PCRE2_SIZE *ovector; @@ -11227,7 +11284,7 @@ if (has_alternatives) if (i <= 3) OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), SLJIT_IMM, 0); else - BACKTRACK_AS(bracket_backtrack)->u.matching_put_label = sljit_emit_put_label(compiler, SLJIT_MEM1(STACK_TOP), STACK(stacksize)); + BACKTRACK_AS(bracket_backtrack)->u.matching_mov_addr = sljit_emit_mov_addr(compiler, SLJIT_MEM1(STACK_TOP), STACK(stacksize)); } if (ket != OP_KETRMAX) BACKTRACK_AS(bracket_backtrack)->alternative_matchingpath = LABEL(); @@ -11314,17 +11371,22 @@ if (bra == OP_BRAMINZERO) /* Continue to the normal backtrack. */ } -if ((ket != OP_KET && bra != OP_BRAMINZERO) || bra == OP_BRAZERO) +if ((ket != OP_KET && bra != OP_BRAMINZERO) || bra == OP_BRAZERO || (has_alternatives && repeat_type != OP_EXACT)) count_match(common); cc += 1 + LINK_SIZE; if (opcode == OP_ONCE) { + int data; + int framesize = BACKTRACK_AS(bracket_backtrack)->u.framesize; + + SLJIT_ASSERT(SHRT_MIN <= framesize && framesize < SHRT_MAX/2); /* We temporarily encode the needs_control_head in the lowest bit. - Note: on the target architectures of SLJIT the ((x << 1) >> 1) returns - the same value for small signed numbers (including negative numbers). */ - BACKTRACK_AS(bracket_backtrack)->u.framesize = (int)((unsigned)BACKTRACK_AS(bracket_backtrack)->u.framesize << 1) | (needs_control_head ? 1 : 0); + The real value should be short enough for this operation to work + without triggering Undefined Behaviour. */ + data = (int)((short)((unsigned short)framesize << 1) | (needs_control_head ? 1 : 0)); + BACKTRACK_AS(bracket_backtrack)->u.framesize = data; } return cc + repeat_length; } @@ -13005,7 +13067,7 @@ struct sljit_jump *once = NULL; struct sljit_jump *cond = NULL; struct sljit_label *rmin_label = NULL; struct sljit_label *exact_label = NULL; -struct sljit_put_label *put_label = NULL; +struct sljit_jump *mov_addr = NULL; if (*cc == OP_BRAZERO || *cc == OP_BRAMINZERO) { @@ -13166,8 +13228,8 @@ else if (has_alternatives) { sljit_emit_ijump(compiler, SLJIT_JUMP, TMP1, 0); - SLJIT_ASSERT(CURRENT_AS(bracket_backtrack)->u.matching_put_label); - sljit_set_put_label(CURRENT_AS(bracket_backtrack)->u.matching_put_label, LABEL()); + SLJIT_ASSERT(CURRENT_AS(bracket_backtrack)->u.matching_mov_addr); + sljit_set_label(CURRENT_AS(bracket_backtrack)->u.matching_mov_addr, LABEL()); sljit_emit_op0(compiler, SLJIT_ENDBR); } else @@ -13320,7 +13382,7 @@ if (has_alternatives) if (alt_max <= 3) OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), SLJIT_IMM, alt_count); else - put_label = sljit_emit_put_label(compiler, SLJIT_MEM1(STACK_TOP), STACK(stacksize)); + mov_addr = sljit_emit_mov_addr(compiler, SLJIT_MEM1(STACK_TOP), STACK(stacksize)); } if (offset != 0 && ket == OP_KETRMAX && common->optimized_cbracket[offset >> 1] != 0) @@ -13346,7 +13408,7 @@ if (has_alternatives) } else { - sljit_set_put_label(put_label, LABEL()); + sljit_set_label(mov_addr, LABEL()); sljit_emit_op0(compiler, SLJIT_ENDBR); } } @@ -13878,7 +13940,7 @@ jump_list *match = NULL; struct sljit_jump *next_alt = NULL; struct sljit_jump *accept_exit = NULL; struct sljit_label *quit; -struct sljit_put_label *put_label = NULL; +struct sljit_jump *mov_addr = NULL; /* Recurse captures then. */ common->then_trap = NULL; @@ -13941,7 +14003,7 @@ while (1) if (alt_max > 1 || (recurse_flags & recurse_flag_accept_found)) { if (alt_max > 3) - put_label = sljit_emit_put_label(compiler, SLJIT_MEM1(STACK_TOP), STACK(1)); + mov_addr = sljit_emit_mov_addr(compiler, SLJIT_MEM1(STACK_TOP), STACK(1)); else OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, alt_count); } @@ -13974,7 +14036,7 @@ while (1) if (alt_max > 3) { sljit_emit_ijump(compiler, SLJIT_JUMP, TMP1, 0); - sljit_set_put_label(put_label, LABEL()); + sljit_set_label(mov_addr, LABEL()); sljit_emit_op0(compiler, SLJIT_ENDBR); } else @@ -13985,7 +14047,7 @@ while (1) } else if (alt_max > 3) { - sljit_set_put_label(put_label, LABEL()); + sljit_set_label(mov_addr, LABEL()); sljit_emit_op0(compiler, SLJIT_ENDBR); } else @@ -14303,7 +14365,7 @@ if (common->has_then) set_then_offsets(common, common->start, NULL); } -compiler = sljit_create_compiler(allocator_data, NULL); +compiler = sljit_create_compiler(allocator_data); if (!compiler) { SLJIT_FREE(common->optimized_cbracket, allocator_data); @@ -14718,7 +14780,7 @@ if (common->getucdtype != NULL) SLJIT_FREE(common->optimized_cbracket, allocator_data); SLJIT_FREE(common->private_data_ptrs, allocator_data); -executable_func = sljit_generate_code(compiler); +executable_func = sljit_generate_code(compiler, 0, NULL); executable_size = sljit_get_generated_code_size(compiler); sljit_free_compiler(compiler); diff --git a/src/pcre2_jit_misc.c b/src/pcre2_jit_misc.c index bb6a558..c3abc0b 100644 --- a/src/pcre2_jit_misc.c +++ b/src/pcre2_jit_misc.c @@ -141,8 +141,8 @@ if (startsize == 0 || maxsize == 0 || maxsize > SIZE_MAX - STACK_GROWTH_RATE) return NULL; if (startsize > maxsize) startsize = maxsize; -startsize = (startsize + STACK_GROWTH_RATE - 1) & ~(STACK_GROWTH_RATE - 1); -maxsize = (maxsize + STACK_GROWTH_RATE - 1) & ~(STACK_GROWTH_RATE - 1); +startsize = (startsize + STACK_GROWTH_RATE - 1) & (size_t)(~(STACK_GROWTH_RATE - 1)); +maxsize = (maxsize + STACK_GROWTH_RATE - 1) & (size_t)(~(STACK_GROWTH_RATE - 1)); jit_stack = PRIV(memctl_malloc)(sizeof(pcre2_real_jit_stack), (pcre2_memctl *)gcontext); if (jit_stack == NULL) return NULL; diff --git a/src/pcre2_jit_simd_inc.h b/src/pcre2_jit_simd_inc.h index 783a85f..502977f 100644 --- a/src/pcre2_jit_simd_inc.h +++ b/src/pcre2_jit_simd_inc.h @@ -2176,7 +2176,7 @@ struct sljit_label *restart; struct sljit_jump *jump[2]; SLJIT_ASSERT(common->mode == PCRE2_JIT_COMPLETE && offs1 > offs2); -SLJIT_ASSERT(diff <= IN_UCHARS(max_fast_forward_char_pair_offset())); +SLJIT_ASSERT(diff <= (unsigned)IN_UCHARS(max_fast_forward_char_pair_offset())); /* Initialize. */ if (common->match_end_ptr != 0) diff --git a/src/pcre2_jit_test.c b/src/pcre2_jit_test.c index 54ce32f..6d95bb9 100644 --- a/src/pcre2_jit_test.c +++ b/src/pcre2_jit_test.c @@ -148,7 +148,7 @@ int main(void) #define F_PROPERTY 0x200000 struct regression_test_case { - int compile_options; + uint32_t compile_options; int newline; int match_options; int start_offset; @@ -276,6 +276,7 @@ static struct regression_test_case regression_test_cases[] = { { CM, A, 0, 0, "a1277|a1377|bX487", "bx487" }, { CM, A, 0, 0, "a1277|a1377|bx487", "bX487" }, { 0, A, 0, 0, "(a|)b*+a", "a" }, + { 0, A, 0, 0 | F_NOMATCH, "(.|.|.|.|.)(|.|.|.|.)(.||.|.|.)(.|.||.|.)(.|.|.||.)(.|.|.|.|)(A|.|.|.|.)(.|A|.|.|.)(.|.|A|.|.)(.|.|.|A|.)(.|.|.|.|A)(B|.|.|.|.)(.|B|.|.|.)(.|.|B|.|.)(.|.|.|B|.)(.|.|.|.|B)xa", "1234567890123456ax" }, /* Greedy and non-greedy ? operators. */ { MU, A, 0, 0, "(?:a)?a", "laab" }, @@ -395,6 +396,7 @@ static struct regression_test_case regression_test_cases[] = { { MU, A, 0, 0, "[\\x{10001}-\\x{10fffe}]+", "#\xc3\xa9\xe2\xb1\xa5\xf0\x90\x80\x80\xf0\x90\x80\x81\xf4\x8f\xbf\xbe\xf4\x8f\xbf\xbf" }, { MU, A, 0, 0, "[^\\x{10001}-\\x{10fffe}]+", "\xf0\x90\x80\x81#\xc3\xa9\xe2\xb1\xa5\xf0\x90\x80\x80\xf4\x8f\xbf\xbf\xf4\x8f\xbf\xbe" }, { CMU, A, 0, 0 | F_NOMATCH | F_PROPERTY, "^[\\x{100}-\\x{17f}]", " " }, + { M, A, 0, 0 | F_NOMATCH, "[^\\S\\W]{6}", "abcdefghijk" }, /* Unicode properties. */ { MUP, A, 0, 0, "[1-5\xc3\xa9\\w]", "\xc3\xa1_" }, @@ -1172,7 +1174,7 @@ static int regression_tests(void) int counter = 0; int jit_compile_mode; int utf = 0; - int disabled_options = 0; + uint32_t disabled_options = 0; int i; #ifdef SUPPORT_PCRE2_8 pcre2_code_8 *re8; @@ -1377,9 +1379,9 @@ static int regression_tests(void) ovector8_1 = pcre2_get_ovector_pointer_8(mdata8_1); ovector8_2 = pcre2_get_ovector_pointer_8(mdata8_2); for (i = 0; i < OVECTOR_SIZE * 2; ++i) - ovector8_1[i] = -2; + ovector8_1[i] = (PCRE2_SIZE)(-2); for (i = 0; i < OVECTOR_SIZE * 2; ++i) - ovector8_2[i] = -2; + ovector8_2[i] = (PCRE2_SIZE)(-2); pcre2_set_match_limit_8(mcontext8, 10000000); } if (re8) { @@ -1417,9 +1419,9 @@ static int regression_tests(void) ovector16_1 = pcre2_get_ovector_pointer_16(mdata16_1); ovector16_2 = pcre2_get_ovector_pointer_16(mdata16_2); for (i = 0; i < OVECTOR_SIZE * 2; ++i) - ovector16_1[i] = -2; + ovector16_1[i] = (PCRE2_SIZE)(-2); for (i = 0; i < OVECTOR_SIZE * 2; ++i) - ovector16_2[i] = -2; + ovector16_2[i] = (PCRE2_SIZE)(-2); pcre2_set_match_limit_16(mcontext16, 10000000); } if (re16) { @@ -1462,9 +1464,9 @@ static int regression_tests(void) ovector32_1 = pcre2_get_ovector_pointer_32(mdata32_1); ovector32_2 = pcre2_get_ovector_pointer_32(mdata32_2); for (i = 0; i < OVECTOR_SIZE * 2; ++i) - ovector32_1[i] = -2; + ovector32_1[i] = (PCRE2_SIZE)(-2); for (i = 0; i < OVECTOR_SIZE * 2; ++i) - ovector32_2[i] = -2; + ovector32_2[i] = (PCRE2_SIZE)(-2); pcre2_set_match_limit_32(mcontext32, 10000000); } if (re32) { @@ -1844,7 +1846,7 @@ static int check_invalid_utf_result(int pattern_index, const char *type, int res #define CPI (PCRE2_JIT_COMPLETE | PCRE2_JIT_PARTIAL_SOFT | PCRE2_JIT_INVALID_UTF) struct invalid_utf8_regression_test_case { - int compile_options; + uint32_t compile_options; int jit_compile_options; int start_offset; int skip_left; @@ -2135,7 +2137,7 @@ static int invalid_utf8_regression_tests(void) #define CPI (PCRE2_JIT_COMPLETE | PCRE2_JIT_PARTIAL_SOFT | PCRE2_JIT_INVALID_UTF) struct invalid_utf16_regression_test_case { - int compile_options; + uint32_t compile_options; int jit_compile_options; int start_offset; int skip_left; @@ -2343,7 +2345,7 @@ static int invalid_utf16_regression_tests(void) #define CPI (PCRE2_JIT_COMPLETE | PCRE2_JIT_PARTIAL_SOFT | PCRE2_JIT_INVALID_UTF) struct invalid_utf32_regression_test_case { - int compile_options; + uint32_t compile_options; int jit_compile_options; int start_offset; int skip_left; diff --git a/src/pcre2_match.c b/src/pcre2_match.c index b4a9703..6c422c2 100644 --- a/src/pcre2_match.c +++ b/src/pcre2_match.c @@ -5862,7 +5862,7 @@ fprintf(stderr, "++ %2ld op=%3d %s\n", Fecode - mb->start_code, *Fecode, { ptrdiff_t diff = Feptr - mb->start_subject; - uint32_t available = (diff > 65535)? 65535 : ((diff > 0)? diff : 0); + uint32_t available = (diff > 65535)? 65535 : ((diff > 0)? (int)diff : 0); if (Lmin > available) RRETURN(MATCH_NOMATCH); if (Lmax > available) Lmax = available; Feptr -= Lmax; diff --git a/src/pcre2_tables.c b/src/pcre2_tables.c index e00252f..097a1ac 100644 --- a/src/pcre2_tables.c +++ b/src/pcre2_tables.c @@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Original API code Copyright (c) 1997-2012 University of Cambridge - New API code Copyright (c) 2016-2021 University of Cambridge + New API code Copyright (c) 2016-2024 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -171,9 +171,9 @@ are implementing). 6. Do not break after Prepend characters. 7. Do not break within emoji modifier sequences or emoji zwj sequences. That - is, do not break between characters with the Extended_Pictographic property. - Extend and ZWJ characters are allowed between the characters; this cannot be - represented in this table, the code has to deal with it. + is, do not break between characters with the Extended_Pictographic property + if a ZWJ intervenes. Extend characters are allowed between the characters; + this cannot be represented in this table, the code has to deal with it. 8. Do not break within emoji flag sequences. That is, do not break between regional indicator (RI) symbols if there are an odd number of RI characters @@ -203,8 +203,8 @@ const uint32_t PRIV(ucp_gbtable)[] = { ESZ|(1u< 0) PCRE2_COMPILE(compiled_code, use_pbuffer, patlen, pat_patctl.options|use_forbid_utf, &errorcode, &erroroffset, use_pat_context); +/* If valgrind is supported, mark the pbuffer as accessible again. The 16-bit +and 32-bit buffers can be marked completely undefined, but we must leave the +pattern in the 8-bit buffer defined because it may be read from a callout +during matching. */ + +#ifdef SUPPORT_VALGRIND +#ifdef SUPPORT_PCRE2_8 +if (test_mode == PCRE8_MODE) + { + VALGRIND_MAKE_MEM_UNDEFINED(pbuffer8 + valgrind_access_length, + pbuffer8_size - valgrind_access_length); + } +#endif +#ifdef SUPPORT_PCRE2_16 +if (test_mode == PCRE16_MODE) + { + VALGRIND_MAKE_MEM_UNDEFINED(pbuffer16, pbuffer16_size); + } +#endif +#ifdef SUPPORT_PCRE2_32 +if (test_mode == PCRE32_MODE) + { + VALGRIND_MAKE_MEM_UNDEFINED(pbuffer32, pbuffer32_size); + } +#endif +#endif + /* Call the JIT compiler if requested. When timing, we must free and recompile the pattern each time because that is the only way to free the JIT compiled code. We know that compilation will always succeed. */ @@ -6012,44 +6058,29 @@ if (TEST(compiled_code, !=, NULL) && pat_patctl.jit != 0) start_time = clock(); PCRE2_JIT_COMPILE(jitrc, compiled_code, pat_patctl.jit); time_taken += clock() - start_time; + if (jitrc != 0) + { + fprintf(outfile, "JIT compilation was not successful"); + if (!print_error_message(jitrc, " (", ")\n")) return PR_ABEND; + break; + } } total_jit_compile_time += time_taken; - fprintf(outfile, "JIT compile %8.4f microseconds\n", - ((1000000 / CLOCKS_PER_SEC) * (double)time_taken) / timeit); + if (jitrc == 0) + fprintf(outfile, "JIT compile %8.4f microseconds\n", + ((1000000 / CLOCKS_PER_SEC) * (double)time_taken) / timeit); } else { PCRE2_JIT_COMPILE(jitrc, compiled_code, pat_patctl.jit); + if (jitrc != 0 && (pat_patctl.control & CTL_JITVERIFY) != 0) + { + fprintf(outfile, "JIT compilation was not successful"); + if (!print_error_message(jitrc, " (", ")\n")) return PR_ABEND; + } } } -/* If valgrind is supported, mark the pbuffer as accessible again. The 16-bit -and 32-bit buffers can be marked completely undefined, but we must leave the -pattern in the 8-bit buffer defined because it may be read from a callout -during matching. */ - -#ifdef SUPPORT_VALGRIND -#ifdef SUPPORT_PCRE2_8 -if (test_mode == PCRE8_MODE) - { - VALGRIND_MAKE_MEM_UNDEFINED(pbuffer8 + valgrind_access_length, - pbuffer8_size - valgrind_access_length); - } -#endif -#ifdef SUPPORT_PCRE2_16 -if (test_mode == PCRE16_MODE) - { - VALGRIND_MAKE_MEM_UNDEFINED(pbuffer16, pbuffer16_size); - } -#endif -#ifdef SUPPORT_PCRE2_32 -if (test_mode == PCRE32_MODE) - { - VALGRIND_MAKE_MEM_UNDEFINED(pbuffer32, pbuffer32_size); - } -#endif -#endif - /* Compilation failed; go back for another re, skipping to blank line if non-interactive. */ @@ -9397,11 +9428,11 @@ max_oveccount = DEFAULT_OVECCOUNT; #define CONTEXTTESTS \ (void)G(pcre2_set_compile_extra_options_,BITS)(G(pat_context,BITS), 0); \ (void)G(pcre2_set_max_pattern_length_,BITS)(G(pat_context,BITS), 0); \ + (void)G(pcre2_set_max_pattern_compiled_length_,BITS)(G(pat_context,BITS), 0); \ (void)G(pcre2_set_max_varlookbehind_,BITS)(G(pat_context,BITS), 0); \ (void)G(pcre2_set_offset_limit_,BITS)(G(dat_context,BITS), 0); \ (void)G(pcre2_get_match_data_size_,BITS)(G(match_data,BITS)) - /* Call the appropriate functions for the current mode, and exercise some functions that are not otherwise called. */ diff --git a/src/sljit/allocator_src/sljitExecAllocatorApple.c b/src/sljit/allocator_src/sljitExecAllocatorApple.c index 95b9842..9bd2094 100644 --- a/src/sljit/allocator_src/sljitExecAllocatorApple.c +++ b/src/sljit/allocator_src/sljitExecAllocatorApple.c @@ -41,9 +41,10 @@ #include #include -#define SLJIT_MAP_JIT (get_map_jit_flag()) #define SLJIT_UPDATE_WX_FLAGS(from, to, enable_exec) +#ifdef MAP_JIT +#define SLJIT_MAP_JIT (get_map_jit_flag()) static SLJIT_INLINE int get_map_jit_flag(void) { size_t page_size; @@ -70,6 +71,9 @@ static SLJIT_INLINE int get_map_jit_flag(void) } return map_jit_flag; } +#else /* !defined(MAP_JIT) */ +#define SLJIT_MAP_JIT (0) +#endif #elif defined(SLJIT_CONFIG_ARM) && SLJIT_CONFIG_ARM diff --git a/src/sljit/allocator_src/sljitExecAllocatorCore.c b/src/sljit/allocator_src/sljitExecAllocatorCore.c index 6cd3911..4e1119b 100644 --- a/src/sljit/allocator_src/sljitExecAllocatorCore.c +++ b/src/sljit/allocator_src/sljitExecAllocatorCore.c @@ -181,8 +181,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size) header->executable_offset = free_block->header.executable_offset; #endif /* SLJIT_HAS_EXECUTABLE_OFFSET */ AS_BLOCK_HEADER(header, size)->prev_size = size; - } - else { + } else { sljit_remove_free_block(free_block); header = (struct block_header*)free_block; size = chunk_size; @@ -230,26 +229,25 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size) #endif /* SLJIT_HAS_EXECUTABLE_OFFSET */ sljit_insert_free_block(free_block, chunk_size); next_header = AS_BLOCK_HEADER(free_block, chunk_size); - } - else { + } else { /* All space belongs to this allocation. */ allocated_size += chunk_size; header->size = chunk_size; next_header = AS_BLOCK_HEADER(header, chunk_size); } - SLJIT_ALLOCATOR_UNLOCK(); next_header->size = 1; next_header->prev_size = chunk_size; #ifdef SLJIT_HAS_EXECUTABLE_OFFSET next_header->executable_offset = executable_offset; #endif /* SLJIT_HAS_EXECUTABLE_OFFSET */ + SLJIT_ALLOCATOR_UNLOCK(); return MEM_START(header); } -SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr) +SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void *ptr) { struct block_header *header; - struct free_block* free_block; + struct free_block *free_block; SLJIT_ALLOCATOR_LOCK(); header = AS_BLOCK_HEADER(ptr, -(sljit_sw)sizeof(struct block_header)); @@ -269,8 +267,7 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr) free_block->size += header->size; header = AS_BLOCK_HEADER(free_block, free_block->size); header->prev_size = free_block->size; - } - else { + } else { free_block = (struct free_block*)header; sljit_insert_free_block(free_block, header->size); } @@ -308,7 +305,7 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void) free_block = free_blocks; while (free_block) { next_free_block = free_block->next; - if (!free_block->header.prev_size && + 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); @@ -317,14 +314,14 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void) free_block = next_free_block; } - SLJIT_ASSERT((total_size && free_blocks) || (!total_size && !free_blocks)); + SLJIT_ASSERT(total_size || (!total_size && !free_blocks)); SLJIT_UPDATE_WX_FLAGS(NULL, NULL, 1); SLJIT_ALLOCATOR_UNLOCK(); } #ifdef SLJIT_HAS_EXECUTABLE_OFFSET -SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr) +SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void *code) { - return ((struct block_header *)(ptr))[-1].executable_offset; + return ((struct block_header*)SLJIT_CODE_TO_PTR(code))[-1].executable_offset; } #endif /* SLJIT_HAS_EXECUTABLE_OFFSET */ diff --git a/src/sljit/sljitConfigInternal.h b/src/sljit/sljitConfigInternal.h index ce4e7b0..de06dd8 100644 --- a/src/sljit/sljitConfigInternal.h +++ b/src/sljit/sljitConfigInternal.h @@ -49,8 +49,8 @@ extern "C" { sljit_s16, sljit_u16 : signed and unsigned 16 bit integer type sljit_s32, sljit_u32 : 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_sp, sljit_up : signed and unsigned pointer value (usually the same as + sljit_uw, but some 64 bit ABIs may use 32 bit pointers) sljit_f32 : 32 bit single precision floating point value sljit_f64 : 64 bit double precision floating point value @@ -98,6 +98,10 @@ extern "C" { SLJIT_TMP_R(i) : accessing temporary registers SLJIT_TMP_FR0 .. FR9 : accessing temporary floating point registers SLJIT_TMP_FR(i) : accessing temporary floating point registers + SLJIT_TMP_DEST_REG : a temporary register for results + SLJIT_TMP_MEM_REG : a temporary base register for accessing memory + (can be the same as SLJIT_TMP_DEST_REG) + SLJIT_TMP_DEST_FREG : a temporary register for float results SLJIT_FUNC : calling convention attribute for both calling JIT from C and C calling back from JIT SLJIT_W(number) : defining 64 bit constants on 64 bit architectures (platform independent helper) SLJIT_F64_SECOND(reg) : provides the register index of the second 32 bit part of a 64 bit @@ -132,23 +136,23 @@ extern "C" { */ #ifndef SLJIT_MALLOC -#define SLJIT_MALLOC(size, allocator_data) malloc(size) +#define SLJIT_MALLOC(size, allocator_data) (malloc(size)) #endif #ifndef SLJIT_FREE -#define SLJIT_FREE(ptr, allocator_data) free(ptr) +#define SLJIT_FREE(ptr, allocator_data) (free(ptr)) #endif #ifndef SLJIT_MEMCPY -#define SLJIT_MEMCPY(dest, src, len) memcpy(dest, src, len) +#define SLJIT_MEMCPY(dest, src, len) (memcpy(dest, src, len)) #endif #ifndef SLJIT_MEMMOVE -#define SLJIT_MEMMOVE(dest, src, len) memmove(dest, src, len) +#define SLJIT_MEMMOVE(dest, src, len) (memmove(dest, src, len)) #endif #ifndef SLJIT_ZEROMEM -#define SLJIT_ZEROMEM(dest, len) memset(dest, 0, len) +#define SLJIT_ZEROMEM(dest, len) (memset(dest, 0, len)) #endif /***************************/ @@ -198,7 +202,7 @@ extern "C" { /* Type of public API functions. */ /*********************************/ -#ifndef SLJIT_API_FUNC_ATTRIBUTE +#ifndef SLJIT_API_FUNC_ATTRIBUTE #if (defined SLJIT_CONFIG_STATIC && SLJIT_CONFIG_STATIC) /* Static ABI functions. For all-in-one programs. */ @@ -358,7 +362,8 @@ typedef long int sljit_sw; #endif /* _WIN32 */ #endif -typedef sljit_uw sljit_p; +typedef sljit_sw sljit_sp; +typedef sljit_uw sljit_up; /* Floating point types. */ typedef float sljit_f32; @@ -399,6 +404,10 @@ typedef double sljit_f64; #define SLJIT_CONV_MAX_FLOAT SLJIT_CONV_RESULT_MAX_INT #define SLJIT_CONV_MIN_FLOAT SLJIT_CONV_RESULT_MIN_INT #define SLJIT_CONV_NAN_FLOAT SLJIT_CONV_RESULT_MIN_INT +#elif (defined SLJIT_CONFIG_LOONGARCH && SLJIT_CONFIG_LOONGARCH) +#define SLJIT_CONV_MAX_FLOAT SLJIT_CONV_RESULT_MAX_INT +#define SLJIT_CONV_MIN_FLOAT SLJIT_CONV_RESULT_MIN_INT +#define SLJIT_CONV_NAN_FLOAT SLJIT_CONV_RESULT_ZERO #else #error "Result for float to integer conversion is not defined" #endif @@ -522,19 +531,6 @@ typedef double sljit_f64; #define SLJIT_FUNC #endif /* !SLJIT_FUNC */ -/* Disable instrumentation for these functions as they may not be sound */ -#ifndef SLJIT_FUNC_ATTRIBUTE -#if defined(__has_feature) -#if __has_feature(memory_sanitizer) -#define SLJIT_FUNC_ATTRIBUTE __attribute__((no_sanitize("memory"))) -#endif /* __has_feature(memory_sanitizer) */ -#endif /* defined(__has_feature) */ -#endif - -#ifndef SLJIT_FUNC_ATTRIBUTE -#define SLJIT_FUNC_ATTRIBUTE -#endif - #ifndef SLJIT_INDIRECT_CALL #if ((defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) && (!defined _CALL_ELF || _CALL_ELF == 1)) \ || ((defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) && defined _AIX) @@ -570,9 +566,9 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void); #endif /* SLJIT_FREE_EXEC */ #if (defined SLJIT_PROT_EXECUTABLE_ALLOCATOR && SLJIT_PROT_EXECUTABLE_ALLOCATOR) -SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr); -#define SLJIT_EXEC_OFFSET(ptr) sljit_exec_offset(ptr) -#endif +SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void *code); +#define SLJIT_EXEC_OFFSET(code) sljit_exec_offset(code) +#endif /* SLJIT_PROT_EXECUTABLE_ALLOCATOR */ #endif /* SLJIT_EXECUTABLE_ALLOCATOR */ @@ -592,6 +588,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr); #define SLJIT_NUMBER_OF_FLOAT_REGISTERS 7 #define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 0 #define SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS 1 +#define SLJIT_TMP_DEST_REG SLJIT_TMP_R0 +#define SLJIT_TMP_MEM_REG SLJIT_TMP_R0 +#define SLJIT_TMP_DEST_FREG SLJIT_TMP_FR0 #define SLJIT_LOCALS_OFFSET_BASE (8 * SSIZE_OF(sw)) #define SLJIT_PREF_SHIFT_REG SLJIT_R2 #define SLJIT_MASKED_SHIFT 1 @@ -612,6 +611,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr); #define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 10 #define SLJIT_LOCALS_OFFSET_BASE (4 * SSIZE_OF(sw)) #endif /* !_WIN64 */ +#define SLJIT_TMP_DEST_REG SLJIT_TMP_R0 +#define SLJIT_TMP_MEM_REG SLJIT_TMP_R0 +#define SLJIT_TMP_DEST_FREG SLJIT_TMP_FR0 #define SLJIT_PREF_SHIFT_REG SLJIT_R3 #define SLJIT_MASKED_SHIFT 1 #define SLJIT_MASKED_SHIFT32 1 @@ -624,6 +626,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr); #define SLJIT_NUMBER_OF_FLOAT_REGISTERS 14 #define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 8 #define SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS 2 +#define SLJIT_TMP_DEST_REG SLJIT_TMP_R1 +#define SLJIT_TMP_MEM_REG SLJIT_TMP_R1 +#define SLJIT_TMP_DEST_FREG SLJIT_TMP_FR0 #define SLJIT_LOCALS_OFFSET_BASE 0 #elif (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) @@ -634,6 +639,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr); #define SLJIT_NUMBER_OF_FLOAT_REGISTERS 30 #define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 8 #define SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS 2 +#define SLJIT_TMP_DEST_REG SLJIT_TMP_R0 +#define SLJIT_TMP_MEM_REG SLJIT_TMP_R0 +#define SLJIT_TMP_DEST_FREG SLJIT_TMP_FR0 #define SLJIT_LOCALS_OFFSET_BASE (2 * (sljit_s32)sizeof(sljit_sw)) #define SLJIT_MASKED_SHIFT 1 #define SLJIT_MASKED_SHIFT32 1 @@ -646,6 +654,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr); #define SLJIT_NUMBER_OF_FLOAT_REGISTERS 30 #define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 18 #define SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS 2 +#define SLJIT_TMP_DEST_REG SLJIT_TMP_R1 +#define SLJIT_TMP_MEM_REG SLJIT_TMP_R1 +#define SLJIT_TMP_DEST_FREG SLJIT_TMP_FR0 #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) || (defined _AIX) #define SLJIT_LOCALS_OFFSET_BASE ((6 + 8) * (sljit_s32)sizeof(sljit_sw)) #elif (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) @@ -670,6 +681,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr); #endif #define SLJIT_NUMBER_OF_TEMPORARY_REGISTERS 5 #define SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS 3 +#define SLJIT_TMP_DEST_REG SLJIT_TMP_R1 +#define SLJIT_TMP_MEM_REG SLJIT_TMP_R1 +#define SLJIT_TMP_DEST_FREG SLJIT_TMP_FR0 #define SLJIT_MASKED_SHIFT 1 #define SLJIT_MASKED_SHIFT32 1 @@ -681,6 +695,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr); #define SLJIT_NUMBER_OF_FLOAT_REGISTERS 30 #define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 12 #define SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS 2 +#define SLJIT_TMP_DEST_REG SLJIT_TMP_R1 +#define SLJIT_TMP_MEM_REG SLJIT_TMP_R1 +#define SLJIT_TMP_DEST_FREG SLJIT_TMP_FR0 #define SLJIT_LOCALS_OFFSET_BASE 0 #define SLJIT_MASKED_SHIFT 1 #define SLJIT_MASKED_SHIFT32 1 @@ -714,6 +731,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr); #define SLJIT_NUMBER_OF_FLOAT_REGISTERS 15 #define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 8 #define SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS 1 +#define SLJIT_TMP_DEST_REG SLJIT_TMP_R0 +#define SLJIT_TMP_MEM_REG SLJIT_TMP_R2 +#define SLJIT_TMP_DEST_FREG SLJIT_TMP_FR0 #define SLJIT_LOCALS_OFFSET_BASE SLJIT_S390X_DEFAULT_STACK_FRAME_SIZE #define SLJIT_MASKED_SHIFT 1 @@ -725,6 +745,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr); #define SLJIT_NUMBER_OF_FLOAT_REGISTERS 30 #define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 12 #define SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS 2 +#define SLJIT_TMP_DEST_REG SLJIT_TMP_R1 +#define SLJIT_TMP_MEM_REG SLJIT_TMP_R1 +#define SLJIT_TMP_DEST_FREG SLJIT_TMP_FR0 #define SLJIT_LOCALS_OFFSET_BASE 0 #define SLJIT_MASKED_SHIFT 1 #define SLJIT_MASKED_SHIFT32 1 @@ -738,6 +761,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr); #define SLJIT_NUMBER_OF_FLOAT_REGISTERS 0 #define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 0 #define SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS 0 +#define SLJIT_TMP_DEST_REG 0 +#define SLJIT_TMP_MEM_REG 0 +#define SLJIT_TMP_DEST_FREG 0 #define SLJIT_LOCALS_OFFSET_BASE 0 #endif diff --git a/src/sljit/sljitLir.c b/src/sljit/sljitLir.c index 6f19300..2dca17c 100644 --- a/src/sljit/sljitLir.c +++ b/src/sljit/sljitLir.c @@ -152,28 +152,43 @@ #define SLJIT_SIMD_TYPE_MASK2(m) ((sljit_s32)0xc0000fff & ~(SLJIT_SIMD_FLOAT | SLJIT_SIMD_TEST | (m))) /* Jump flags. */ -#define JUMP_LABEL 0x1 -#define JUMP_ADDR 0x2 +#define JUMP_ADDR 0x1 +#define JUMP_MOV_ADDR 0x2 /* SLJIT_REWRITABLE_JUMP is 0x1000. */ #if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) -# define PATCH_MB 0x4 -# define PATCH_MW 0x8 +# define PATCH_MB 0x04 +# define PATCH_MW 0x08 #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) # define PATCH_MD 0x10 -#endif +# define MOV_ADDR_HI 0x20 +# define JUMP_MAX_SIZE ((sljit_uw)(10 + 3)) +# define CJUMP_MAX_SIZE ((sljit_uw)(2 + 10 + 3)) +#else /* !SLJIT_CONFIG_X86_64 */ +# define JUMP_MAX_SIZE ((sljit_uw)5) +# define CJUMP_MAX_SIZE ((sljit_uw)6) +#endif /* SLJIT_CONFIG_X86_64 */ # define TYPE_SHIFT 13 +#if (defined SLJIT_DEBUG && SLJIT_DEBUG) +/* Bits 7..12 is for debug jump size, SLJIT_REWRITABLE_JUMP is 0x1000 */ +# define JUMP_SIZE_SHIFT 7 +#endif /* SLJIT_DEBUG */ #endif /* SLJIT_CONFIG_X86 */ #if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) || (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) -# define IS_BL 0x4 -# define PATCH_B 0x8 -#endif /* SLJIT_CONFIG_ARM_V6 || SLJIT_CONFIG_ARM_V6 */ +# define IS_BL 0x04 +# define PATCH_B 0x08 +#endif /* SLJIT_CONFIG_ARM_V6 || SLJIT_CONFIG_ARM_V7 */ #if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) # define CPOOL_SIZE 512 #endif /* SLJIT_CONFIG_ARM_V6 */ +#if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) +# define JUMP_SIZE_SHIFT 26 +# define JUMP_MAX_SIZE ((sljit_uw)3) +#endif /* SLJIT_CONFIG_ARM_V7 */ + #if (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2) # define IS_COND 0x04 # define IS_BL 0x08 @@ -181,25 +196,30 @@ # define PATCH_TYPE1 0x10 /* conditional + imm20 */ # define PATCH_TYPE2 0x20 - /* IT + imm24 */ -# define PATCH_TYPE3 0x30 /* imm11 */ -# define PATCH_TYPE4 0x40 +# define PATCH_TYPE3 0x30 /* imm24 */ -# define PATCH_TYPE5 0x50 +# define PATCH_TYPE4 0x40 /* BL + imm24 */ -# define PATCH_BL 0x60 +# define PATCH_TYPE5 0x50 + /* addwi/subwi */ +# define PATCH_TYPE6 0x60 /* 0xf00 cc code for branches */ +# define JUMP_SIZE_SHIFT 26 +# define JUMP_MAX_SIZE ((sljit_uw)5) #endif /* SLJIT_CONFIG_ARM_THUMB2 */ #if (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) # define IS_COND 0x004 # define IS_CBZ 0x008 # define IS_BL 0x010 -# define PATCH_B 0x020 -# define PATCH_COND 0x040 -# define PATCH_ABS48 0x080 -# define PATCH_ABS64 0x100 +# define PATCH_COND 0x020 +# define PATCH_B 0x040 +# define PATCH_B32 0x080 +# define PATCH_ABS48 0x100 +# define PATCH_ABS64 0x200 +# define JUMP_SIZE_SHIFT 58 +# define JUMP_MAX_SIZE ((sljit_uw)5) #endif /* SLJIT_CONFIG_ARM_64 */ #if (defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC) @@ -210,8 +230,12 @@ #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) # define PATCH_ABS32 0x040 # define PATCH_ABS48 0x080 +# define JUMP_SIZE_SHIFT 58 +# define JUMP_MAX_SIZE ((sljit_uw)7) +#else /* !SLJIT_CONFIG_PPC_64 */ +# define JUMP_SIZE_SHIFT 26 +# define JUMP_MAX_SIZE ((sljit_uw)4) #endif /* SLJIT_CONFIG_PPC_64 */ -# define REMOVE_COND 0x100 #endif /* SLJIT_CONFIG_PPC */ #if (defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS) @@ -253,8 +277,11 @@ # define PATCH_ABS32 0x080 # define PATCH_ABS44 0x100 # define PATCH_ABS52 0x200 +# define JUMP_SIZE_SHIFT 58 +# define JUMP_MAX_SIZE ((sljit_uw)6) #else /* !SLJIT_CONFIG_RISCV_64 */ -# define PATCH_REL32 0x0 +# define JUMP_SIZE_SHIFT 26 +# define JUMP_MAX_SIZE ((sljit_uw)2) #endif /* SLJIT_CONFIG_RISCV_64 */ #endif /* SLJIT_CONFIG_RISCV */ @@ -268,6 +295,8 @@ # define PATCH_REL32 0x040 # define PATCH_ABS32 0x080 # define PATCH_ABS52 0x100 +# define JUMP_SIZE_SHIFT 58 +# define JUMP_MAX_SIZE ((sljit_uw)4) #endif /* SLJIT_CONFIG_LOONGARCH */ /* Stack management. */ @@ -289,6 +318,14 @@ /* Utils can still be used even if SLJIT_CONFIG_UNSUPPORTED is set. */ #include "sljitUtils.c" +#if (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2) +#define SLJIT_CODE_TO_PTR(code) ((void*)((sljit_up)(code) & ~(sljit_up)0x1)) +#elif (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL) +#define SLJIT_CODE_TO_PTR(code) ((void*)(*(sljit_up*)code)) +#else /* !SLJIT_CONFIG_ARM_THUMB2 && !SLJIT_INDIRECT_CALL */ +#define SLJIT_CODE_TO_PTR(code) ((void*)(code)) +#endif /* SLJIT_CONFIG_ARM_THUMB2 || SLJIT_INDIRECT_CALL */ + #if !(defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED) #if (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR) @@ -417,7 +454,7 @@ static sljit_s32 compiler_initialized = 0; static void init_compiler(void); #endif -SLJIT_API_FUNC_ATTRIBUTE struct sljit_compiler* sljit_create_compiler(void *allocator_data, void *exec_allocator_data) +SLJIT_API_FUNC_ATTRIBUTE struct sljit_compiler* sljit_create_compiler(void *allocator_data) { struct sljit_compiler *compiler = (struct sljit_compiler*)SLJIT_MALLOC(sizeof(struct sljit_compiler), allocator_data); if (!compiler) @@ -428,10 +465,11 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_compiler* sljit_create_compiler(void *allo sizeof(sljit_s8) == 1 && sizeof(sljit_u8) == 1 && sizeof(sljit_s16) == 2 && sizeof(sljit_u16) == 2 && sizeof(sljit_s32) == 4 && sizeof(sljit_u32) == 4 - && (sizeof(sljit_p) == 4 || sizeof(sljit_p) == 8) - && sizeof(sljit_p) <= sizeof(sljit_sw) + && (sizeof(sljit_up) == 4 || sizeof(sljit_up) == 8) + && sizeof(sljit_up) <= sizeof(sljit_sw) + && sizeof(sljit_up) == sizeof(sljit_sp) && (sizeof(sljit_sw) == 4 || sizeof(sljit_sw) == 8) - && (sizeof(sljit_uw) == 4 || sizeof(sljit_uw) == 8), + && (sizeof(sljit_uw) == sizeof(sljit_sw)), invalid_integer_types); SLJIT_COMPILE_ASSERT(SLJIT_REWRITABLE_JUMP != SLJIT_32, rewritable_jump_and_single_op_must_not_be_the_same); @@ -442,7 +480,6 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_compiler* sljit_create_compiler(void *allo compiler->error = SLJIT_SUCCESS; compiler->allocator_data = allocator_data; - compiler->exec_allocator_data = exec_allocator_data; compiler->buf = (struct sljit_memory_fragment*)SLJIT_MALLOC(BUF_SIZE, allocator_data); compiler->abuf = (struct sljit_memory_fragment*)SLJIT_MALLOC(ABUF_SIZE, allocator_data); @@ -537,37 +574,17 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_compiler_memory_error(struct sljit_compi compiler->error = SLJIT_ERR_ALLOC_FAILED; } -#if (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2) SLJIT_API_FUNC_ATTRIBUTE void sljit_free_code(void* code, void *exec_allocator_data) { SLJIT_UNUSED_ARG(exec_allocator_data); - /* Remove thumb mode flag. */ - SLJIT_FREE_EXEC((void*)((sljit_uw)code & ~(sljit_uw)0x1), exec_allocator_data); + SLJIT_FREE_EXEC(SLJIT_CODE_TO_PTR(code), exec_allocator_data); } -#elif (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL) -SLJIT_API_FUNC_ATTRIBUTE void sljit_free_code(void* code, void *exec_allocator_data) -{ - SLJIT_UNUSED_ARG(exec_allocator_data); - - /* Resolve indirection. */ - code = (void*)(*(sljit_uw*)code); - SLJIT_FREE_EXEC(code, exec_allocator_data); -} -#else -SLJIT_API_FUNC_ATTRIBUTE void sljit_free_code(void* code, void *exec_allocator_data) -{ - SLJIT_UNUSED_ARG(exec_allocator_data); - - SLJIT_FREE_EXEC(code, exec_allocator_data); -} -#endif SLJIT_API_FUNC_ATTRIBUTE void sljit_set_label(struct sljit_jump *jump, struct sljit_label* label) { if (SLJIT_LIKELY(!!jump) && SLJIT_LIKELY(!!label)) { jump->flags &= (sljit_uw)~JUMP_ADDR; - jump->flags |= JUMP_LABEL; jump->u.label = label; } } @@ -575,18 +592,11 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_label(struct sljit_jump *jump, struct sl SLJIT_API_FUNC_ATTRIBUTE void sljit_set_target(struct sljit_jump *jump, sljit_uw target) { if (SLJIT_LIKELY(!!jump)) { - jump->flags &= (sljit_uw)~JUMP_LABEL; jump->flags |= JUMP_ADDR; jump->u.target = target; } } -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_put_label(struct sljit_put_label *put_label, struct sljit_label *label) -{ - if (SLJIT_LIKELY(!!put_label)) - put_label->label = label; -} - #define SLJIT_CURRENT_FLAGS_ALL \ (SLJIT_CURRENT_FLAGS_32 | SLJIT_CURRENT_FLAGS_ADD | SLJIT_CURRENT_FLAGS_SUB | SLJIT_CURRENT_FLAGS_COMPARE) @@ -681,31 +691,66 @@ static SLJIT_INLINE void reverse_buf(struct sljit_compiler *compiler) compiler->buf = prev; } -/* Only used in RISC architectures where the instruction size is constant */ -#if !(defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) \ - && !(defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X) - -static SLJIT_INLINE sljit_uw compute_next_addr(struct sljit_label *label, struct sljit_jump *jump, - struct sljit_const *const_, struct sljit_put_label *put_label) +static SLJIT_INLINE void* allocate_executable_memory(sljit_uw size, sljit_s32 options, + void *exec_allocator_data, sljit_sw *executable_offset) { - sljit_uw result = ~(sljit_uw)0; + void *code; + struct sljit_generate_code_buffer *buffer; + + if (SLJIT_LIKELY(!(options & SLJIT_GENERATE_CODE_BUFFER))) { + code = SLJIT_MALLOC_EXEC(size, exec_allocator_data); + *executable_offset = SLJIT_EXEC_OFFSET(code); + return code; + } + + buffer = (struct sljit_generate_code_buffer*)exec_allocator_data; + + if (size <= buffer->size) { + *executable_offset = buffer->executable_offset; + return buffer->buffer; + } + + return NULL; +} + +#define SLJIT_MAX_ADDRESS ~(sljit_uw)0 + +#define SLJIT_GET_NEXT_SIZE(ptr) (ptr != NULL) ? ((ptr)->size) : SLJIT_MAX_ADDRESS +#define SLJIT_GET_NEXT_ADDRESS(ptr) (ptr != NULL) ? ((ptr)->addr) : SLJIT_MAX_ADDRESS + +#if !(defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) + +#define SLJIT_NEXT_DEFINE_TYPES \ + sljit_uw next_label_size; \ + sljit_uw next_jump_addr; \ + sljit_uw next_const_addr; \ + sljit_uw next_min_addr + +#define SLJIT_NEXT_INIT_TYPES() \ + next_label_size = SLJIT_GET_NEXT_SIZE(label); \ + next_jump_addr = SLJIT_GET_NEXT_ADDRESS(jump); \ + next_const_addr = SLJIT_GET_NEXT_ADDRESS(const_); - if (label) - result = label->size; +#define SLJIT_GET_NEXT_MIN() \ + next_min_addr = sljit_get_next_min(next_label_size, next_jump_addr, next_const_addr); - if (jump && jump->addr < result) - result = jump->addr; +static SLJIT_INLINE sljit_uw sljit_get_next_min(sljit_uw next_label_size, + sljit_uw next_jump_addr, sljit_uw next_const_addr) +{ + sljit_uw result = next_jump_addr; + + SLJIT_ASSERT(result == SLJIT_MAX_ADDRESS || result != next_const_addr); - if (const_ && const_->addr < result) - result = const_->addr; + if (next_const_addr < result) + result = next_const_addr; - if (put_label && put_label->addr < result) - result = put_label->addr; + if (next_label_size < result) + result = next_label_size; return result; } -#endif /* !SLJIT_CONFIG_X86 && !SLJIT_CONFIG_S390X */ +#endif /* !SLJIT_CONFIG_X86 */ static SLJIT_INLINE void set_emit_enter(struct sljit_compiler *compiler, sljit_s32 options, sljit_s32 args, sljit_s32 scratches, sljit_s32 saveds, @@ -746,8 +791,9 @@ static SLJIT_INLINE void set_set_context(struct sljit_compiler *compiler, static SLJIT_INLINE void set_label(struct sljit_label *label, struct sljit_compiler *compiler) { label->next = NULL; + label->u.index = compiler->label_count++; label->size = compiler->size; - if (compiler->last_label) + if (compiler->last_label != NULL) compiler->last_label->next = label; else compiler->labels = label; @@ -758,7 +804,21 @@ static SLJIT_INLINE void set_jump(struct sljit_jump *jump, struct sljit_compiler { jump->next = NULL; jump->flags = flags; - if (compiler->last_jump) + jump->u.label = NULL; + if (compiler->last_jump != NULL) + compiler->last_jump->next = jump; + else + compiler->jumps = jump; + compiler->last_jump = jump; +} + +static SLJIT_INLINE void set_mov_addr(struct sljit_jump *jump, struct sljit_compiler *compiler, sljit_uw offset) +{ + jump->next = NULL; + jump->addr = compiler->size - offset; + jump->flags = JUMP_MOV_ADDR; + jump->u.label = NULL; + if (compiler->last_jump != NULL) compiler->last_jump->next = jump; else compiler->jumps = jump; @@ -769,26 +829,13 @@ static SLJIT_INLINE void set_const(struct sljit_const *const_, struct sljit_comp { const_->next = NULL; const_->addr = compiler->size; - if (compiler->last_const) + if (compiler->last_const != NULL) compiler->last_const->next = const_; else compiler->consts = const_; compiler->last_const = const_; } -static SLJIT_INLINE void set_put_label(struct sljit_put_label *put_label, struct sljit_compiler *compiler, sljit_uw offset) -{ - put_label->next = NULL; - put_label->label = NULL; - put_label->addr = compiler->size - offset; - put_label->flags = 0; - if (compiler->last_put_label) - compiler->last_put_label->next = put_label; - else - compiler->put_labels = put_label; - compiler->last_put_label = put_label; -} - #define ADDRESSING_DEPENDS_ON(exp, reg) \ (((exp) & SLJIT_MEM) && (((exp) & REG_MASK) == reg || OFFS_REG(exp) == reg)) @@ -1106,6 +1153,10 @@ static const char* op2_names[] = { "ashr", "mashr", "rotl", "rotr" }; +static const char* op2r_names[] = { + "muladd" +}; + static const char* op_src_dst_names[] = { "fast_return", "skip_frames_before_fast_return", "prefetch_l1", "prefetch_l2", @@ -1187,13 +1238,19 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_generate_code(struct sljit_com jump = compiler->jumps; while (jump) { /* All jumps have target. */ - CHECK_ARGUMENT(jump->flags & (JUMP_LABEL | JUMP_ADDR)); + CHECK_ARGUMENT((jump->flags & JUMP_ADDR) || jump->u.label != NULL); jump = jump->next; } #endif CHECK_RETURN_OK; } +#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) +#define SLJIT_ENTER_CPU_SPECIFIC_OPTIONS (SLJIT_ENTER_USE_VEX) +#else /* !SLJIT_CONFIG_X86 */ +#define SLJIT_ENTER_CPU_SPECIFIC_OPTIONS (0) +#endif /* !SLJIT_CONFIG_X86 */ + static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_enter(struct sljit_compiler *compiler, sljit_s32 options, sljit_s32 arg_types, sljit_s32 scratches, sljit_s32 saveds, sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size) @@ -1202,9 +1259,9 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_enter(struct sljit_compil #if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) if (options & SLJIT_ENTER_REG_ARG) { - CHECK_ARGUMENT(!(options & ~(0x3 | SLJIT_ENTER_REG_ARG))); + CHECK_ARGUMENT(!(options & ~(0x3 | SLJIT_ENTER_REG_ARG | SLJIT_ENTER_CPU_SPECIFIC_OPTIONS))); } else { - CHECK_ARGUMENT(options == 0); + CHECK_ARGUMENT((options & ~SLJIT_ENTER_CPU_SPECIFIC_OPTIONS) == 0); } CHECK_ARGUMENT(SLJIT_KEPT_SAVEDS_COUNT(options) <= 3 && SLJIT_KEPT_SAVEDS_COUNT(options) <= saveds); CHECK_ARGUMENT(scratches >= 0 && scratches <= SLJIT_NUMBER_OF_REGISTERS); @@ -1238,11 +1295,17 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_enter(struct sljit_compil fprintf(compiler->verbose, "],"); if (options & SLJIT_ENTER_REG_ARG) { - fprintf(compiler->verbose, " enter:reg_arg,"); - if (SLJIT_KEPT_SAVEDS_COUNT(options) > 0) - fprintf(compiler->verbose, " keep:%d,", SLJIT_KEPT_SAVEDS_COUNT(options)); + fprintf(compiler->verbose, " opt:reg_arg(%d),", SLJIT_KEPT_SAVEDS_COUNT(options)); + else + fprintf(compiler->verbose, " opt:reg_arg,"); + } + +#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) + if (options & SLJIT_ENTER_USE_VEX) { + fprintf(compiler->verbose, " opt:use_vex,"); } +#endif /* !SLJIT_CONFIG_X86 */ fprintf(compiler->verbose, " scratches:%d, saveds:%d, fscratches:%d, fsaveds:%d, local_size:%d\n", scratches, saveds, fscratches, fsaveds, local_size); @@ -1259,9 +1322,9 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_set_context(struct sljit_compi #if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) if (options & SLJIT_ENTER_REG_ARG) { - CHECK_ARGUMENT(!(options & ~(0x3 | SLJIT_ENTER_REG_ARG))); + CHECK_ARGUMENT(!(options & ~(0x3 | SLJIT_ENTER_REG_ARG | SLJIT_ENTER_CPU_SPECIFIC_OPTIONS))); } else { - CHECK_ARGUMENT(options == 0); + CHECK_ARGUMENT((options & ~SLJIT_ENTER_CPU_SPECIFIC_OPTIONS) == 0); } CHECK_ARGUMENT(SLJIT_KEPT_SAVEDS_COUNT(options) <= 3 && SLJIT_KEPT_SAVEDS_COUNT(options) <= saveds); CHECK_ARGUMENT(scratches >= 0 && scratches <= SLJIT_NUMBER_OF_REGISTERS); @@ -1295,11 +1358,17 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_set_context(struct sljit_compi fprintf(compiler->verbose, "],"); if (options & SLJIT_ENTER_REG_ARG) { - fprintf(compiler->verbose, " enter:reg_arg,"); - if (SLJIT_KEPT_SAVEDS_COUNT(options) > 0) - fprintf(compiler->verbose, " keep:%d,", SLJIT_KEPT_SAVEDS_COUNT(options)); + fprintf(compiler->verbose, " opt:reg_arg(%d),", SLJIT_KEPT_SAVEDS_COUNT(options)); + else + fprintf(compiler->verbose, " opt:reg_arg,"); + } + +#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) + if (options & SLJIT_ENTER_USE_VEX) { + fprintf(compiler->verbose, " opt:use_vex,"); } +#endif /* !SLJIT_CONFIG_X86 */ fprintf(compiler->verbose, " scratches:%d, saveds:%d, fscratches:%d, fsaveds:%d, local_size:%d\n", scratches, saveds, fscratches, fsaveds, local_size); @@ -1308,6 +1377,8 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_set_context(struct sljit_compi CHECK_RETURN_OK; } +#undef SLJIT_ENTER_CPU_SPECIFIC_OPTIONS + static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_return_void(struct sljit_compiler *compiler) { if (SLJIT_UNLIKELY(compiler->skip_checks)) { @@ -1636,6 +1707,33 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op2(struct sljit_compiler CHECK_RETURN_OK; } +static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op2r(struct sljit_compiler *compiler, sljit_s32 op, + sljit_s32 dst_reg, + sljit_s32 src1, sljit_sw src1w, + sljit_s32 src2, sljit_sw src2w) +{ +#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) + CHECK_ARGUMENT((op | SLJIT_32) == SLJIT_MULADD32); + CHECK_ARGUMENT(FUNCTION_CHECK_IS_REG(dst_reg)); + FUNCTION_CHECK_SRC(src1, src1w); + FUNCTION_CHECK_SRC(src2, src2w); + compiler->last_flags = 0; +#endif +#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) + if (SLJIT_UNLIKELY(!!compiler->verbose)) { + fprintf(compiler->verbose, " %s%s ", op2r_names[GET_OPCODE(op) - SLJIT_OP2R_BASE], !(op & SLJIT_32) ? "" : "32"); + + sljit_verbose_reg(compiler, dst_reg); + fprintf(compiler->verbose, ", "); + sljit_verbose_param(compiler, src1, src1w); + fprintf(compiler->verbose, ", "); + sljit_verbose_param(compiler, src2, src2w); + fprintf(compiler->verbose, "\n"); + } +#endif + CHECK_RETURN_OK; +} + static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_shift_into(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 dst_reg, sljit_s32 src1_reg, @@ -1721,11 +1819,11 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_get_register_index(sljit_s32 t #if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) if (type == SLJIT_GP_REGISTER) { CHECK_ARGUMENT((reg > 0 && reg <= SLJIT_NUMBER_OF_REGISTERS) - || (reg >= SLJIT_TMP_REGISTER_BASE && reg <= (SLJIT_TMP_REGISTER_BASE + SLJIT_NUMBER_OF_TEMPORARY_REGISTERS))); + || (reg >= SLJIT_TMP_REGISTER_BASE && reg < (SLJIT_TMP_REGISTER_BASE + SLJIT_NUMBER_OF_TEMPORARY_REGISTERS))); } else { CHECK_ARGUMENT(type == SLJIT_FLOAT_REGISTER || ((type >> 12) == 0 || ((type >> 12) >= 3 && (type >> 12) <= 6))); CHECK_ARGUMENT((reg > 0 && reg <= SLJIT_NUMBER_OF_FLOAT_REGISTERS) - || (reg >= SLJIT_TMP_FREGISTER_BASE && reg <= (SLJIT_TMP_FREGISTER_BASE + SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS))); + || (reg >= SLJIT_TMP_FREGISTER_BASE && reg < (SLJIT_TMP_FREGISTER_BASE + SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS))); } #endif CHECK_RETURN_OK; @@ -2927,14 +3025,14 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_const(struct sljit_compil CHECK_RETURN_OK; } -static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_put_label(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw) +static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_mov_addr(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw) { #if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) FUNCTION_CHECK_DST(dst, dstw); #endif #if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) if (SLJIT_UNLIKELY(!!compiler->verbose)) { - fprintf(compiler->verbose, " put_label "); + fprintf(compiler->verbose, " mov_addr "); sljit_verbose_param(compiler, dst, dstw); fprintf(compiler->verbose, "\n"); } @@ -3058,6 +3156,8 @@ static sljit_s32 sljit_emit_fmem_unaligned(struct sljit_compiler *compiler, slji # include "sljitNativeLOONGARCH_64.c" #endif +#include "sljitSerialize.c" + static SLJIT_INLINE sljit_s32 emit_mov_before_return(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw) { #if (defined SLJIT_64BIT_ARCHITECTURE && SLJIT_64BIT_ARCHITECTURE) @@ -3288,7 +3388,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fmem_update(struct sljit_compiler #if !(defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) \ && !(defined SLJIT_CONFIG_ARM && SLJIT_CONFIG_ARM) \ - && !(defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X) + && !(defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X) \ + && !(defined SLJIT_CONFIG_LOONGARCH && SLJIT_CONFIG_LOONGARCH) SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_mov(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 freg, diff --git a/src/sljit/sljitLir.h b/src/sljit/sljitLir.h index 2ba6683..8b6fa69 100644 --- a/src/sljit/sljitLir.h +++ b/src/sljit/sljitLir.h @@ -427,7 +427,10 @@ struct sljit_memory_fragment { struct sljit_label { struct sljit_label *next; - sljit_uw addr; + union { + sljit_uw index; + sljit_uw addr; + } u; /* The maximum size difference. */ sljit_uw size; }; @@ -443,36 +446,35 @@ struct sljit_jump { } u; }; -struct sljit_put_label { - struct sljit_put_label *next; - struct sljit_label *label; - sljit_uw addr; - sljit_uw flags; -}; - struct sljit_const { struct sljit_const *next; sljit_uw addr; }; +struct sljit_generate_code_buffer { + void *buffer; + sljit_uw size; + sljit_sw executable_offset; +}; + struct sljit_compiler { sljit_s32 error; sljit_s32 options; struct sljit_label *labels; struct sljit_jump *jumps; - struct sljit_put_label *put_labels; struct sljit_const *consts; struct sljit_label *last_label; struct sljit_jump *last_jump; struct sljit_const *last_const; - struct sljit_put_label *last_put_label; void *allocator_data; - void *exec_allocator_data; + void *user_data; struct sljit_memory_fragment *buf; struct sljit_memory_fragment *abuf; + /* Number of labels created by the compiler. */ + sljit_uw label_count; /* Available scratch registers. */ sljit_s32 scratches; /* Available saved registers. */ @@ -492,15 +494,16 @@ struct sljit_compiler { #if (defined SLJIT_HAS_STATUS_FLAGS_STATE && SLJIT_HAS_STATUS_FLAGS_STATE) sljit_s32 status_flags_state; -#endif +#endif /* SLJIT_HAS_STATUS_FLAGS_STATE */ #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) sljit_s32 args_size; -#endif +#endif /* SLJIT_CONFIG_X86_32 */ #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) + /* Temporary fields. */ sljit_s32 mode32; -#endif +#endif /* SLJIT_CONFIG_X86_64 */ #if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) /* Constant pool handling. */ @@ -511,7 +514,7 @@ struct sljit_compiler { /* Other members. */ /* Contains pointer, "ldr pc, [...]" pairs. */ sljit_uw patches; -#endif +#endif /* SLJIT_CONFIG_ARM_V6 */ #if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) || (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) /* Temporary fields. */ @@ -520,40 +523,45 @@ struct sljit_compiler { #if (defined SLJIT_CONFIG_ARM_32 && SLJIT_CONFIG_ARM_32) && (defined __SOFTFP__) sljit_uw args_size; -#endif +#endif /* SLJIT_CONFIG_ARM_32 && __SOFTFP__ */ #if (defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC) + /* Temporary fields. */ sljit_u32 imm; -#endif +#endif /* SLJIT_CONFIG_PPC */ #if (defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS) sljit_s32 delay_slot; + /* Temporary fields. */ sljit_s32 cache_arg; sljit_sw cache_argw; -#endif +#endif /* SLJIT_CONFIG_MIPS */ #if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) sljit_uw args_size; -#endif +#endif /* SLJIT_CONFIG_MIPS_32 */ #if (defined SLJIT_CONFIG_RISCV && SLJIT_CONFIG_RISCV) + /* Temporary fields. */ sljit_s32 cache_arg; sljit_sw cache_argw; -#endif +#endif /* SLJIT_CONFIG_RISCV */ #if (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X) /* Need to allocate register save area to make calls. */ + /* Temporary fields. */ sljit_s32 mode; -#endif +#endif /* SLJIT_CONFIG_S390X */ #if (defined SLJIT_CONFIG_LOONGARCH && SLJIT_CONFIG_LOONGARCH) + /* Temporary fields. */ sljit_s32 cache_arg; sljit_sw cache_argw; -#endif +#endif /* SLJIT_CONFIG_LOONGARCH */ #if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) FILE* verbose; -#endif +#endif /* SLJIT_VERBOSE */ #if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) \ || (defined SLJIT_DEBUG && SLJIT_DEBUG) @@ -564,7 +572,7 @@ struct sljit_compiler { sljit_s32 last_return; /* Local size passed to entry functions. */ sljit_s32 logical_local_size; -#endif +#endif /* SLJIT_ARGUMENT_CHECKS || SLJIT_DEBUG */ #if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) \ || (defined SLJIT_DEBUG && SLJIT_DEBUG) \ @@ -572,7 +580,7 @@ struct sljit_compiler { /* Trust arguments when an API function is called. Used internally for calling API functions. */ sljit_s32 skip_checks; -#endif +#endif /* SLJIT_ARGUMENT_CHECKS || SLJIT_DEBUG || SLJIT_VERBOSE */ }; /* --------------------------------------------------------------------- */ @@ -583,12 +591,10 @@ struct sljit_compiler { custom memory managers. This pointer is passed to SLJIT_MALLOC and SLJIT_FREE macros. Most allocators (including the default one) ignores this value, and it is recommended to pass NULL - as a dummy value for allocator_data. The exec_allocator_data - has the same purpose but this one is passed to SLJIT_MALLOC_EXEC / - SLJIT_MALLOC_FREE functions. + as a dummy value for allocator_data. Returns NULL if failed. */ -SLJIT_API_FUNC_ATTRIBUTE struct sljit_compiler* sljit_create_compiler(void *allocator_data, void *exec_allocator_data); +SLJIT_API_FUNC_ATTRIBUTE struct sljit_compiler* sljit_create_compiler(void *allocator_data); /* Frees everything except the compiled machine code. */ SLJIT_API_FUNC_ATTRIBUTE void sljit_free_compiler(struct sljit_compiler *compiler); @@ -619,20 +625,31 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_compiler_memory_error(struct sljit_compi of the compiler to out-of-memory status). */ SLJIT_API_FUNC_ATTRIBUTE void* sljit_alloc_memory(struct sljit_compiler *compiler, sljit_s32 size); -/* Returns the allocator data passed to sljit_create_compiler. These pointers - may contain context data even if the normal/exec allocator ignores it. */ -static SLJIT_INLINE void* sljit_get_allocator_data(struct sljit_compiler *compiler) { return compiler->allocator_data; } -static SLJIT_INLINE void* sljit_get_exec_allocator_data(struct sljit_compiler *compiler) { return compiler->exec_allocator_data; } +/* Returns the allocator data passed to sljit_create_compiler. */ +static SLJIT_INLINE void* sljit_compiler_get_allocator_data(struct sljit_compiler *compiler) { return compiler->allocator_data; } +/* Sets/get the user data for a compiler. */ +static SLJIT_INLINE void sljit_compiler_set_user_data(struct sljit_compiler *compiler, void *user_data) { compiler->user_data = user_data; } +static SLJIT_INLINE void* sljit_compiler_get_user_data(struct sljit_compiler *compiler) { return compiler->user_data; } #if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) /* Passing NULL disables verbose. */ SLJIT_API_FUNC_ATTRIBUTE void sljit_compiler_verbose(struct sljit_compiler *compiler, FILE* verbose); #endif +/* Option bits for sljit_generate_code. */ + +/* The exec_allocator_data points to a pre-allocated + buffer which type is sljit_generate_code_buffer. */ +#define SLJIT_GENERATE_CODE_BUFFER 0x1 + /* Create executable code from the instruction stream. This is the final step - of the code generation so no more instructions can be emitted after this call. */ + of the code generation, and no more instructions can be emitted after this call. + + options is the combination of SLJIT_GENERATE_CODE_* bits + exec_allocator_data is passed to SLJIT_MALLOC_EXEC and + SLJIT_MALLOC_FREE functions */ -SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler); +SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler, sljit_s32 options, void *exec_allocator_data); /* Free executable code. */ @@ -708,6 +725,11 @@ static SLJIT_INLINE sljit_uw sljit_get_generated_code_size(struct sljit_compiler #define SLJIT_HAS_AVX2 101 #endif +#if (defined SLJIT_CONFIG_LOONGARCH) +/* [Not emulated] LASX support is available on LoongArch */ +#define SLJIT_HAS_LASX 201 +#endif + SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type); /* If type is between SLJIT_ORDERED_EQUAL and SLJIT_ORDERED_LESS_EQUAL, @@ -777,17 +799,22 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_cmp_info(sljit_s32 type); global / local context pointers) across function calls. The value of n must be between 1 and 3. This option is only supported by SLJIT_ENTER_REG_ARG calling convention. */ -#define SLJIT_ENTER_KEEP(n) (n) +#define SLJIT_ENTER_KEEP(n) (n) /* The compiled function uses an SLJIT specific register argument calling convention. This is a lightweight function call type where both the caller and the called functions must be compiled by SLJIT. The type argument of the call must be SLJIT_CALL_REG_ARG and all arguments must be stored in scratch registers. */ -#define SLJIT_ENTER_REG_ARG 0x00000004 +#define SLJIT_ENTER_REG_ARG 0x00000004 /* The local_size must be >= 0 and <= SLJIT_MAX_LOCAL_SIZE. */ -#define SLJIT_MAX_LOCAL_SIZE 1048576 +#define SLJIT_MAX_LOCAL_SIZE 1048576 + +#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) +/* Use VEX prefix for all SIMD operations on x86. */ +#define SLJIT_ENTER_USE_VEX 0x00010000 +#endif /* !SLJIT_CONFIG_X86 */ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compiler, sljit_s32 options, sljit_s32 arg_types, sljit_s32 scratches, sljit_s32 saveds, @@ -855,7 +882,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_to(struct sljit_compiler *c int | 4 byte (physical_address & 0x3 == 0) word | 4 byte if SLJIT_32BIT_ARCHITECTURE is defined and its value is 1 | 8 byte if SLJIT_64BIT_ARCHITECTURE is defined and its value is 1 - pointer | size of sljit_p type (4 byte on 32 bit machines, 4 or 8 byte + pointer | size of sljit_up type (4 byte on 32 bit machines, 4 or 8 byte | on 64 bit machines) Note: Different architectures have different addressing limitations. @@ -913,6 +940,13 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_to(struct sljit_compiler *c #define SLJIT_IS_IMM(arg) ((arg) == SLJIT_IMM) #define SLJIT_IS_REG_PAIR(arg) (!((arg) & SLJIT_MEM) && (arg) >= (SLJIT_MEM << 1)) +/* Macros for extracting registers from operands. */ +/* Support operands which contains a single register or + constructed using SLJIT_MEM1, SLJIT_MEM2, or SLJIT_REG_PAIR. */ +#define SLJIT_EXTRACT_REG(arg) ((arg) & 0x7f) +/* Support operands which constructed using SLJIT_MEM2, or SLJIT_REG_PAIR. */ +#define SLJIT_EXTRACT_SECOND_REG(arg) ((arg) >> 8) + /* Sets 32 bit operation mode on 64 bit CPUs. This option is ignored on 32 bit CPUs. When this option is set for an arithmetic operation, only the lower 32 bits of the input registers are used, and the CPU status @@ -1084,7 +1118,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compile S16 - signed 16 bit data transfer U32 - unsigned int (32 bit) data transfer S32 - signed int (32 bit) data transfer - P - pointer (sljit_p) data transfer + P - pointer (sljit_up) data transfer */ /* Flags: - (does not modify flags) */ @@ -1251,6 +1285,19 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compil sljit_s32 src1, sljit_sw src1w, sljit_s32 src2, sljit_sw src2w); +/* Starting index of opcodes for sljit_emit_op2r. */ +#define SLJIT_OP2R_BASE 96 + +/* Flags: - (may destroy flags) */ +#define SLJIT_MULADD (SLJIT_OP2R_BASE + 0) +#define SLJIT_MULADD32 (SLJIT_MULADD | SLJIT_32) + +/* Similar to sljit_emit_fop2, except the destination is always a register. */ +SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2r(struct sljit_compiler *compiler, sljit_s32 op, + sljit_s32 dst_reg, + sljit_s32 src1, sljit_sw src1w, + sljit_s32 src2, sljit_sw src2w); + /* Emit a left or right shift operation, where the bits shifted in comes from a separate source operand. All operands are interpreted as unsigned integers. @@ -1298,7 +1345,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler * /* Starting index of opcodes for sljit_emit_op_src and sljit_emit_op_dst. */ -#define SLJIT_OP_SRC_DST_BASE 96 +#define SLJIT_OP_SRC_DST_BASE 112 /* Fast return, see SLJIT_FAST_CALL for more details. Note: src cannot be an immedate value @@ -1350,7 +1397,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_dst(struct sljit_compiler *comp sljit_s32 dst, sljit_sw dstw); /* Starting index of opcodes for sljit_emit_fop1. */ -#define SLJIT_FOP1_BASE 128 +#define SLJIT_FOP1_BASE 144 /* Flags: - (does not modify flags) */ #define SLJIT_MOV_F64 (SLJIT_FOP1_BASE + 0) @@ -1395,7 +1442,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compil sljit_s32 src, sljit_sw srcw); /* Starting index of opcodes for sljit_emit_fop2. */ -#define SLJIT_FOP2_BASE 160 +#define SLJIT_FOP2_BASE 176 /* Flags: - (may destroy flags) */ #define SLJIT_ADD_F64 (SLJIT_FOP2_BASE + 0) @@ -1416,7 +1463,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compil sljit_s32 src2, sljit_sw src2w); /* Starting index of opcodes for sljit_emit_fop2r. */ -#define SLJIT_FOP2R_BASE 168 +#define SLJIT_FOP2R_BASE 192 /* Flags: - (may destroy flags) */ #define SLJIT_COPYSIGN_F64 (SLJIT_FOP2R_BASE + 0) @@ -2138,17 +2185,15 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_local_base(struct sljit_compiler *c Flags: - (does not modify flags) */ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value); -/* Store the value of a label (see: sljit_set_put_label) +/* Store the value of a label (see: sljit_set_label / sljit_set_target) Flags: - (does not modify flags) */ -SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label* sljit_emit_put_label(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw); - -/* Set the value stored by put_label to this label. */ -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_put_label(struct sljit_put_label *put_label, struct sljit_label *label); +SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_mov_addr(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw); -/* After the code generation the address for label, jump and const instructions - are computed. Since these structures are freed by sljit_free_compiler, the - addresses must be preserved by the user program elsewere. */ -static SLJIT_INLINE sljit_uw sljit_get_label_addr(struct sljit_label *label) { return label->addr; } +/* Provides the address of label, jump and const instructions after sljit_generate_code + is called. The returned value is unspecified before the sljit_generate_code call. + Since these structures are freed by sljit_free_compiler, the addresses must be + preserved by the user program elsewere. */ +static SLJIT_INLINE sljit_uw sljit_get_label_addr(struct sljit_label *label) { return label->u.addr; } static SLJIT_INLINE sljit_uw sljit_get_jump_addr(struct sljit_jump *jump) { return jump->addr; } static SLJIT_INLINE sljit_uw sljit_get_const_addr(struct sljit_const *const_) { return const_->addr; } @@ -2221,6 +2266,98 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *c SLJIT_API_FUNC_ATTRIBUTE void sljit_set_current_flags(struct sljit_compiler *compiler, sljit_s32 current_flags); +/* --------------------------------------------------------------------- */ +/* Serialization functions */ +/* --------------------------------------------------------------------- */ + +/* Label/jump/const enumeration functions. The items in each group + are enumerated in creation order. Serialization / deserialization + preserves this order for each group. For example the fifth label + after deserialization refers to the same machine code location as + the fifth label before the serialization. */ +static SLJIT_INLINE struct sljit_label *sljit_get_first_label(struct sljit_compiler *compiler) { return compiler->labels; } +static SLJIT_INLINE struct sljit_jump *sljit_get_first_jump(struct sljit_compiler *compiler) { return compiler->jumps; } +static SLJIT_INLINE struct sljit_const *sljit_get_first_const(struct sljit_compiler *compiler) { return compiler->consts; } + +static SLJIT_INLINE struct sljit_label *sljit_get_next_label(struct sljit_label *label) { return label->next; } +static SLJIT_INLINE struct sljit_jump *sljit_get_next_jump(struct sljit_jump *jump) { return jump->next; } +static SLJIT_INLINE struct sljit_const *sljit_get_next_const(struct sljit_const *const_) { return const_->next; } + +/* A number starting from 0 is assigned to each label, which +represents its creation index. The first label created by the +compiler has index 0, the second has index 1, the third has +index 2, and so on. The returned value is unspecified after +sljit_generate_code() is called. */ +static SLJIT_INLINE sljit_uw sljit_get_label_index(struct sljit_label *label) { return label->u.index; } + +/* The sljit_jump_has_label() and sljit_jump_has_target() functions +returns non-zero value if a label or target is set for the jump +respectively. Both may return with a zero value. The other two +functions return the value assigned to the jump. */ +SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_jump_has_label(struct sljit_jump *jump); +static SLJIT_INLINE struct sljit_label *sljit_jump_get_label(struct sljit_jump *jump) { return jump->u.label; } +SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_jump_has_target(struct sljit_jump *jump); +static SLJIT_INLINE sljit_uw sljit_jump_get_target(struct sljit_jump *jump) { return jump->u.target; } +SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_jump_is_mov_addr(struct sljit_jump *jump); + +/* Option bits for sljit_serialize_compiler. */ + +/* When debugging is enabled, the serialized buffer contains +debugging information unless this option is specified. */ +#define SLJIT_SERIALIZE_IGNORE_DEBUG 0x1 + +/* Serialize the internal structure of the compiler into a buffer. +If the serialization is successful, the returned value is a newly +allocated buffer which is allocated by the memory allocator assigned +to the compiler. Otherwise the returned value is NULL. Unlike +sljit_generate_code(), serialization does not modify the internal +state of the compiler, so the code generation can be continued. + + options must be the combination of SLJIT_SERIALIZE_* option bits + size is an output argument, which is set to the byte size of + the result buffer if the operation is successful + +Notes: + - This function is useful for ahead-of-time compilation (AOT). + - The returned buffer must be freed later by the caller. + The SLJIT_FREE() macro is suitable for this purpose: + SLJIT_FREE(returned_buffer, sljit_get_allocator_data(compiler)) + - Memory allocated by sljit_alloc_memory() is not serialized. + - The type of the returned buffer is sljit_uw* to emphasize that + the buffer is word aligned. However, the 'size' output argument + contains the byte size, so this value is always divisible by + sizeof(sljit_uw). +*/ +SLJIT_API_FUNC_ATTRIBUTE sljit_uw* sljit_serialize_compiler(struct sljit_compiler *compiler, + sljit_s32 options, sljit_uw *size); + +/* Construct a new compiler instance from a buffer produced by +sljit_serialize_compiler(). If the operation is successful, the new +compiler instance is returned. Otherwise the returned value is NULL. + + buffer points to a word aligned memory data which was + created by sljit_serialize_compiler() + size is the byte size of the buffer + options must be 0 + allocator_data specify an allocator specific data, see + sljit_create_compiler() for further details + +Notes: + - Labels assigned to jumps are restored with their + corresponding label in the label set created by + the deserializer. Target addresses assigned to + jumps are also restored. Uninitialized jumps + remain uninitialized. + - After the deserialization, sljit_generate_code() does + not need to be the next operation on the returned + compiler, the code generation can be continued. + Even sljit_serialize_compiler() can be called again. + - When debugging is enabled, a buffers without debug + information cannot be deserialized. +*/ +SLJIT_API_FUNC_ATTRIBUTE struct sljit_compiler *sljit_deserialize_compiler(sljit_uw* buffer, sljit_uw size, + sljit_s32 options, void *allocator_data); + /* --------------------------------------------------------------------- */ /* Miscellaneous utility functions */ /* --------------------------------------------------------------------- */ diff --git a/src/sljit/sljitNativeARM_32.c b/src/sljit/sljitNativeARM_32.c index d44616d..a253c06 100644 --- a/src/sljit/sljitNativeARM_32.c +++ b/src/sljit/sljitNativeARM_32.c @@ -120,6 +120,7 @@ static const sljit_u8 freg_ebit_map[((SLJIT_NUMBER_OF_FLOAT_REGISTERS + 2) << 1) #define LDREX 0xe1900f9f #define LDREXB 0xe1d00f9f #define LDREXH 0xe1f00f9f +#define MLA 0xe0200090 #define MOV 0xe1a00000 #define MUL 0xe0000090 #define MVN 0xe1e00000 @@ -482,11 +483,12 @@ static SLJIT_INLINE sljit_s32 detect_jump_type(struct sljit_jump *jump, sljit_uw #if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) if (jump->flags & IS_BL) code_ptr--; +#endif /* SLJIT_CONFIG_ARM_V6 */ if (jump->flags & JUMP_ADDR) diff = ((sljit_sw)jump->u.target - (sljit_sw)(code_ptr + 2) - executable_offset); else { - SLJIT_ASSERT(jump->flags & JUMP_LABEL); + SLJIT_ASSERT(jump->u.label != NULL); diff = ((sljit_sw)(code + jump->u.label->size) - (sljit_sw)(code_ptr + 2)); } @@ -494,6 +496,7 @@ static SLJIT_INLINE sljit_s32 detect_jump_type(struct sljit_jump *jump, sljit_uw if (diff & 0x3) return 0; +#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) if (jump->flags & IS_BL) { if (diff <= 0x01ffffff && diff >= -0x02000000) { *code_ptr = (BL - CONDITIONAL) | (*(code_ptr + 1) & COND_MASK); @@ -508,20 +511,8 @@ static SLJIT_INLINE sljit_s32 detect_jump_type(struct sljit_jump *jump, sljit_uw } } #else /* !SLJIT_CONFIG_ARM_V6 */ - if (jump->flags & JUMP_ADDR) - diff = ((sljit_sw)jump->u.target - (sljit_sw)code_ptr - executable_offset); - else { - SLJIT_ASSERT(jump->flags & JUMP_LABEL); - 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; - if (diff <= 0x01ffffff && diff >= -0x02000000) { - code_ptr -= 2; - *code_ptr = ((jump->flags & IS_BL) ? (BL - CONDITIONAL) : (B - CONDITIONAL)) | (code_ptr[2] & COND_MASK); + *code_ptr = ((jump->flags & IS_BL) ? (BL - CONDITIONAL) : (B - CONDITIONAL)) | (*code_ptr & COND_MASK); jump->flags |= PATCH_B; return 1; } @@ -529,7 +520,7 @@ static SLJIT_INLINE sljit_s32 detect_jump_type(struct sljit_jump *jump, sljit_uw return 0; } -static SLJIT_INLINE void inline_set_jump_addr(sljit_uw jump_ptr, sljit_sw executable_offset, sljit_uw new_addr, sljit_s32 flush_cache) +static void set_jump_addr(sljit_uw jump_ptr, sljit_sw executable_offset, sljit_uw new_addr, sljit_s32 flush_cache) { #if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) sljit_ins *ptr = (sljit_ins*)jump_ptr; @@ -628,7 +619,7 @@ static sljit_uw get_imm(sljit_uw imm); static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 reg, sljit_uw imm); static sljit_s32 emit_op_mem(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg, sljit_sw argw, sljit_s32 tmp_reg); -static SLJIT_INLINE void inline_set_const(sljit_uw addr, sljit_sw executable_offset, sljit_uw new_constant, sljit_s32 flush_cache) +static void set_const_value(sljit_uw addr, sljit_sw executable_offset, sljit_uw new_constant, sljit_s32 flush_cache) { #if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) sljit_ins *ptr = (sljit_ins*)addr; @@ -720,18 +711,120 @@ static SLJIT_INLINE void inline_set_const(sljit_uw addr, sljit_sw executable_off #endif /* SLJIT_CONFIG_ARM_V6 */ } -SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler) +static SLJIT_INLINE sljit_sw mov_addr_get_length(struct sljit_jump *jump, sljit_ins *code_ptr, sljit_ins *code, sljit_sw executable_offset) +{ + sljit_uw addr; + sljit_sw diff; + SLJIT_UNUSED_ARG(executable_offset); + + if (jump->flags & JUMP_ADDR) + addr = jump->u.target; + else + addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code + jump->u.label->size, executable_offset); + + /* The pc+8 offset is represented by the 2 * SSIZE_OF(ins) below. */ + diff = (sljit_sw)addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset); + + if ((diff & 0x3) == 0 && diff <= (0x3fc + 2 * SSIZE_OF(ins)) && diff >= (-0x3fc + 2 * SSIZE_OF(ins))) { + jump->flags |= PATCH_B; + return 0; + } + +#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) + return 0; +#else /* !SLJIT_CONFIG_ARM_V6 */ + return 1; +#endif /* SLJIT_CONFIG_ARM_V6 */ +} + +#if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) + +static void reduce_code_size(struct sljit_compiler *compiler) +{ + struct sljit_label *label; + struct sljit_jump *jump; + struct sljit_const *const_; + SLJIT_NEXT_DEFINE_TYPES; + sljit_uw total_size; + sljit_uw size_reduce = 0; + sljit_sw diff; + + label = compiler->labels; + jump = compiler->jumps; + const_ = compiler->consts; + SLJIT_NEXT_INIT_TYPES(); + + while (1) { + SLJIT_GET_NEXT_MIN(); + + if (next_min_addr == SLJIT_MAX_ADDRESS) + break; + + if (next_min_addr == next_label_size) { + label->size -= size_reduce; + + label = label->next; + next_label_size = SLJIT_GET_NEXT_SIZE(label); + } + + if (next_min_addr == next_const_addr) { + const_->addr -= size_reduce; + const_ = const_->next; + next_const_addr = SLJIT_GET_NEXT_ADDRESS(const_); + continue; + } + + if (next_min_addr != next_jump_addr) + continue; + + jump->addr -= size_reduce; + if (!(jump->flags & JUMP_MOV_ADDR)) { + total_size = JUMP_MAX_SIZE - 1; + + if (!(jump->flags & (SLJIT_REWRITABLE_JUMP | JUMP_ADDR))) { + /* Unit size: instruction. */ + diff = (sljit_sw)jump->u.label->size - (sljit_sw)jump->addr - 2; + + if (diff <= (0x01ffffff / SSIZE_OF(ins)) && diff >= (-0x02000000 / SSIZE_OF(ins))) + total_size = 1 - 1; + } + + size_reduce += JUMP_MAX_SIZE - 1 - total_size; + } else { + /* Real size minus 1. Unit size: instruction. */ + total_size = 1; + + if (!(jump->flags & JUMP_ADDR)) { + diff = (sljit_sw)jump->u.label->size - (sljit_sw)jump->addr; + if (diff <= 0xff + 2 && diff >= -0xff + 2) + total_size = 0; + } + + size_reduce += 1 - total_size; + } + + jump->flags |= total_size << JUMP_SIZE_SHIFT; + jump = jump->next; + next_jump_addr = SLJIT_GET_NEXT_ADDRESS(jump); + } + + compiler->size -= size_reduce; +} + +#endif /* SLJIT_CONFIG_ARM_V7 */ + +SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler, sljit_s32 options, void *exec_allocator_data) { struct sljit_memory_fragment *buf; sljit_ins *code; sljit_ins *code_ptr; sljit_ins *buf_ptr; sljit_ins *buf_end; - sljit_uw size; sljit_uw word_count; - sljit_uw next_addr; + SLJIT_NEXT_DEFINE_TYPES; sljit_sw executable_offset; sljit_uw addr; + sljit_sw diff; #if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) sljit_uw cpool_size; sljit_uw cpool_skip_alignment; @@ -744,22 +837,22 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil struct sljit_label *label; struct sljit_jump *jump; struct sljit_const *const_; - struct sljit_put_label *put_label; CHECK_ERROR_PTR(); CHECK_PTR(check_sljit_generate_code(compiler)); - reverse_buf(compiler); /* Second code generation pass. */ #if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) - size = compiler->size + (compiler->patches << 1); + compiler->size += (compiler->patches << 1); if (compiler->cpool_fill > 0) - size += compiler->cpool_fill + CONST_POOL_ALIGNMENT - 1; + compiler->size += compiler->cpool_fill + CONST_POOL_ALIGNMENT - 1; #else /* !SLJIT_CONFIG_ARM_V6 */ - size = compiler->size; + reduce_code_size(compiler); #endif /* SLJIT_CONFIG_ARM_V6 */ - code = (sljit_ins*)SLJIT_MALLOC_EXEC(size * sizeof(sljit_ins), compiler->exec_allocator_data); + code = (sljit_ins*)allocate_executable_memory(compiler->size * sizeof(sljit_ins), options, exec_allocator_data, &executable_offset); PTR_FAIL_WITH_EXEC_IF(code); + + reverse_buf(compiler); buf = compiler->buf; #if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) @@ -773,33 +866,24 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil code_ptr = code; word_count = 0; - next_addr = 1; - executable_offset = SLJIT_EXEC_OFFSET(code); - label = compiler->labels; jump = compiler->jumps; const_ = compiler->consts; - put_label = compiler->put_labels; - - if (label && label->size == 0) { - label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code, executable_offset); - label = label->next; - } + SLJIT_NEXT_INIT_TYPES(); + SLJIT_GET_NEXT_MIN(); do { buf_ptr = (sljit_ins*)buf->memory; buf_end = buf_ptr + (buf->used_size >> 2); do { - word_count++; #if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) if (cpool_size > 0) { if (cpool_skip_alignment > 0) { buf_ptr++; cpool_skip_alignment--; - } - else { + } else { if (SLJIT_UNLIKELY(resolve_const_pool_index(compiler, &first_patch, cpool_current_index, cpool_start_address, buf_ptr))) { - SLJIT_FREE_EXEC(code, compiler->exec_allocator_data); + SLJIT_FREE_EXEC(code, exec_allocator_data); compiler->error = SLJIT_ERR_ALLOC_FAILED; return NULL; } @@ -807,59 +891,59 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil if (++cpool_current_index >= cpool_size) { SLJIT_ASSERT(!first_patch); cpool_size = 0; - if (label && label->size == word_count) { - /* Points after the current instruction. */ - label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset); - label->size = (sljit_uw)(code_ptr - code); - label = label->next; - - next_addr = compute_next_addr(label, jump, const_, put_label); - } } } - } - else if ((*buf_ptr & 0xff000000) != PUSH_POOL) { + } else if ((*buf_ptr & 0xff000000) != PUSH_POOL) { #endif /* SLJIT_CONFIG_ARM_V6 */ *code_ptr = *buf_ptr++; - if (next_addr == word_count) { + if (next_min_addr == word_count) { SLJIT_ASSERT(!label || label->size >= word_count); SLJIT_ASSERT(!jump || jump->addr >= word_count); SLJIT_ASSERT(!const_ || const_->addr >= word_count); - SLJIT_ASSERT(!put_label || put_label->addr >= word_count); - /* These structures are ordered by their address. */ - if (jump && jump->addr == word_count) { -#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) - if (detect_jump_type(jump, code_ptr, code, executable_offset)) - code_ptr--; - jump->addr = (sljit_uw)code_ptr; -#else /* !SLJIT_CONFIG_ARM_V6 */ - jump->addr = (sljit_uw)(code_ptr - 2); - if (detect_jump_type(jump, code_ptr, code, executable_offset)) - code_ptr -= 2; -#endif /* SLJIT_CONFIG_ARM_V6 */ - jump = jump->next; - } - if (label && label->size == word_count) { - /* code_ptr can be affected above. */ - label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr + 1, executable_offset); - label->size = (sljit_uw)((code_ptr + 1) - code); + if (next_min_addr == next_label_size) { + label->u.addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset); + label->size = (sljit_uw)(code_ptr - code); label = label->next; + next_label_size = SLJIT_GET_NEXT_SIZE(label); } - if (const_ && const_->addr == word_count) { + + /* These structures are ordered by their address. */ + if (next_min_addr == next_jump_addr) { + if (!(jump->flags & JUMP_MOV_ADDR)) { #if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) - const_->addr = (sljit_uw)code_ptr; + if (detect_jump_type(jump, code_ptr, code, executable_offset)) + code_ptr--; + jump->addr = (sljit_uw)code_ptr; #else /* !SLJIT_CONFIG_ARM_V6 */ - const_->addr = (sljit_uw)(code_ptr - 1); + word_count += jump->flags >> JUMP_SIZE_SHIFT; + jump->addr = (sljit_uw)code_ptr; + if (!detect_jump_type(jump, code_ptr, code, executable_offset)) { + code_ptr[2] = code_ptr[0]; + addr = ((code_ptr[0] & 0xf) << 12); + code_ptr[0] = MOVW | addr; + code_ptr[1] = MOVT | addr; + code_ptr += 2; + } + SLJIT_ASSERT((sljit_uw)code_ptr - jump->addr <= (jump->flags >> JUMP_SIZE_SHIFT) * sizeof(sljit_ins)); #endif /* SLJIT_CONFIG_ARM_V6 */ + } else { +#if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) + word_count += jump->flags >> JUMP_SIZE_SHIFT; +#endif /* SLJIT_CONFIG_ARM_V7 */ + addr = (sljit_uw)code_ptr; + code_ptr += mov_addr_get_length(jump, code_ptr, code, executable_offset); + jump->addr = addr; + } + jump = jump->next; + next_jump_addr = SLJIT_GET_NEXT_ADDRESS(jump); + } else if (next_min_addr == next_const_addr) { + const_->addr = (sljit_uw)code_ptr; const_ = const_->next; + next_const_addr = SLJIT_GET_NEXT_ADDRESS(const_); } - if (put_label && put_label->addr == word_count) { - SLJIT_ASSERT(put_label->label); - put_label->addr = (sljit_uw)code_ptr; - put_label = put_label->next; - } - next_addr = compute_next_addr(label, jump, const_, put_label); + + SLJIT_GET_NEXT_MIN(); } code_ptr++; #if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) @@ -879,14 +963,20 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil last_pc_patch = code_ptr; } #endif /* SLJIT_CONFIG_ARM_V6 */ + word_count++; } while (buf_ptr < buf_end); buf = buf->next; } while (buf); + if (label && label->size == word_count) { + label->u.addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset); + label->size = (sljit_uw)(code_ptr - code); + label = label->next; + } + SLJIT_ASSERT(!label); SLJIT_ASSERT(!jump); SLJIT_ASSERT(!const_); - SLJIT_ASSERT(!put_label); #if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) SLJIT_ASSERT(cpool_size == 0); @@ -901,7 +991,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil cpool_current_index = 0; while (buf_ptr < buf_end) { if (SLJIT_UNLIKELY(resolve_const_pool_index(compiler, &first_patch, cpool_current_index, cpool_start_address, buf_ptr))) { - SLJIT_FREE_EXEC(code, compiler->exec_allocator_data); + SLJIT_FREE_EXEC(code, exec_allocator_data); compiler->error = SLJIT_ERR_ALLOC_FAILED; return NULL; } @@ -914,43 +1004,64 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil jump = compiler->jumps; while (jump) { + addr = (jump->flags & JUMP_ADDR) ? jump->u.target : jump->u.label->u.addr; buf_ptr = (sljit_ins*)jump->addr; - if (jump->flags & PATCH_B) { - addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(buf_ptr + 2, executable_offset); - if (!(jump->flags & JUMP_ADDR)) { - SLJIT_ASSERT(jump->flags & JUMP_LABEL); - SLJIT_ASSERT((sljit_sw)(jump->u.label->addr - addr) <= 0x01ffffff && (sljit_sw)(jump->u.label->addr - addr) >= -0x02000000); - *buf_ptr |= ((jump->u.label->addr - addr) >> 2) & 0x00ffffff; - } - else { - SLJIT_ASSERT((sljit_sw)(jump->u.target - addr) <= 0x01ffffff && (sljit_sw)(jump->u.target - addr) >= -0x02000000); - *buf_ptr |= ((jump->u.target - addr) >> 2) & 0x00ffffff; - } - } - else if (jump->flags & SLJIT_REWRITABLE_JUMP) { + if (jump->flags & JUMP_MOV_ADDR) { #if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) - jump->addr = (sljit_uw)code_ptr; - code_ptr[0] = (sljit_ins)buf_ptr; - code_ptr[1] = *buf_ptr; - inline_set_jump_addr((sljit_uw)code_ptr, executable_offset, (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target, 0); - code_ptr += 2; + SLJIT_ASSERT((buf_ptr[0] & (sljit_ins)0xffff0000) == 0xe59f0000); #else /* !SLJIT_CONFIG_ARM_V6 */ - inline_set_jump_addr((sljit_uw)buf_ptr, executable_offset, (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target, 0); + SLJIT_ASSERT((buf_ptr[0] & ~(sljit_ins)0xf000) == 0); #endif /* SLJIT_CONFIG_ARM_V6 */ + + if (jump->flags & PATCH_B) { + SLJIT_ASSERT((((sljit_sw)addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(buf_ptr + 2, executable_offset)) & 0x3) == 0); + diff = ((sljit_sw)addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(buf_ptr + 2, executable_offset)) >> 2; + + SLJIT_ASSERT(diff <= 0xff && diff >= -0xff); + + addr = ADD; + if (diff < 0) { + diff = -diff; + addr = SUB; + } + + buf_ptr[0] = addr | (buf_ptr[0] & 0xf000) | RN(TMP_PC) | (1 << 25) | (0xf << 8) | (sljit_ins)(diff & 0xff); + } else { +#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) + buf_ptr[((buf_ptr[0] & 0xfff) >> 2) + 2] = addr; +#else /* !SLJIT_CONFIG_ARM_V6 */ + buf_ptr[1] = MOVT | buf_ptr[0] | ((addr >> 12) & 0xf0000) | ((addr >> 16) & 0xfff); + buf_ptr[0] = MOVW | buf_ptr[0] | ((addr << 4) & 0xf0000) | (addr & 0xfff); +#endif /* SLJIT_CONFIG_ARM_V6 */ + } + } else if (jump->flags & PATCH_B) { + diff = (sljit_sw)addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(buf_ptr + 2, executable_offset); + SLJIT_ASSERT(diff <= 0x01ffffff && diff >= -0x02000000); + *buf_ptr |= (diff >> 2) & 0x00ffffff; } else { #if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) if (jump->flags & IS_BL) buf_ptr--; - if (*buf_ptr & (1 << 23)) - buf_ptr += ((*buf_ptr & 0xfff) >> 2) + 2; - else - buf_ptr += 1; - *buf_ptr = (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target; + + if (jump->flags & SLJIT_REWRITABLE_JUMP) { + jump->addr = (sljit_uw)code_ptr; + code_ptr[0] = (sljit_ins)buf_ptr; + code_ptr[1] = *buf_ptr; + set_jump_addr((sljit_uw)code_ptr, executable_offset, addr, 0); + code_ptr += 2; + } else { + if (*buf_ptr & (1 << 23)) + buf_ptr += ((*buf_ptr & 0xfff) >> 2) + 2; + else + buf_ptr += 1; + *buf_ptr = addr; + } #else /* !SLJIT_CONFIG_ARM_V6 */ - inline_set_jump_addr((sljit_uw)buf_ptr, executable_offset, (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target, 0); + set_jump_addr((sljit_uw)buf_ptr, executable_offset, addr, 0); #endif /* SLJIT_CONFIG_ARM_V6 */ } + jump = jump->next; } @@ -967,30 +1078,14 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil else buf_ptr += 1; /* Set the value again (can be a simple constant). */ - inline_set_const((sljit_uw)code_ptr, executable_offset, *buf_ptr, 0); + set_const_value((sljit_uw)code_ptr, executable_offset, *buf_ptr, 0); code_ptr += 2; const_ = const_->next; } #endif /* SLJIT_CONFIG_ARM_V6 */ - put_label = compiler->put_labels; - while (put_label) { - addr = put_label->label->addr; - buf_ptr = (sljit_ins*)put_label->addr; - -#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) - SLJIT_ASSERT((buf_ptr[0] & 0xffff0000) == 0xe59f0000); - buf_ptr[((buf_ptr[0] & 0xfff) >> 2) + 2] = addr; -#else /* !SLJIT_CONFIG_ARM_V6 */ - SLJIT_ASSERT((buf_ptr[-1] & 0xfff00000) == MOVW && (buf_ptr[0] & 0xfff00000) == MOVT); - buf_ptr[-1] |= ((addr << 4) & 0xf0000) | (addr & 0xfff); - buf_ptr[0] |= ((addr >> 12) & 0xf0000) | ((addr >> 16) & 0xfff); -#endif /* SLJIT_CONFIG_ARM_V6 */ - put_label = put_label->next; - } - - SLJIT_ASSERT(code_ptr - code <= (sljit_s32)size); + SLJIT_ASSERT(code_ptr - code <= (sljit_s32)compiler->size); compiler->error = SLJIT_ERR_COMPILED; compiler->executable_offset = executable_offset; @@ -1113,7 +1208,7 @@ static const sljit_ins data_transfer_insts[16] = { /* Inverted immediate. */ #define INV_IMM 0x02 /* Source and destination is register. */ -#define MOVE_REG_CONV 0x04 +#define REGISTER_OP 0x04 /* Unused return value. */ #define UNUSED_RETURN 0x08 /* SET_FLAGS must be (1 << 20) as it is also the value of S bit (can be used for optimization). */ @@ -1498,7 +1593,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_to(struct sljit_compiler *c static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 flags, sljit_uw dst, sljit_uw src1, sljit_uw src2) { - sljit_s32 is_masked; + sljit_s32 reg, is_masked; sljit_uw shift_type; switch (op) { @@ -1515,7 +1610,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl case SLJIT_MOV_U8: case SLJIT_MOV_S8: SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & ARGS_SWAPPED)); - if (flags & MOVE_REG_CONV) + if (flags & REGISTER_OP) return push_inst(compiler, (op == SLJIT_MOV_U8 ? UXTB : SXTB) | RD(dst) | RM(src2)); if (dst != src2) { @@ -1527,7 +1622,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl case SLJIT_MOV_U16: case SLJIT_MOV_S16: SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & ARGS_SWAPPED)); - if (flags & MOVE_REG_CONV) + if (flags & REGISTER_OP) return push_inst(compiler, (op == SLJIT_MOV_U16 ? UXTH : SXTH) | RD(dst) | RM(src2)); if (dst != src2) { @@ -1543,11 +1638,11 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl case SLJIT_CTZ: SLJIT_ASSERT(!(flags & INV_IMM) && !(src2 & SRC2_IMM)); - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & ARGS_SWAPPED)); + SLJIT_ASSERT(src1 == TMP_REG1 && src2 != TMP_REG2 && !(flags & ARGS_SWAPPED)); #if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) - FAIL_IF(push_inst(compiler, RSB | SRC2_IMM | RD(TMP_REG1) | RN(src2) | 0)); - FAIL_IF(push_inst(compiler, AND | RD(TMP_REG2) | RN(src2) | RM(TMP_REG1))); - FAIL_IF(push_inst(compiler, CLZ | RD(dst) | RM(TMP_REG2))); + FAIL_IF(push_inst(compiler, RSB | SRC2_IMM | RD(TMP_REG2) | RN(src2) | 0)); + FAIL_IF(push_inst(compiler, AND | RD(TMP_REG1) | RN(src2) | RM(TMP_REG2))); + FAIL_IF(push_inst(compiler, CLZ | RD(dst) | RM(TMP_REG1))); FAIL_IF(push_inst(compiler, CMP | SET_FLAGS | SRC2_IMM | RN(dst) | 32)); return push_inst(compiler, (EOR ^ 0xf0000000) | SRC2_IMM | RD(dst) | RN(dst) | 0x1f); #else /* !SLJIT_CONFIG_ARM_V6 */ @@ -1563,9 +1658,9 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl case SLJIT_REV_U16: case SLJIT_REV_S16: - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & ARGS_SWAPPED) && src2 != TMP_REG1 && dst != TMP_REG1); + SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & ARGS_SWAPPED)); FAIL_IF(push_inst(compiler, REV16 | RD(dst) | RM(src2))); - if (dst == TMP_REG2 || (src2 == TMP_REG2 && op == SLJIT_REV_U16)) + if (!(flags & REGISTER_OP)) return SLJIT_SUCCESS; return push_inst(compiler, (op == SLJIT_REV_U16 ? UXTH : SXTH) | RD(dst) | RM(dst)); case SLJIT_ADD: @@ -1601,10 +1696,11 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl if (!(flags & SET_FLAGS)) return push_inst(compiler, MUL | RN(dst) | RM8(src2) | RM(src1)); - FAIL_IF(push_inst(compiler, SMULL | RN(TMP_REG1) | RD(dst) | RM8(src2) | RM(src1))); + reg = dst == TMP_REG1 ? TMP_REG2 : TMP_REG1; + FAIL_IF(push_inst(compiler, SMULL | RN(reg) | RD(dst) | RM8(src2) | RM(src1))); /* cmp TMP_REG1, dst asr #31. */ - return push_inst(compiler, CMP | SET_FLAGS | RN(TMP_REG1) | RM(dst) | 0xfc0); + return push_inst(compiler, CMP | SET_FLAGS | RN(reg) | RM(dst) | 0xfc0); case SLJIT_AND: if ((flags & (UNUSED_RETURN | INV_IMM)) == UNUSED_RETURN) @@ -1654,6 +1750,9 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl is_masked = 0; break; + case SLJIT_MULADD: + return push_inst(compiler, MLA | RN(dst) | RD(dst) | RM8(src2) | RM(src1)); + default: SLJIT_UNREACHABLE(); return SLJIT_SUCCESS; @@ -1973,6 +2072,7 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3 sljit_s32 dst_reg; sljit_s32 src1_reg = 0; sljit_s32 src2_reg = 0; + sljit_s32 src2_tmp_reg = 0; sljit_s32 flags = HAS_FLAGS(op) ? SET_FLAGS : 0; sljit_s32 neg_op = 0; sljit_u32 imm2; @@ -1982,7 +2082,7 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3 if (flags & SET_FLAGS) inp_flags &= ~ALLOW_DOUBLE_IMM; - if (dst == TMP_REG2) + if (dst == TMP_REG1) flags |= UNUSED_RETURN; SLJIT_ASSERT(!(inp_flags & ALLOW_INV_IMM) || (inp_flags & ALLOW_IMM)); @@ -2068,17 +2168,6 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3 } } while(0); - /* Source 1. */ - if (FAST_IS_REG(src1)) - src1_reg = src1; - else if (src1 & SLJIT_MEM) { - FAIL_IF(emit_op_mem(compiler, inp_flags | LOAD_DATA, TMP_REG1, src1, src1w, TMP_REG1)); - src1_reg = TMP_REG1; - } else if (!(inp_flags & ALLOW_DOUBLE_IMM) || src2_reg != 0 || op == SLJIT_SUB || op == SLJIT_SUBC) { - FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)src1w)); - src1_reg = TMP_REG1; - } - /* Destination. */ dst_reg = FAST_IS_REG(dst) ? dst : TMP_REG2; @@ -2088,21 +2177,44 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3 inp_flags &= ~SIGNED; if (FAST_IS_REG(src2)) - return emit_op_mem(compiler, inp_flags, src2, dst, dstw, TMP_REG2); + return emit_op_mem(compiler, inp_flags, src2, dst, dstw, TMP_REG1); } if (FAST_IS_REG(src2) && dst_reg != TMP_REG2) - flags |= MOVE_REG_CONV; + flags |= REGISTER_OP; + + src2_tmp_reg = dst_reg; + } else { + if (op == SLJIT_REV_U16 || op == SLJIT_REV_S16) { + if (!(dst & SLJIT_MEM) && (!(src2 & SLJIT_MEM) || op == SLJIT_REV_S16)) + flags |= REGISTER_OP; + } + + src2_tmp_reg = FAST_IS_REG(src1) ? TMP_REG1 : TMP_REG2; + } + + if (src2_reg == 0 && (src2 & SLJIT_MEM)) { + src2_reg = src2_tmp_reg; + FAIL_IF(emit_op_mem(compiler, inp_flags | LOAD_DATA, src2_reg, src2, src2w, TMP_REG1)); + } + + /* Source 1. */ + if (FAST_IS_REG(src1)) + src1_reg = src1; + else if (src1 & SLJIT_MEM) { + FAIL_IF(emit_op_mem(compiler, inp_flags | LOAD_DATA, TMP_REG1, src1, src1w, TMP_REG1)); + src1_reg = TMP_REG1; + } else if (!(inp_flags & ALLOW_DOUBLE_IMM) || src2_reg != 0 || op == SLJIT_SUB || op == SLJIT_SUBC) { + FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)src1w)); + src1_reg = TMP_REG1; } /* Source 2. */ if (src2_reg == 0) { - src2_reg = (op <= SLJIT_MOV_P) ? dst_reg : TMP_REG2; + src2_reg = src2_tmp_reg; if (FAST_IS_REG(src2)) src2_reg = src2; - else if (src2 & SLJIT_MEM) - FAIL_IF(emit_op_mem(compiler, inp_flags | LOAD_DATA, src2_reg, src2, src2w, TMP_REG2)); else if (!(inp_flags & ALLOW_DOUBLE_IMM)) FAIL_IF(load_immediate(compiler, src2_reg, (sljit_uw)src2w)); else { @@ -2122,8 +2234,8 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3 } if (src2_reg == 0) { - FAIL_IF(load_immediate(compiler, TMP_REG2, (sljit_uw)src2w)); - src2_reg = TMP_REG2; + FAIL_IF(load_immediate(compiler, src2_tmp_reg, (sljit_uw)src2w)); + src2_reg = src2_tmp_reg; } else { FAIL_IF(emit_single_op(compiler, op, flags, (sljit_uw)dst_reg, (sljit_uw)src1_reg, (sljit_uw)src2_reg)); src1_reg = dst_reg; @@ -2368,7 +2480,25 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compil CHECK(check_sljit_emit_op2(compiler, op, 1, 0, 0, src1, src1w, src2, src2w)); SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_op2(compiler, op, TMP_REG2, 0, src1, src1w, src2, src2w); + return sljit_emit_op2(compiler, op, TMP_REG1, 0, src1, src1w, src2, src2w); +} + +SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2r(struct sljit_compiler *compiler, sljit_s32 op, + sljit_s32 dst_reg, + sljit_s32 src1, sljit_sw src1w, + sljit_s32 src2, sljit_sw src2w) +{ + CHECK_ERROR(); + CHECK(check_sljit_emit_op2r(compiler, op, dst_reg, src1, src1w, src2, src2w)); + ADJUST_LOCAL_OFFSET(src1, src1w); + ADJUST_LOCAL_OFFSET(src2, src2w); + + switch (GET_OPCODE(op)) { + case SLJIT_MULADD: + return emit_op(compiler, op, 0, dst_reg, 0, src1, src1w, src2, src2w); + } + + return SLJIT_SUCCESS; } SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *compiler, sljit_s32 op, @@ -2533,8 +2663,8 @@ static sljit_s32 emit_fop_mem(struct sljit_compiler *compiler, sljit_s32 flags, arg &= ~SLJIT_MEM; if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) { - FAIL_IF(push_inst(compiler, ADD | RD(TMP_REG2) | RN(arg & REG_MASK) | RM(OFFS_REG(arg)) | (((sljit_ins)argw & 0x3) << 7))); - arg = TMP_REG2; + FAIL_IF(push_inst(compiler, ADD | RD(TMP_REG1) | RN(arg & REG_MASK) | RM(OFFS_REG(arg)) | (((sljit_ins)argw & 0x3) << 7))); + arg = TMP_REG1; argw = 0; } @@ -2547,25 +2677,25 @@ static sljit_s32 emit_fop_mem(struct sljit_compiler *compiler, sljit_s32 flags, imm = get_imm((sljit_uw)argw & ~(sljit_uw)0x3fc); if (imm) { - FAIL_IF(push_inst(compiler, ADD | RD(TMP_REG2) | RN(arg & REG_MASK) | imm)); - return push_inst(compiler, EMIT_FPU_DATA_TRANSFER(inst, 1, TMP_REG2, reg, (argw & 0x3fc) >> 2)); + FAIL_IF(push_inst(compiler, ADD | RD(TMP_REG1) | RN(arg & REG_MASK) | imm)); + return push_inst(compiler, EMIT_FPU_DATA_TRANSFER(inst, 1, TMP_REG1, reg, (argw & 0x3fc) >> 2)); } imm = get_imm((sljit_uw)-argw & ~(sljit_uw)0x3fc); if (imm) { argw = -argw; - FAIL_IF(push_inst(compiler, SUB | RD(TMP_REG2) | RN(arg & REG_MASK) | imm)); - return push_inst(compiler, EMIT_FPU_DATA_TRANSFER(inst, 0, TMP_REG2, reg, (argw & 0x3fc) >> 2)); + FAIL_IF(push_inst(compiler, SUB | RD(TMP_REG1) | RN(arg & REG_MASK) | imm)); + return push_inst(compiler, EMIT_FPU_DATA_TRANSFER(inst, 0, TMP_REG1, reg, (argw & 0x3fc) >> 2)); } } if (arg) { - FAIL_IF(load_immediate(compiler, TMP_REG2, (sljit_uw)argw)); - FAIL_IF(push_inst(compiler, ADD | RD(TMP_REG2) | RN(arg & REG_MASK) | RM(TMP_REG2))); + FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)argw)); + FAIL_IF(push_inst(compiler, ADD | RD(TMP_REG1) | RN(arg & REG_MASK) | RM(TMP_REG1))); } else - FAIL_IF(load_immediate(compiler, TMP_REG2, (sljit_uw)argw)); + FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)argw)); - return push_inst(compiler, EMIT_FPU_DATA_TRANSFER(inst, 1, TMP_REG2, reg, 0)); + return push_inst(compiler, EMIT_FPU_DATA_TRANSFER(inst, 1, TMP_REG1, reg, 0)); } static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_compiler *compiler, sljit_s32 op, @@ -2675,7 +2805,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compil switch (GET_OPCODE(op)) { case SLJIT_MOV_F64: if (src != dst_r) { - if (dst_r != TMP_FREG1) + if (!(dst & SLJIT_MEM)) FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VMOV_F32, op & SLJIT_32, dst_r, src, 0))); else dst_r = src; @@ -2745,7 +2875,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compil return push_inst(compiler, EMIT_FPU_OPERATION((VNEG_F32 & ~COND_MASK) | 0xb0000000, op & SLJIT_32, dst_r, dst_r, 0)); } - if (dst_r == TMP_FREG1) + if (dst_r != dst) FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_32), TMP_FREG1, dst, dstw)); return SLJIT_SUCCESS; @@ -2974,27 +3104,25 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile #if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) if (type >= SLJIT_FAST_CALL) PTR_FAIL_IF(prepare_blx(compiler)); + + jump->addr = compiler->size; PTR_FAIL_IF(push_inst_with_unique_literal(compiler, ((EMIT_DATA_TRANSFER(WORD_SIZE | LOAD_DATA, 1, type <= SLJIT_JUMP ? TMP_PC : TMP_REG1, TMP_PC, 0)) & ~COND_MASK) | get_cc(compiler, type), 0)); - if (jump->flags & SLJIT_REWRITABLE_JUMP) { - jump->addr = compiler->size; + if (jump->flags & SLJIT_REWRITABLE_JUMP) compiler->patches++; - } if (type >= SLJIT_FAST_CALL) { jump->flags |= IS_BL; + jump->addr = compiler->size; PTR_FAIL_IF(emit_blx(compiler)); } - - if (!(jump->flags & SLJIT_REWRITABLE_JUMP)) - jump->addr = compiler->size; #else /* !SLJIT_CONFIG_ARM_V6 */ + jump->addr = compiler->size; if (type >= SLJIT_FAST_CALL) jump->flags |= IS_BL; - PTR_FAIL_IF(emit_imm(compiler, TMP_REG1, 0)); PTR_FAIL_IF(push_inst(compiler, (((type <= SLJIT_JUMP ? BX : BLX) | RM(TMP_REG1)) & ~COND_MASK) | get_cc(compiler, type))); - jump->addr = compiler->size; + compiler->size += JUMP_MAX_SIZE - 1; #endif /* SLJIT_CONFIG_ARM_V6 */ return jump; } @@ -3264,14 +3392,17 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compi #if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) if (type >= SLJIT_FAST_CALL) FAIL_IF(prepare_blx(compiler)); + jump->addr = compiler->size; FAIL_IF(push_inst_with_unique_literal(compiler, EMIT_DATA_TRANSFER(WORD_SIZE | LOAD_DATA, 1, type <= SLJIT_JUMP ? TMP_PC : TMP_REG1, TMP_PC, 0), 0)); - if (type >= SLJIT_FAST_CALL) + if (type >= SLJIT_FAST_CALL) { + jump->addr = compiler->size; FAIL_IF(emit_blx(compiler)); + } #else /* !SLJIT_CONFIG_ARM_V6 */ - FAIL_IF(emit_imm(compiler, TMP_REG1, 0)); + jump->addr = compiler->size; FAIL_IF(push_inst(compiler, (type <= SLJIT_JUMP ? BX : BLX) | RM(TMP_REG1))); + compiler->size += JUMP_MAX_SIZE - 1; #endif /* SLJIT_CONFIG_ARM_V6 */ - jump->addr = compiler->size; return SLJIT_SUCCESS; } @@ -3425,7 +3556,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *comp } if (src1 & SLJIT_MEM) { - FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, (src2_reg != dst_reg) ? dst_reg : TMP_REG1, src1, src1w, TMP_REG2)); + FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, (src2_reg != dst_reg) ? dst_reg : TMP_REG1, src1, src1w, TMP_REG1)); if (src2_reg != dst_reg) { src1 = src2_reg; @@ -3488,8 +3619,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fselect(struct sljit_compiler *com } if (src1 & SLJIT_MEM) { - FAIL_IF(emit_fop_mem(compiler, (type & SLJIT_32) | FPU_LOAD, TMP_FREG1, src1, src1w)); - src1 = TMP_FREG1; + FAIL_IF(emit_fop_mem(compiler, (type & SLJIT_32) | FPU_LOAD, TMP_FREG2, src1, src1w)); + src1 = TMP_FREG2; } cc = get_cc(compiler, type & ~SLJIT_32); @@ -4444,6 +4575,10 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi CHECK_PTR(check_sljit_emit_const(compiler, dst, dstw, init_value)); ADJUST_LOCAL_OFFSET(dst, dstw); + const_ = (struct sljit_const*)ensure_abuf(compiler, sizeof(struct sljit_const)); + PTR_FAIL_IF(!const_); + set_const(const_, compiler); + dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2; #if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) @@ -4454,22 +4589,18 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi PTR_FAIL_IF(emit_imm(compiler, dst_r, init_value)); #endif /* SLJIT_CONFIG_ARM_V6 */ - const_ = (struct sljit_const*)ensure_abuf(compiler, sizeof(struct sljit_const)); - PTR_FAIL_IF(!const_); - set_const(const_, compiler); - if (dst & SLJIT_MEM) PTR_FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG2, dst, dstw, TMP_REG1)); return const_; } -SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label* sljit_emit_put_label(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw) +SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_mov_addr(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw) { - struct sljit_put_label *put_label; + struct sljit_jump *jump; sljit_s32 dst_r; CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_put_label(compiler, dst, dstw)); + CHECK_PTR(check_sljit_emit_mov_addr(compiler, dst, dstw)); ADJUST_LOCAL_OFFSET(dst, dstw); dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2; @@ -4478,24 +4609,28 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label* sljit_emit_put_label(struct slj PTR_FAIL_IF(push_inst_with_unique_literal(compiler, EMIT_DATA_TRANSFER(WORD_SIZE | LOAD_DATA, 1, dst_r, TMP_PC, 0), 0)); compiler->patches++; #else /* !SLJIT_CONFIG_ARM_V6 */ - PTR_FAIL_IF(emit_imm(compiler, dst_r, 0)); + PTR_FAIL_IF(push_inst(compiler, RD(dst_r))); #endif /* SLJIT_CONFIG_ARM_V6 */ - put_label = (struct sljit_put_label*)ensure_abuf(compiler, sizeof(struct sljit_put_label)); - PTR_FAIL_IF(!put_label); - set_put_label(put_label, compiler, 0); + jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump)); + PTR_FAIL_IF(!jump); + set_mov_addr(jump, compiler, 1); + +#if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) + compiler->size += 1; +#endif /* SLJIT_CONFIG_ARM_V7 */ if (dst & SLJIT_MEM) PTR_FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG2, dst, dstw, TMP_REG1)); - return put_label; + return jump; } SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset) { - inline_set_jump_addr(addr, executable_offset, new_target, 1); + set_jump_addr(addr, executable_offset, new_target, 1); } SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset) { - inline_set_const(addr, executable_offset, (sljit_uw)new_constant, 1); + set_const_value(addr, executable_offset, (sljit_uw)new_constant, 1); } diff --git a/src/sljit/sljitNativeARM_64.c b/src/sljit/sljitNativeARM_64.c index b268582..5331ebd 100644 --- a/src/sljit/sljitNativeARM_64.c +++ b/src/sljit/sljitNativeARM_64.c @@ -71,6 +71,8 @@ static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 3] = { #define ADD 0x8b000000 #define ADDE 0x8b200000 #define ADDI 0x91000000 +#define ADR 0x10000000 +#define ADRP 0x90000000 #define AND 0x8a000000 #define ANDI 0x92000000 #define AND_v 0x0e201c00 @@ -202,77 +204,263 @@ static SLJIT_INLINE sljit_s32 emit_imm64_const(struct sljit_compiler *compiler, return push_inst(compiler, MOVK | RD(dst) | ((sljit_ins)(imm >> 48) << 5) | (3 << 21)); } -static SLJIT_INLINE sljit_sw detect_jump_type(struct sljit_jump *jump, sljit_ins *code_ptr, sljit_ins *code, sljit_sw executable_offset) +static SLJIT_INLINE sljit_ins* detect_jump_type(struct sljit_jump *jump, sljit_ins *code_ptr, sljit_ins *code, sljit_sw executable_offset) { sljit_sw diff; sljit_uw target_addr; - if (jump->flags & SLJIT_REWRITABLE_JUMP) { - jump->flags |= PATCH_ABS64; - return 0; - } + if (jump->flags & SLJIT_REWRITABLE_JUMP) + goto exit; if (jump->flags & JUMP_ADDR) target_addr = jump->u.target; else { - SLJIT_ASSERT(jump->flags & JUMP_LABEL); + SLJIT_ASSERT(jump->u.label != NULL); target_addr = (sljit_uw)(code + jump->u.label->size) + (sljit_uw)executable_offset; } - diff = (sljit_sw)target_addr - (sljit_sw)(code_ptr - 4) - executable_offset; + diff = (sljit_sw)target_addr - (sljit_sw)code_ptr - executable_offset; if (jump->flags & IS_COND) { diff += SSIZE_OF(ins); if (diff <= 0xfffff && diff >= -0x100000) { - code_ptr[-5] ^= (jump->flags & IS_CBZ) ? (0x1 << 24) : 0x1; - jump->addr -= sizeof(sljit_ins); + *(--code_ptr) ^= (jump->flags & IS_CBZ) ? (0x1 << 24) : 0x1; jump->flags |= PATCH_COND; - return 5; + jump->addr -= sizeof(sljit_ins); + return code_ptr; } diff -= SSIZE_OF(ins); } if (diff <= 0x7ffffff && diff >= -0x8000000) { + if (jump->flags & IS_COND) + code_ptr[-1] -= (4 << 5); jump->flags |= PATCH_B; - return 4; + return code_ptr; } if (target_addr < 0x100000000l) { if (jump->flags & IS_COND) - code_ptr[-5] -= (2 << 5); - code_ptr[-2] = code_ptr[0]; - return 2; + code_ptr[-1] -= (2 << 5); + code_ptr[2] = code_ptr[0]; + return code_ptr + 2; + } + + if (diff <= 0xfffff000l && diff >= -0x100000000l) { + if (jump->flags & IS_COND) + code_ptr[-1] -= (2 << 5); + jump->flags |= PATCH_B32; + code_ptr[2] = code_ptr[0]; + return code_ptr + 2; } if (target_addr < 0x1000000000000l) { if (jump->flags & IS_COND) - code_ptr[-5] -= (1 << 5); + code_ptr[-1] -= (1 << 5); jump->flags |= PATCH_ABS48; - code_ptr[-1] = code_ptr[0]; - return 1; + code_ptr[3] = code_ptr[0]; + return code_ptr + 3; } +exit: jump->flags |= PATCH_ABS64; - return 0; + code_ptr[4] = code_ptr[0]; + return code_ptr + 4; } -static SLJIT_INLINE sljit_sw put_label_get_length(struct sljit_put_label *put_label, sljit_uw max_label) +static SLJIT_INLINE sljit_sw mov_addr_get_length(struct sljit_jump *jump, sljit_ins *code_ptr, sljit_ins *code, sljit_sw executable_offset) { - if (max_label < 0x100000000l) { - put_label->flags = 0; - return 2; + sljit_uw addr; + sljit_sw diff; + SLJIT_UNUSED_ARG(executable_offset); + + SLJIT_ASSERT(jump->flags < ((sljit_uw)4 << JUMP_SIZE_SHIFT)); + if (jump->flags & JUMP_ADDR) + addr = jump->u.target; + else + addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code + jump->u.label->size, executable_offset); + + diff = (sljit_sw)addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset); + + if (diff <= 0xfffff && diff >= -0x100000) { + jump->flags |= PATCH_B; + return 0; } - if (max_label < 0x1000000000000l) { - put_label->flags = 1; + if (diff <= 0xfffff000l && diff >= -0x100000000l) { + SLJIT_ASSERT(jump->flags >= ((sljit_uw)1 << JUMP_SIZE_SHIFT)); + jump->flags |= PATCH_B32; return 1; } - put_label->flags = 2; - return 0; + if (addr < 0x100000000l) { + SLJIT_ASSERT(jump->flags >= ((sljit_uw)1 << JUMP_SIZE_SHIFT)); + return 1; + } + + if (addr < 0x1000000000000l) { + SLJIT_ASSERT(jump->flags >= ((sljit_uw)2 << JUMP_SIZE_SHIFT)); + jump->flags |= PATCH_ABS48; + return 2; + } + + SLJIT_ASSERT(jump->flags >= ((sljit_uw)3 << JUMP_SIZE_SHIFT)); + jump->flags |= PATCH_ABS64; + return 3; +} + +static SLJIT_INLINE void generate_jump_or_mov_addr(struct sljit_jump *jump, sljit_sw executable_offset) +{ + sljit_sw addr = (sljit_sw)((jump->flags & JUMP_ADDR) ? jump->u.target : jump->u.label->u.addr); + sljit_ins* buf_ptr = (sljit_ins*)jump->addr; + sljit_u32 dst; + SLJIT_UNUSED_ARG(executable_offset); + + if (!(jump->flags & JUMP_MOV_ADDR)) { + if (jump->flags & PATCH_COND) { + addr = (addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset)) >> 2; + SLJIT_ASSERT(addr <= 0x3ffff && addr >= -0x40000); + buf_ptr[0] = (buf_ptr[0] & ~(sljit_ins)0xffffe0) | (sljit_ins)((addr & 0x7ffff) << 5); + return; + } + + if (jump->flags & PATCH_B) { + addr = (addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset)) >> 2; + SLJIT_ASSERT(addr <= 0x1ffffff && addr >= -0x2000000); + buf_ptr[0] = ((jump->flags & IS_BL) ? BL : B) | (sljit_ins)(addr & 0x3ffffff); + return; + } + + dst = (buf_ptr[0] >> 5) & 0x1f; + + if (jump->flags & PATCH_B32) { + addr -= (sljit_sw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset) & ~(sljit_sw)0xfff; + SLJIT_ASSERT(addr <= 0xfffff000l && addr >= -0x100000000l); + buf_ptr[0] = ADRP | (((sljit_ins)(addr >> 12) & 0x3) << 29) | (((sljit_ins)(addr >> 14) & 0x7ffff) << 5) | dst; + buf_ptr[1] = ADDI | dst | (dst << 5) | ((sljit_ins)(addr & 0xfff) << 10); + return; + } + } else { + dst = *buf_ptr; + + if (jump->flags & PATCH_B) { + addr -= (sljit_sw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset); + SLJIT_ASSERT(addr <= 0xfffff && addr >= -0x100000); + buf_ptr[0] = ADR | (((sljit_ins)addr & 0x3) << 29) | (((sljit_ins)(addr >> 2) & 0x7ffff) << 5) | dst; + return; + } + + if (jump->flags & PATCH_B32) { + addr -= ((sljit_sw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset)) & ~(sljit_sw)0xfff; + SLJIT_ASSERT(addr <= 0xffffffffl && addr >= -0x100000000l); + buf_ptr[0] = ADRP | (((sljit_ins)(addr >> 12) & 0x3) << 29) | (((sljit_ins)(addr >> 14) & 0x7ffff) << 5) | dst; + buf_ptr[1] = ADDI | dst | (dst << 5) | ((sljit_ins)(addr & 0xfff) << 10); + return; + } + } + + SLJIT_ASSERT((jump->flags & (PATCH_ABS48 | PATCH_ABS64)) || (sljit_uw)addr <= (sljit_uw)0xffffffff); + SLJIT_ASSERT((jump->flags & PATCH_ABS64) || (sljit_uw)addr <= (sljit_uw)0xffffffffffff); + + buf_ptr[0] = MOVZ | (((sljit_ins)addr & 0xffff) << 5) | dst; + buf_ptr[1] = MOVK | (((sljit_ins)(addr >> 16) & 0xffff) << 5) | (1 << 21) | dst; + if (jump->flags & (PATCH_ABS48 | PATCH_ABS64)) + buf_ptr[2] = MOVK | (((sljit_ins)(addr >> 32) & 0xffff) << 5) | (2 << 21) | dst; + + if (jump->flags & PATCH_ABS64) + buf_ptr[3] = MOVK | ((sljit_ins)((sljit_uw)addr >> 48) << 5) | (3 << 21) | dst; +} + +static void reduce_code_size(struct sljit_compiler *compiler) +{ + struct sljit_label *label; + struct sljit_jump *jump; + struct sljit_const *const_; + SLJIT_NEXT_DEFINE_TYPES; + sljit_uw total_size; + sljit_uw size_reduce = 0; + sljit_sw diff; + + label = compiler->labels; + jump = compiler->jumps; + const_ = compiler->consts; + SLJIT_NEXT_INIT_TYPES(); + + while (1) { + SLJIT_GET_NEXT_MIN(); + + if (next_min_addr == SLJIT_MAX_ADDRESS) + break; + + if (next_min_addr == next_label_size) { + label->size -= size_reduce; + + label = label->next; + next_label_size = SLJIT_GET_NEXT_SIZE(label); + } + + if (next_min_addr == next_const_addr) { + const_->addr -= size_reduce; + const_ = const_->next; + next_const_addr = SLJIT_GET_NEXT_ADDRESS(const_); + continue; + } + + if (next_min_addr != next_jump_addr) + continue; + + jump->addr -= size_reduce; + if (!(jump->flags & JUMP_MOV_ADDR)) { + total_size = JUMP_MAX_SIZE; + + if (!(jump->flags & SLJIT_REWRITABLE_JUMP)) { + if (jump->flags & JUMP_ADDR) { + if (jump->u.target < 0x100000000l) + total_size = 3; + else if (jump->u.target < 0x1000000000000l) + total_size = 4; + } else { + /* Unit size: instruction. */ + diff = (sljit_sw)jump->u.label->size - (sljit_sw)jump->addr; + + if ((jump->flags & IS_COND) && (diff + 1) <= (0xfffff / SSIZE_OF(ins)) && (diff + 1) >= (-0x100000 / SSIZE_OF(ins))) + total_size = 0; + else if (diff <= (0x7ffffff / SSIZE_OF(ins)) && diff >= (-0x8000000 / SSIZE_OF(ins))) + total_size = 1; + else if (diff <= (0xfffff000l / SSIZE_OF(ins)) && diff >= (-0x100000000l / SSIZE_OF(ins))) + total_size = 3; + } + } + + size_reduce += JUMP_MAX_SIZE - total_size; + } else { + /* Real size minus 1. Unit size: instruction. */ + total_size = 3; + + if (!(jump->flags & JUMP_ADDR)) { + diff = (sljit_sw)jump->u.label->size - (sljit_sw)jump->addr; + + if (diff <= (0xfffff / SSIZE_OF(ins)) && diff >= (-0x100000 / SSIZE_OF(ins))) + total_size = 0; + else if (diff <= (0xfffff000l / SSIZE_OF(ins)) && diff >= (-0x100000000l / SSIZE_OF(ins))) + total_size = 1; + } else if (jump->u.target < 0x100000000l) + total_size = 1; + else if (jump->u.target < 0x1000000000000l) + total_size = 2; + + size_reduce += 3 - total_size; + } + + jump->flags |= total_size << JUMP_SIZE_SHIFT; + jump = jump->next; + next_jump_addr = SLJIT_GET_NEXT_ADDRESS(jump); + } + + compiler->size -= size_reduce; } -SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler) +SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler, sljit_s32 options, void *exec_allocator_data) { struct sljit_memory_fragment *buf; sljit_ins *code; @@ -280,67 +468,73 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil sljit_ins *buf_ptr; sljit_ins *buf_end; sljit_uw word_count; - sljit_uw next_addr; + SLJIT_NEXT_DEFINE_TYPES; sljit_sw executable_offset; sljit_sw addr; - sljit_u32 dst; struct sljit_label *label; struct sljit_jump *jump; struct sljit_const *const_; - struct sljit_put_label *put_label; CHECK_ERROR_PTR(); CHECK_PTR(check_sljit_generate_code(compiler)); - reverse_buf(compiler); - code = (sljit_ins*)SLJIT_MALLOC_EXEC(compiler->size * sizeof(sljit_ins), compiler->exec_allocator_data); + reduce_code_size(compiler); + + code = (sljit_ins*)allocate_executable_memory(compiler->size * sizeof(sljit_ins), options, exec_allocator_data, &executable_offset); PTR_FAIL_WITH_EXEC_IF(code); + + reverse_buf(compiler); buf = compiler->buf; code_ptr = code; word_count = 0; - next_addr = 0; - executable_offset = SLJIT_EXEC_OFFSET(code); - label = compiler->labels; jump = compiler->jumps; const_ = compiler->consts; - put_label = compiler->put_labels; + SLJIT_NEXT_INIT_TYPES(); + SLJIT_GET_NEXT_MIN(); do { buf_ptr = (sljit_ins*)buf->memory; buf_end = buf_ptr + (buf->used_size >> 2); do { *code_ptr = *buf_ptr++; - if (next_addr == word_count) { + if (next_min_addr == word_count) { SLJIT_ASSERT(!label || label->size >= word_count); SLJIT_ASSERT(!jump || jump->addr >= word_count); SLJIT_ASSERT(!const_ || const_->addr >= word_count); - SLJIT_ASSERT(!put_label || put_label->addr >= word_count); /* These structures are ordered by their address. */ - if (label && label->size == word_count) { - label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset); + if (next_min_addr == next_label_size) { + label->u.addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset); label->size = (sljit_uw)(code_ptr - code); label = label->next; + next_label_size = SLJIT_GET_NEXT_SIZE(label); } - if (jump && jump->addr == word_count) { - jump->addr = (sljit_uw)(code_ptr - 4); - code_ptr -= detect_jump_type(jump, code_ptr, code, executable_offset); - jump = jump->next; - } - if (const_ && const_->addr == word_count) { + + if (next_min_addr == next_jump_addr) { + if (!(jump->flags & JUMP_MOV_ADDR)) { + word_count = word_count - 1 + (jump->flags >> JUMP_SIZE_SHIFT); + jump->addr = (sljit_uw)code_ptr; + code_ptr = detect_jump_type(jump, code_ptr, code, executable_offset); + SLJIT_ASSERT((jump->flags & PATCH_COND) || ((sljit_uw)code_ptr - jump->addr < (jump->flags >> JUMP_SIZE_SHIFT) * sizeof(sljit_ins))); + } else { + word_count += jump->flags >> JUMP_SIZE_SHIFT; + addr = (sljit_sw)code_ptr; + code_ptr += mov_addr_get_length(jump, code_ptr, code, executable_offset); + jump->addr = (sljit_uw)addr; + } + + jump = jump->next; + next_jump_addr = SLJIT_GET_NEXT_ADDRESS(jump); + } else if (next_min_addr == next_const_addr) { const_->addr = (sljit_uw)code_ptr; const_ = const_->next; + next_const_addr = SLJIT_GET_NEXT_ADDRESS(const_); } - if (put_label && put_label->addr == word_count) { - SLJIT_ASSERT(put_label->label); - put_label->addr = (sljit_uw)(code_ptr - 3); - code_ptr -= put_label_get_length(put_label, (sljit_uw)(SLJIT_ADD_EXEC_OFFSET(code, executable_offset) + put_label->label->size)); - put_label = put_label->next; - } - next_addr = compute_next_addr(label, jump, const_, put_label); + + SLJIT_GET_NEXT_MIN(); } code_ptr++; word_count++; @@ -350,7 +544,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil } while (buf); if (label && label->size == word_count) { - label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset); + label->u.addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset); label->size = (sljit_uw)(code_ptr - code); label = label->next; } @@ -358,61 +552,14 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil SLJIT_ASSERT(!label); SLJIT_ASSERT(!jump); SLJIT_ASSERT(!const_); - SLJIT_ASSERT(!put_label); SLJIT_ASSERT(code_ptr - code <= (sljit_sw)compiler->size); jump = compiler->jumps; while (jump) { - do { - addr = (sljit_sw)((jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target); - buf_ptr = (sljit_ins *)jump->addr; - - if (jump->flags & PATCH_B) { - addr = (addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset)) >> 2; - SLJIT_ASSERT(addr <= 0x1ffffff && addr >= -0x2000000); - buf_ptr[0] = ((jump->flags & IS_BL) ? BL : B) | (sljit_ins)(addr & 0x3ffffff); - if (jump->flags & IS_COND) - buf_ptr[-1] -= (4 << 5); - break; - } - if (jump->flags & PATCH_COND) { - addr = (addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset)) >> 2; - SLJIT_ASSERT(addr <= 0x3ffff && addr >= -0x40000); - buf_ptr[0] = (buf_ptr[0] & ~(sljit_ins)0xffffe0) | (sljit_ins)((addr & 0x7ffff) << 5); - break; - } - - SLJIT_ASSERT((jump->flags & (PATCH_ABS48 | PATCH_ABS64)) || (sljit_uw)addr <= (sljit_uw)0xffffffff); - SLJIT_ASSERT((jump->flags & PATCH_ABS64) || (sljit_uw)addr <= (sljit_uw)0xffffffffffff); - - dst = buf_ptr[0] & 0x1f; - buf_ptr[0] = MOVZ | dst | (((sljit_ins)addr & 0xffff) << 5); - buf_ptr[1] = MOVK | dst | (((sljit_ins)(addr >> 16) & 0xffff) << 5) | (1 << 21); - if (jump->flags & (PATCH_ABS48 | PATCH_ABS64)) - buf_ptr[2] = MOVK | dst | (((sljit_ins)(addr >> 32) & 0xffff) << 5) | (2 << 21); - if (jump->flags & PATCH_ABS64) - buf_ptr[3] = MOVK | dst | ((sljit_ins)(addr >> 48) << 5) | (3 << 21); - } while (0); + generate_jump_or_mov_addr(jump, executable_offset); jump = jump->next; } - put_label = compiler->put_labels; - while (put_label) { - addr = (sljit_sw)put_label->label->addr; - buf_ptr = (sljit_ins*)put_label->addr; - - buf_ptr[0] |= ((sljit_ins)addr & 0xffff) << 5; - buf_ptr[1] |= ((sljit_ins)(addr >> 16) & 0xffff) << 5; - - if (put_label->flags >= 1) - buf_ptr[2] |= ((sljit_ins)(addr >> 32) & 0xffff) << 5; - - if (put_label->flags >= 2) - buf_ptr[3] |= (sljit_ins)(addr >> 48) << 5; - - put_label = put_label->next; - } - compiler->error = SLJIT_ERR_COMPILED; compiler->executable_offset = executable_offset; compiler->executable_size = (sljit_uw)(code_ptr - code) * sizeof(sljit_ins); @@ -693,7 +840,6 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s imm = (flags & ARG2_IMM) ? arg2 : arg1; switch (op) { - case SLJIT_MUL: case SLJIT_CLZ: case SLJIT_CTZ: case SLJIT_REV: @@ -703,6 +849,8 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s case SLJIT_REV_S32: case SLJIT_ADDC: case SLJIT_SUBC: + case SLJIT_MUL: + case SLJIT_MULADD: /* No form with immediate operand (except imm 0, which is represented by a ZERO register). */ break; @@ -957,6 +1105,9 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s /* fallthrough */ case SLJIT_ROTR: return push_inst(compiler, (RORV ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2)); + case SLJIT_MULADD: + compiler->status_flags_state = 0; + return push_inst(compiler, (MADD ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2) | RT2(dst)); default: SLJIT_UNREACHABLE(); return SLJIT_SUCCESS; @@ -1031,14 +1182,20 @@ static sljit_s32 emit_op_mem(struct sljit_compiler *compiler, sljit_s32 flags, s if (argw <= 0xff && argw >= -0x100) return push_inst(compiler, STURBI | type | RT(reg) | RN(arg) | (((sljit_ins)argw & 0x1ff) << 12)); - if (argw >= 0) { - if (argw <= 0xfff0ff && ((argw + 0x100) & 0xfff) <= 0x1ff) { + if (((argw + 0x100) & 0xfff) <= 0x1ff && argw <= 0xfff0ff && argw >= -0xfff100) { + if (argw >= 0) { + if (argw & 0x100) + argw += 0x1000; + FAIL_IF(push_inst(compiler, ADDI | (1 << 22) | RD(tmp_reg) | RN(arg) | (((sljit_ins)argw >> 12) << 10))); return push_inst(compiler, STURBI | type | RT(reg) | RN(tmp_reg) | (((sljit_ins)argw & 0x1ff) << 12)); + } else { + if (!(argw & 0x100)) + argw -= 0x1000; + + FAIL_IF(push_inst(compiler, SUBI | (1 << 22) | RD(tmp_reg) | RN(arg) | (((sljit_ins)-argw >> 12) << 10))); + return push_inst(compiler, STURBI | type | RT(reg) | RN(tmp_reg) | (((sljit_ins)argw & 0x1ff) << 12)); } - } else if (argw >= -0xfff100 && ((-argw + 0xff) & 0xfff) <= 0x1ff) { - FAIL_IF(push_inst(compiler, SUBI | (1 << 22) | RD(tmp_reg) | RN(arg) | (((sljit_ins)-argw >> 12) << 10))); - return push_inst(compiler, STURBI | type | RT(reg) | RN(tmp_reg) | (((sljit_ins)argw & 0x1ff) << 12)); } FAIL_IF(load_immediate(compiler, tmp_reg, argw)); @@ -1422,7 +1579,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile op = GET_OPCODE(op); if (op >= SLJIT_MOV && op <= SLJIT_MOV_P) { /* Both operands are registers. */ - if (dst_r != TMP_REG1 && FAST_IS_REG(src)) + if (FAST_IS_REG(dst) && FAST_IS_REG(src)) return emit_op_imm(compiler, op | ((op_flags & SLJIT_32) ? INT_OP : 0), dst_r, TMP_REG1, src); switch (op) { @@ -1472,7 +1629,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile else if (!(src & SLJIT_MEM)) dst_r = src; else - FAIL_IF(emit_op_mem(compiler, mem_flags, dst_r, src, srcw, TMP_REG1)); + FAIL_IF(emit_op_mem(compiler, mem_flags, dst_r, src, srcw, TMP_REG2)); if (dst & SLJIT_MEM) return emit_op_mem(compiler, mem_flags | STORE, dst_r, dst, dstw, TMP_REG2); @@ -1534,7 +1691,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile mem_flags = INT_SIZE; } - if (dst == TMP_REG1) + if (dst == TMP_REG2) flags |= UNUSED_RETURN; if (src1 & SLJIT_MEM) { @@ -1572,7 +1729,24 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compil CHECK(check_sljit_emit_op2(compiler, op, 1, 0, 0, src1, src1w, src2, src2w)); SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_op2(compiler, op, TMP_REG1, 0, src1, src1w, src2, src2w); + return sljit_emit_op2(compiler, op, TMP_REG2, 0, src1, src1w, src2, src2w); +} + +SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2r(struct sljit_compiler *compiler, sljit_s32 op, + sljit_s32 dst_reg, + sljit_s32 src1, sljit_sw src1w, + sljit_s32 src2, sljit_sw src2w) +{ + CHECK_ERROR(); + CHECK(check_sljit_emit_op2r(compiler, op, dst_reg, src1, src1w, src2, src2w)); + + switch (GET_OPCODE(op)) { + case SLJIT_MULADD: + SLJIT_SKIP_CHECKS(compiler); + return sljit_emit_op2(compiler, op, dst_reg, 0, src1, src1w, src2, src2w); + } + + return SLJIT_SUCCESS; } SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *compiler, sljit_s32 op, @@ -1753,18 +1927,18 @@ static sljit_s32 emit_fop_mem(struct sljit_compiler *compiler, sljit_s32 flags, return push_inst(compiler, STR_FR | type | VT(reg) | RN(arg & REG_MASK) | RM(OFFS_REG(arg)) | (argw ? (1 << 12) : 0)); - FAIL_IF(push_inst(compiler, ADD | RD(TMP_REG1) | RN(arg & REG_MASK) | RM(OFFS_REG(arg)) | ((sljit_ins)argw << 10))); - return push_inst(compiler, STR_FI | type | VT(reg) | RN(TMP_REG1)); + FAIL_IF(push_inst(compiler, ADD | RD(TMP_REG2) | RN(arg & REG_MASK) | RM(OFFS_REG(arg)) | ((sljit_ins)argw << 10))); + return push_inst(compiler, STR_FI | type | VT(reg) | RN(TMP_REG2)); } arg &= REG_MASK; if (!arg) { - FAIL_IF(load_immediate(compiler, TMP_REG1, argw & ~(0xfff << shift))); + FAIL_IF(load_immediate(compiler, TMP_REG2, argw & ~(0xfff << shift))); argw = (argw >> shift) & 0xfff; - return push_inst(compiler, STR_FI | type | VT(reg) | RN(TMP_REG1) | ((sljit_ins)argw << 10)); + return push_inst(compiler, STR_FI | type | VT(reg) | RN(TMP_REG2) | ((sljit_ins)argw << 10)); } if (argw >= 0 && (argw & ((1 << shift) - 1)) == 0) { @@ -1772,18 +1946,18 @@ static sljit_s32 emit_fop_mem(struct sljit_compiler *compiler, sljit_s32 flags, return push_inst(compiler, STR_FI | type | VT(reg) | RN(arg) | ((sljit_ins)argw << (10 - shift))); if (argw <= 0xffffff) { - FAIL_IF(push_inst(compiler, ADDI | (1 << 22) | RD(TMP_REG1) | RN(arg) | (((sljit_ins)argw >> 12) << 10))); + FAIL_IF(push_inst(compiler, ADDI | (1 << 22) | RD(TMP_REG2) | RN(arg) | (((sljit_ins)argw >> 12) << 10))); argw = ((argw & 0xfff) >> shift); - return push_inst(compiler, STR_FI | type | VT(reg) | RN(TMP_REG1) | ((sljit_ins)argw << 10)); + return push_inst(compiler, STR_FI | type | VT(reg) | RN(TMP_REG2) | ((sljit_ins)argw << 10)); } } if (argw <= 255 && argw >= -256) return push_inst(compiler, STUR_FI | type | VT(reg) | RN(arg) | (((sljit_ins)argw & 0x1ff) << 12)); - FAIL_IF(load_immediate(compiler, TMP_REG1, argw)); - return push_inst(compiler, STR_FR | type | VT(reg) | RN(arg) | RM(TMP_REG1)); + FAIL_IF(load_immediate(compiler, TMP_REG2, argw)); + return push_inst(compiler, STR_FR | type | VT(reg) | RN(arg) | RM(TMP_REG2)); } static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_compiler *compiler, sljit_s32 op, @@ -1910,7 +2084,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compil switch (GET_OPCODE(op)) { case SLJIT_MOV_F64: if (src != dst_r) { - if (dst_r != TMP_FREG1) + if (!(dst & SLJIT_MEM)) FAIL_IF(push_inst(compiler, (FMOV ^ inv_bits) | VD(dst_r) | VN(src))); else dst_r = src; @@ -2180,14 +2354,14 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile if (type < SLJIT_JUMP) { jump->flags |= IS_COND; PTR_FAIL_IF(push_inst(compiler, B_CC | (6 << 5) | get_cc(compiler, type))); - } - else if (type >= SLJIT_FAST_CALL) + } else if (type >= SLJIT_FAST_CALL) jump->flags |= IS_BL; - PTR_FAIL_IF(emit_imm64_const(compiler, TMP_REG1, 0)); jump->addr = compiler->size; - PTR_FAIL_IF(push_inst(compiler, ((type >= SLJIT_FAST_CALL) ? BLR : BR) | RN(TMP_REG1))); + PTR_FAIL_IF(push_inst(compiler, ((type >= SLJIT_FAST_CALL) ? BLR : BR) | RN(TMP_REG2))); + /* Maximum number of instructions required for generating a constant. */ + compiler->size += JUMP_MAX_SIZE - 1; return jump; } @@ -2236,9 +2410,11 @@ static SLJIT_INLINE struct sljit_jump* emit_cmp_to0(struct sljit_compiler *compi inv_bits |= 1 << 24; PTR_FAIL_IF(push_inst(compiler, (CBZ ^ inv_bits) | (6 << 5) | RT(src))); - PTR_FAIL_IF(emit_imm64_const(compiler, TMP_REG1, 0)); jump->addr = compiler->size; - PTR_FAIL_IF(push_inst(compiler, BR | RN(TMP_REG1))); + PTR_FAIL_IF(push_inst(compiler, BR | RN(TMP_REG2))); + + /* Maximum number of instructions required for generating a constant. */ + compiler->size += JUMP_MAX_SIZE - 1; return jump; } @@ -2252,8 +2428,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compi if (src != SLJIT_IMM) { if (src & SLJIT_MEM) { ADJUST_LOCAL_OFFSET(src, srcw); - FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG1, src, srcw, TMP_REG1)); - src = TMP_REG1; + FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG2, src, srcw, TMP_REG2)); + src = TMP_REG2; } return push_inst(compiler, ((type >= SLJIT_FAST_CALL) ? BLR : BR) | RN(src)); } @@ -2264,9 +2440,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compi set_jump(jump, compiler, JUMP_ADDR | ((type >= SLJIT_FAST_CALL) ? IS_BL : 0)); jump->u.target = (sljit_uw)srcw; - FAIL_IF(emit_imm64_const(compiler, TMP_REG1, 0)); jump->addr = compiler->size; - return push_inst(compiler, ((type >= SLJIT_FAST_CALL) ? BLR : BR) | RN(TMP_REG1)); + /* Maximum number of instructions required for generating a constant. */ + compiler->size += JUMP_MAX_SIZE - 1; + return push_inst(compiler, ((type >= SLJIT_FAST_CALL) ? BLR : BR) | RN(TMP_REG2)); } SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compiler, sljit_s32 type, @@ -2314,7 +2491,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co if (GET_OPCODE(op) < SLJIT_ADD) { FAIL_IF(push_inst(compiler, CSINC | (cc << 12) | RD(dst_r) | RN(TMP_ZERO) | RM(TMP_ZERO))); - if (dst_r == TMP_REG1) { + if (dst & SLJIT_MEM) { mem_flags = (GET_OPCODE(op) == SLJIT_MOV ? WORD_SIZE : INT_SIZE) | STORE; return emit_op_mem(compiler, mem_flags, TMP_REG1, dst, dstw, TMP_REG2); } @@ -2361,11 +2538,11 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *comp if (src1 == SLJIT_IMM) { if (type & SLJIT_32) src1w = (sljit_s32)src1w; - FAIL_IF(load_immediate(compiler, TMP_REG1, src1w)); - src1 = TMP_REG1; + FAIL_IF(load_immediate(compiler, TMP_REG2, src1w)); + src1 = TMP_REG2; } else if (src1 & SLJIT_MEM) { - FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG1, src1, src1w, TMP_REG2)); - src1 = TMP_REG1; + FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG2, src1, src1w, TMP_REG2)); + src1 = TMP_REG2; } cc = get_cc(compiler, type & ~SLJIT_32); @@ -2386,8 +2563,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fselect(struct sljit_compiler *com ADJUST_LOCAL_OFFSET(src1, src1w); if (src1 & SLJIT_MEM) { - FAIL_IF(emit_fop_mem(compiler, (type & SLJIT_32) ? INT_SIZE : WORD_SIZE, TMP_FREG1, src1, src1w)); - src1 = TMP_FREG1; + FAIL_IF(emit_fop_mem(compiler, (type & SLJIT_32) ? INT_SIZE : WORD_SIZE, TMP_FREG2, src1, src1w)); + src1 = TMP_FREG2; } cc = get_cc(compiler, type & ~SLJIT_32); @@ -2554,13 +2731,13 @@ static sljit_s32 sljit_emit_simd_mem_offset(struct sljit_compiler *compiler, slj sljit_s32 mem = *mem_ptr; if (SLJIT_UNLIKELY(mem & OFFS_REG_MASK)) { - *mem_ptr = TMP_REG1; - return push_inst(compiler, ADD | RD(TMP_REG1) | RN(mem & REG_MASK) | RM(OFFS_REG(mem)) | ((sljit_ins)(memw & 0x3) << 10)); + *mem_ptr = TMP_REG2; + return push_inst(compiler, ADD | RD(TMP_REG2) | RN(mem & REG_MASK) | RM(OFFS_REG(mem)) | ((sljit_ins)(memw & 0x3) << 10)); } if (!(mem & REG_MASK)) { - *mem_ptr = TMP_REG1; - return load_immediate(compiler, TMP_REG1, memw); + *mem_ptr = TMP_REG2; + return load_immediate(compiler, TMP_REG2, memw); } mem &= REG_MASK; @@ -2570,11 +2747,11 @@ static sljit_s32 sljit_emit_simd_mem_offset(struct sljit_compiler *compiler, slj return SLJIT_SUCCESS; } - *mem_ptr = TMP_REG1; + *mem_ptr = TMP_REG2; if (memw < -0xffffff || memw > 0xffffff) { - FAIL_IF(load_immediate(compiler, TMP_REG1, memw)); - return push_inst(compiler, ADD | RD(TMP_REG1) | RN(TMP_REG1) | RM(mem)); + FAIL_IF(load_immediate(compiler, TMP_REG2, memw)); + return push_inst(compiler, ADD | RD(TMP_REG2) | RN(TMP_REG2) | RM(mem)); } ins = ADDI; @@ -2585,16 +2762,16 @@ static sljit_s32 sljit_emit_simd_mem_offset(struct sljit_compiler *compiler, slj } if (memw > 0xfff) { - FAIL_IF(push_inst(compiler, ins | (1 << 22) | RD(TMP_REG1) | RN(mem) | ((sljit_ins)(memw >> 12) << 10))); + FAIL_IF(push_inst(compiler, ins | (1 << 22) | RD(TMP_REG2) | RN(mem) | ((sljit_ins)(memw >> 12) << 10))); memw &= 0xfff; if (memw == 0) return SLJIT_SUCCESS; - mem = TMP_REG1; + mem = TMP_REG2; } - return push_inst(compiler, ins | RD(TMP_REG1) | RN(mem) | ((sljit_ins)memw << 10)); + return push_inst(compiler, ins | RD(TMP_REG2) | RN(mem) | ((sljit_ins)memw << 10)); } SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_mov(struct sljit_compiler *compiler, sljit_s32 type, @@ -2802,8 +2979,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_replicate(struct sljit_compil return push_inst(compiler, MOVI | imm | VD(freg)); } - FAIL_IF(load_immediate(compiler, TMP_REG1, srcw)); - src = TMP_REG1; + FAIL_IF(load_immediate(compiler, TMP_REG2, srcw)); + src = TMP_REG2; } return push_inst(compiler, DUP_g | ins | VD(freg) | RN(src)); @@ -2872,8 +3049,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_mov(struct sljit_compile if (elem_size < 3) srcdstw &= ((sljit_sw)1 << (((sljit_sw)1 << elem_size) << 3)) - 1; - FAIL_IF(load_immediate(compiler, TMP_REG1, srcdstw)); - srcdst = TMP_REG1; + FAIL_IF(load_immediate(compiler, TMP_REG2, srcdstw)); + srcdst = TMP_REG2; } if (type & SLJIT_SIMD_STORE) { @@ -3030,7 +3207,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_sign(struct sljit_compiler *c FAIL_IF(push_inst(compiler, USRA | (1 << 30) | (imms << 16) | VD(TMP_FREG1) | VN(TMP_FREG1))); - dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1; + dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2; ins = (0x1 << 16); if (reg_size == 4 && elem_size == 0) { @@ -3040,8 +3217,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_sign(struct sljit_compiler *c FAIL_IF(push_inst(compiler, UMOV | ins | RD(dst_r) | VN(TMP_FREG1))); - if (dst_r == TMP_REG1) - return emit_op_mem(compiler, STORE | ((type & SLJIT_32) ? INT_SIZE : WORD_SIZE), TMP_REG1, dst, dstw, TMP_REG2); + if (dst_r == TMP_REG2) + return emit_op_mem(compiler, STORE | ((type & SLJIT_32) ? INT_SIZE : WORD_SIZE), TMP_REG2, dst, dstw, TMP_REG1); return SLJIT_SUCCESS; } @@ -3264,26 +3441,28 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi return const_; } -SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label* sljit_emit_put_label(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw) +SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_mov_addr(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw) { - struct sljit_put_label *put_label; + struct sljit_jump *jump; sljit_s32 dst_r; CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_put_label(compiler, dst, dstw)); + CHECK_PTR(check_sljit_emit_mov_addr(compiler, dst, dstw)); ADJUST_LOCAL_OFFSET(dst, dstw); dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1; - PTR_FAIL_IF(emit_imm64_const(compiler, dst_r, 0)); + PTR_FAIL_IF(push_inst(compiler, RD(dst_r))); - put_label = (struct sljit_put_label*)ensure_abuf(compiler, sizeof(struct sljit_put_label)); - PTR_FAIL_IF(!put_label); - set_put_label(put_label, compiler, 1); + jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump)); + PTR_FAIL_IF(!jump); + set_mov_addr(jump, compiler, 1); + + compiler->size += 3; if (dst & SLJIT_MEM) PTR_FAIL_IF(emit_op_mem(compiler, WORD_SIZE | STORE, dst_r, dst, dstw, TMP_REG2)); - return put_label; + return jump; } SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset) diff --git a/src/sljit/sljitNativeARM_T2_32.c b/src/sljit/sljitNativeARM_T2_32.c index c27c50d..799954a 100644 --- a/src/sljit/sljitNativeARM_T2_32.c +++ b/src/sljit/sljitNativeARM_T2_32.c @@ -157,6 +157,7 @@ static const sljit_u8 freg_ebit_map[((SLJIT_NUMBER_OF_FLOAT_REGISTERS + 2) << 1) #define LSRSI 0x0800 #define LSR_W 0xfa20f000 #define LSR_WI 0xea4f0010 +#define MLA 0xfb000000 #define MOV 0x4600 #define MOVS 0x0000 #define MOVSI 0x2000 @@ -292,7 +293,7 @@ static sljit_s32 push_inst32(struct sljit_compiler *compiler, sljit_ins inst) return SLJIT_SUCCESS; } -static SLJIT_INLINE sljit_s32 emit_imm32_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_uw imm) +static sljit_s32 emit_imm32_const(struct sljit_compiler *compiler, sljit_s32 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))); @@ -300,137 +301,262 @@ static SLJIT_INLINE sljit_s32 emit_imm32_const(struct sljit_compiler *compiler, | COPY_BITS(imm, 12 + 16, 16, 4) | COPY_BITS(imm, 11 + 16, 26, 1) | COPY_BITS(imm, 8 + 16, 12, 3) | ((imm & 0xff0000) >> 16)); } -static SLJIT_INLINE void modify_imm32_const(sljit_u16 *inst, sljit_uw new_imm) +/* Dst must be in bits[11-8] */ +static void set_imm32_const(sljit_u16 *inst, sljit_ins dst, sljit_uw new_imm) { - sljit_ins dst = inst[1] & 0x0f00; - SLJIT_ASSERT(((inst[0] & 0xfbf0) == (MOVW >> 16)) && ((inst[2] & 0xfbf0) == (MOVT >> 16)) && dst == (inst[3] & 0x0f00)); inst[0] = (sljit_u16)((MOVW >> 16) | COPY_BITS(new_imm, 12, 0, 4) | COPY_BITS(new_imm, 11, 10, 1)); inst[1] = (sljit_u16)(dst | COPY_BITS(new_imm, 8, 12, 3) | (new_imm & 0xff)); inst[2] = (sljit_u16)((MOVT >> 16) | COPY_BITS(new_imm, 12 + 16, 0, 4) | COPY_BITS(new_imm, 11 + 16, 10, 1)); inst[3] = (sljit_u16)(dst | COPY_BITS(new_imm, 8 + 16, 12, 3) | ((new_imm & 0xff0000) >> 16)); } -static SLJIT_INLINE sljit_s32 detect_jump_type(struct sljit_jump *jump, sljit_u16 *code_ptr, sljit_u16 *code, sljit_sw executable_offset) +static SLJIT_INLINE void modify_imm32_const(sljit_u16 *inst, sljit_uw new_imm) +{ + sljit_ins dst = inst[1] & 0x0f00; + SLJIT_ASSERT(((inst[0] & 0xfbf0) == (MOVW >> 16)) && ((inst[2] & 0xfbf0) == (MOVT >> 16)) && dst == (inst[3] & 0x0f00)); + set_imm32_const(inst, dst, new_imm); +} + +static SLJIT_INLINE sljit_u16* detect_jump_type(struct sljit_jump *jump, sljit_u16 *code_ptr, sljit_u16 *code, sljit_sw executable_offset) { sljit_sw diff; if (jump->flags & SLJIT_REWRITABLE_JUMP) - return 0; + goto exit; if (jump->flags & JUMP_ADDR) { /* Branch to ARM code is not optimized yet. */ if (!(jump->u.target & 0x1)) - return 0; - diff = ((sljit_sw)jump->u.target - (sljit_sw)(code_ptr + 2) - executable_offset) >> 1; - } - else { - SLJIT_ASSERT(jump->flags & JUMP_LABEL); - diff = ((sljit_sw)(code + jump->u.label->size) - (sljit_sw)(code_ptr + 2)) >> 1; + goto exit; + diff = (sljit_sw)jump->u.target - (sljit_sw)(code_ptr + 2) - executable_offset; + } else { + SLJIT_ASSERT(jump->u.label != NULL); + diff = (sljit_sw)(code + jump->u.label->size) - (sljit_sw)(code_ptr + 2); } if (jump->flags & IS_COND) { SLJIT_ASSERT(!(jump->flags & IS_BL)); - if (diff <= 127 && diff >= -128) { + /* Size of the prefix IT instruction. */ + diff += SSIZE_OF(u16); + if (diff <= 0xff && diff >= -0x100) { jump->flags |= PATCH_TYPE1; - return 5; + jump->addr = (sljit_uw)(code_ptr - 1); + return code_ptr - 1; } - if (diff <= 524287 && diff >= -524288) { + if (diff <= 0xfffff && diff >= -0x100000) { jump->flags |= PATCH_TYPE2; - return 4; + jump->addr = (sljit_uw)(code_ptr - 1); + return code_ptr; } - /* +1 comes from the prefix IT instruction. */ - diff--; - if (diff <= 8388607 && diff >= -8388608) { - jump->flags |= PATCH_TYPE3; - return 3; + diff -= SSIZE_OF(u16); + } else if (jump->flags & IS_BL) { + /* Branch and link. */ + if (diff <= 0xffffff && diff >= -0x1000000) { + jump->flags |= PATCH_TYPE5; + return code_ptr + 1; } + goto exit; + } else if (diff <= 0x7ff && diff >= -0x800) { + jump->flags |= PATCH_TYPE3; + return code_ptr; } - else if (jump->flags & IS_BL) { - if (diff <= 8388607 && diff >= -8388608) { - jump->flags |= PATCH_BL; - return 3; - } + + if (diff <= 0xffffff && diff >= -0x1000000) { + jump->flags |= PATCH_TYPE4; + return code_ptr + 1; } - else { - if (diff <= 1023 && diff >= -1024) { - jump->flags |= PATCH_TYPE4; - return 4; - } - if (diff <= 8388607 && diff >= -8388608) { - jump->flags |= PATCH_TYPE5; - return 3; - } + +exit: + code_ptr[4] = code_ptr[0]; + + if (jump->flags & IS_COND) { + code_ptr[3] = code_ptr[-1]; + jump->addr = (sljit_uw)(code_ptr - 1); + } + + return code_ptr + 4; +} + +static SLJIT_INLINE sljit_sw mov_addr_get_length(struct sljit_jump *jump, sljit_u16 *code_ptr, sljit_u16 *code, sljit_sw executable_offset) +{ + sljit_uw addr; + sljit_sw diff; + SLJIT_UNUSED_ARG(executable_offset); + + if (jump->flags & JUMP_ADDR) + addr = jump->u.target; + else + addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code + jump->u.label->size, executable_offset); + + /* The pc+4 offset is represented by the 2 * SSIZE_OF(sljit_u16) below. */ + diff = (sljit_sw)addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset); + + /* Note: ADR with imm8 does not set the last bit (Thumb2 flag). */ + + if (diff <= 0xffd + 2 * SSIZE_OF(u16) && diff >= -0xfff + 2 * SSIZE_OF(u16)) { + jump->flags |= PATCH_TYPE6; + return 1; } - return 0; + return 3; } -static SLJIT_INLINE void set_jump_instruction(struct sljit_jump *jump, sljit_sw executable_offset) +static SLJIT_INLINE void generate_jump_or_mov_addr(struct sljit_jump *jump, sljit_sw executable_offset) { sljit_s32 type = (jump->flags >> 4) & 0xf; + sljit_u16 *jump_inst = (sljit_u16*)jump->addr; sljit_sw diff; - sljit_u16 *jump_inst; - sljit_s32 s, j1, j2; + sljit_ins ins; + + diff = (sljit_sw)((jump->flags & JUMP_ADDR) ? jump->u.target : jump->u.label->u.addr); if (SLJIT_UNLIKELY(type == 0)) { - modify_imm32_const((sljit_u16*)jump->addr, (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target); + ins = (jump->flags & JUMP_MOV_ADDR) ? *jump_inst : RDN3(TMP_REG1); + set_imm32_const((sljit_u16*)jump->addr, ins, (sljit_uw)diff); return; } - if (jump->flags & JUMP_ADDR) { - SLJIT_ASSERT(jump->u.target & 0x1); - diff = ((sljit_sw)jump->u.target - (sljit_sw)(jump->addr + sizeof(sljit_u32)) - executable_offset) >> 1; - } - else { - SLJIT_ASSERT(jump->u.label->addr & 0x1); - diff = ((sljit_sw)(jump->u.label->addr) - (sljit_sw)(jump->addr + sizeof(sljit_u32)) - executable_offset) >> 1; + if (SLJIT_UNLIKELY(type == 6)) { + SLJIT_ASSERT(jump->flags & JUMP_MOV_ADDR); + diff -= (sljit_sw)SLJIT_ADD_EXEC_OFFSET(jump_inst + 2, executable_offset) & ~(sljit_sw)0x3; + + SLJIT_ASSERT(diff <= 0xfff && diff >= -0xfff); + + ins = ADDWI >> 16; + if (diff <= 0) { + diff = -diff; + ins = SUBWI >> 16; + } + + jump_inst[1] = (sljit_u16)(jump_inst[0] | COPY_BITS(diff, 8, 12, 3) | (diff & 0xff)); + jump_inst[0] = (sljit_u16)(ins | 0xf | COPY_BITS(diff, 11, 10, 1)); + return; } - jump_inst = (sljit_u16*)jump->addr; + + SLJIT_ASSERT((diff & 0x1) != 0 && !(jump->flags & JUMP_MOV_ADDR)); + diff = (diff - (sljit_sw)(jump->addr + sizeof(sljit_u32)) - executable_offset) >> 1; switch (type) { case 1: /* Encoding T1 of 'B' instruction */ - SLJIT_ASSERT(diff <= 127 && diff >= -128 && (jump->flags & IS_COND)); + SLJIT_ASSERT(diff <= 0x7f && diff >= -0x80 && (jump->flags & IS_COND)); jump_inst[0] = (sljit_u16)(0xd000 | (jump->flags & 0xf00) | ((sljit_ins)diff & 0xff)); return; case 2: /* Encoding T3 of 'B' instruction */ - SLJIT_ASSERT(diff <= 524287 && diff >= -524288 && (jump->flags & IS_COND)); + SLJIT_ASSERT(diff <= 0x7ffff && diff >= -0x80000 && (jump->flags & IS_COND)); jump_inst[0] = (sljit_u16)(0xf000 | COPY_BITS(jump->flags, 8, 6, 4) | COPY_BITS(diff, 11, 0, 6) | COPY_BITS(diff, 19, 10, 1)); jump_inst[1] = (sljit_u16)(0x8000 | COPY_BITS(diff, 17, 13, 1) | COPY_BITS(diff, 18, 11, 1) | ((sljit_ins)diff & 0x7ff)); return; case 3: - SLJIT_ASSERT(jump->flags & IS_COND); - *jump_inst++ = (sljit_u16)(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_COND)); + SLJIT_ASSERT(diff <= 0x3ff && diff >= -0x400 && !(jump->flags & IS_COND)); jump_inst[0] = (sljit_u16)(0xe000 | (diff & 0x7ff)); return; } - SLJIT_ASSERT(diff <= 8388607 && diff >= -8388608); + SLJIT_ASSERT(diff <= 0x7fffff && diff >= -0x800000); + + /* Really complex instruction form for branches. Negate with sign bit. */ + diff ^= ((diff >> 2) & 0x600000) ^ 0x600000; - /* Really complex instruction form for branches. */ - s = (diff >> 23) & 0x1; - j1 = (~(diff >> 22) ^ s) & 0x1; - j2 = (~(diff >> 21) ^ s) & 0x1; - jump_inst[0] = (sljit_u16)(0xf000 | ((sljit_ins)s << 10) | COPY_BITS(diff, 11, 0, 10)); - jump_inst[1] = (sljit_u16)((j1 << 13) | (j2 << 11) | (diff & 0x7ff)); + jump_inst[0] = (sljit_u16)(0xf000 | COPY_BITS(diff, 11, 0, 10) | COPY_BITS(diff, 23, 10, 1)); + jump_inst[1] = (sljit_u16)((diff & 0x7ff) | COPY_BITS(diff, 22, 13, 1) | COPY_BITS(diff, 21, 11, 1)); + + SLJIT_ASSERT(type == 4 || type == 5); /* The others have a common form. */ - if (type == 5) /* Encoding T4 of 'B' instruction */ + if (type == 4) /* Encoding T4 of 'B' instruction */ jump_inst[1] |= 0x9000; - else if (type == 6) /* Encoding T1 of 'BL' instruction */ + else /* Encoding T1 of 'BL' instruction */ jump_inst[1] |= 0xd000; - else - SLJIT_UNREACHABLE(); } -SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler) +static void reduce_code_size(struct sljit_compiler *compiler) +{ + struct sljit_label *label; + struct sljit_jump *jump; + struct sljit_const *const_; + SLJIT_NEXT_DEFINE_TYPES; + sljit_uw total_size; + sljit_uw size_reduce = 0; + sljit_sw diff; + + label = compiler->labels; + jump = compiler->jumps; + const_ = compiler->consts; + SLJIT_NEXT_INIT_TYPES(); + + while (1) { + SLJIT_GET_NEXT_MIN(); + + if (next_min_addr == SLJIT_MAX_ADDRESS) + break; + + if (next_min_addr == next_label_size) { + label->size -= size_reduce; + + label = label->next; + next_label_size = SLJIT_GET_NEXT_SIZE(label); + } + + if (next_min_addr == next_const_addr) { + const_->addr -= size_reduce; + const_ = const_->next; + next_const_addr = SLJIT_GET_NEXT_ADDRESS(const_); + continue; + } + + if (next_min_addr != next_jump_addr) + continue; + + jump->addr -= size_reduce; + if (!(jump->flags & JUMP_MOV_ADDR)) { + total_size = JUMP_MAX_SIZE; + + if (!(jump->flags & (SLJIT_REWRITABLE_JUMP | JUMP_ADDR))) { + /* Unit size: instruction. */ + diff = (sljit_sw)jump->u.label->size - (sljit_sw)jump->addr - 2; + + if (jump->flags & IS_COND) { + diff++; + + if (diff <= (0xff / SSIZE_OF(u16)) && diff >= (-0x100 / SSIZE_OF(u16))) + total_size = 0; + else if (diff <= (0xfffff / SSIZE_OF(u16)) && diff >= (-0x100000 / SSIZE_OF(u16))) + total_size = 1; + diff--; + } else if (!(jump->flags & IS_BL) && diff <= (0x7ff / SSIZE_OF(u16)) && diff >= (-0x800 / SSIZE_OF(u16))) + total_size = 1; + + if (total_size == JUMP_MAX_SIZE && diff <= (0xffffff / SSIZE_OF(u16)) && diff >= (-0x1000000 / SSIZE_OF(u16))) + total_size = 2; + } + + size_reduce += JUMP_MAX_SIZE - total_size; + } else { + /* Real size minus 1. Unit size: instruction. */ + total_size = 3; + + if (!(jump->flags & JUMP_ADDR)) { + diff = (sljit_sw)jump->u.label->size - (sljit_sw)jump->addr; + + if (diff <= (0xffd / SSIZE_OF(u16)) && diff >= (-0xfff / SSIZE_OF(u16))) + total_size = 1; + } + + size_reduce += 3 - total_size; + } + + jump->flags |= total_size << JUMP_SIZE_SHIFT; + jump = jump->next; + next_jump_addr = SLJIT_GET_NEXT_ADDRESS(jump); + } + + compiler->size -= size_reduce; +} + +SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler, sljit_s32 options, void *exec_allocator_data) { struct sljit_memory_fragment *buf; sljit_u16 *code; @@ -438,64 +564,74 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil sljit_u16 *buf_ptr; sljit_u16 *buf_end; sljit_uw half_count; - sljit_uw next_addr; + SLJIT_NEXT_DEFINE_TYPES; + sljit_sw addr; sljit_sw executable_offset; struct sljit_label *label; struct sljit_jump *jump; struct sljit_const *const_; - struct sljit_put_label *put_label; CHECK_ERROR_PTR(); CHECK_PTR(check_sljit_generate_code(compiler)); - reverse_buf(compiler); - code = (sljit_u16*)SLJIT_MALLOC_EXEC(compiler->size * sizeof(sljit_u16), compiler->exec_allocator_data); + reduce_code_size(compiler); + + code = (sljit_u16*)allocate_executable_memory(compiler->size * sizeof(sljit_u16), options, exec_allocator_data, &executable_offset); PTR_FAIL_WITH_EXEC_IF(code); + + reverse_buf(compiler); buf = compiler->buf; code_ptr = code; half_count = 0; - next_addr = 0; - executable_offset = SLJIT_EXEC_OFFSET(code); - label = compiler->labels; jump = compiler->jumps; const_ = compiler->consts; - put_label = compiler->put_labels; + SLJIT_NEXT_INIT_TYPES(); + SLJIT_GET_NEXT_MIN(); do { buf_ptr = (sljit_u16*)buf->memory; buf_end = buf_ptr + (buf->used_size >> 1); do { *code_ptr = *buf_ptr++; - if (next_addr == half_count) { + if (next_min_addr == half_count) { SLJIT_ASSERT(!label || label->size >= half_count); SLJIT_ASSERT(!jump || jump->addr >= half_count); SLJIT_ASSERT(!const_ || const_->addr >= half_count); - SLJIT_ASSERT(!put_label || put_label->addr >= half_count); /* These structures are ordered by their address. */ - if (label && label->size == half_count) { - label->addr = ((sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset)) | 0x1; + if (next_min_addr == next_label_size) { + label->u.addr = ((sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset)) | 0x1; label->size = (sljit_uw)(code_ptr - code); label = label->next; + next_label_size = SLJIT_GET_NEXT_SIZE(label); } - if (jump && jump->addr == half_count) { - jump->addr = (sljit_uw)code_ptr - ((jump->flags & IS_COND) ? 10 : 8); - code_ptr -= detect_jump_type(jump, code_ptr, code, executable_offset); - jump = jump->next; - } - if (const_ && const_->addr == half_count) { + + if (next_min_addr == next_jump_addr) { + if (!(jump->flags & JUMP_MOV_ADDR)) { + half_count = half_count - 1 + (jump->flags >> JUMP_SIZE_SHIFT); + jump->addr = (sljit_uw)code_ptr; + code_ptr = detect_jump_type(jump, code_ptr, code, executable_offset); + SLJIT_ASSERT((sljit_uw)code_ptr - jump->addr < + ((jump->flags >> JUMP_SIZE_SHIFT) + ((jump->flags & 0xf0) <= PATCH_TYPE2)) * sizeof(sljit_u16)); + } else { + half_count += jump->flags >> JUMP_SIZE_SHIFT; + addr = (sljit_sw)code_ptr; + code_ptr += mov_addr_get_length(jump, code_ptr, code, executable_offset); + jump->addr = (sljit_uw)addr; + } + + jump = jump->next; + next_jump_addr = SLJIT_GET_NEXT_ADDRESS(jump); + } else if (next_min_addr == next_const_addr) { const_->addr = (sljit_uw)code_ptr; const_ = const_->next; + next_const_addr = SLJIT_GET_NEXT_ADDRESS(const_); } - if (put_label && put_label->addr == half_count) { - SLJIT_ASSERT(put_label->label); - put_label->addr = (sljit_uw)code_ptr; - put_label = put_label->next; - } - next_addr = compute_next_addr(label, jump, const_, put_label); + + SLJIT_GET_NEXT_MIN(); } code_ptr++; half_count++; @@ -505,7 +641,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil } while (buf); if (label && label->size == half_count) { - label->addr = ((sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset)) | 0x1; + label->u.addr = ((sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset)) | 0x1; label->size = (sljit_uw)(code_ptr - code); label = label->next; } @@ -513,21 +649,14 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil SLJIT_ASSERT(!label); SLJIT_ASSERT(!jump); SLJIT_ASSERT(!const_); - SLJIT_ASSERT(!put_label); SLJIT_ASSERT(code_ptr - code <= (sljit_sw)compiler->size); jump = compiler->jumps; while (jump) { - set_jump_instruction(jump, executable_offset); + generate_jump_or_mov_addr(jump, executable_offset); jump = jump->next; } - put_label = compiler->put_labels; - while (put_label) { - modify_imm32_const((sljit_u16 *)put_label->addr, put_label->label->addr); - put_label = put_label->next; - } - compiler->error = SLJIT_ERR_COMPILED; compiler->executable_offset = executable_offset; compiler->executable_size = (sljit_uw)(code_ptr - code) * sizeof(sljit_u16); @@ -657,10 +786,11 @@ static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst, /* SET_FLAGS must be 0x100000 as it is also the value of S bit (can be used for optimization). */ #define SET_FLAGS 0x0100000 #define UNUSED_RETURN 0x0200000 +#define REGISTER_OP 0x0400000 static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 dst, sljit_uw arg1, sljit_uw arg2) { - /* dst must be register, TMP_REG1 + /* dst must be register arg1 must be register, imm arg2 must be register, imm */ sljit_s32 reg; @@ -686,6 +816,7 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s case SLJIT_REV_U32: case SLJIT_REV_S32: case SLJIT_MUL: + case SLJIT_MULADD: /* No form with immediate operand. */ break; case SLJIT_MOV: @@ -921,17 +1052,17 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s return push_inst32(compiler, REV_W | RN4(arg2) | RD4(dst) | RM4(arg2)); case SLJIT_REV_U16: case SLJIT_REV_S16: - SLJIT_ASSERT(arg1 == TMP_REG2 && dst != TMP_REG2); + SLJIT_ASSERT(arg1 == TMP_REG2); - flags &= 0xffff; if (IS_2_LO_REGS(dst, arg2)) FAIL_IF(push_inst16(compiler, REV16 | RD3(dst) | RN3(arg2))); else FAIL_IF(push_inst32(compiler, REV16_W | RN4(arg2) | RD4(dst) | RM4(arg2))); - if (dst == TMP_REG1 || (arg2 == TMP_REG1 && flags == SLJIT_REV_U16)) + if (!(flags & REGISTER_OP)) return SLJIT_SUCCESS; + flags &= 0xffff; if (reg_map[dst] <= 7) return push_inst16(compiler, (flags == SLJIT_REV_U16 ? UXTH : SXTH) | RD3(dst) | RN3(dst)); return push_inst32(compiler, (flags == SLJIT_REV_U16 ? UXTH_W : SXTH_W) | RD4(dst) | RM4(dst)); @@ -966,10 +1097,10 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s compiler->status_flags_state = 0; if (!(flags & SET_FLAGS)) return push_inst32(compiler, MUL | RD4(dst) | RN4(arg1) | RM4(arg2)); - SLJIT_ASSERT(dst != TMP_REG2); - FAIL_IF(push_inst32(compiler, SMULL | RT4(dst) | RD4(TMP_REG2) | RN4(arg1) | RM4(arg2))); + reg = (dst == TMP_REG2) ? TMP_REG1 : TMP_REG2; + FAIL_IF(push_inst32(compiler, SMULL | RT4(dst) | RD4(reg) | RN4(arg1) | RM4(arg2))); /* cmp TMP_REG2, dst asr #31. */ - return push_inst32(compiler, CMP_W | RN4(TMP_REG2) | 0x70e0 | RM4(dst)); + return push_inst32(compiler, CMP_W | RN4(reg) | 0x70e0 | RM4(dst)); case SLJIT_AND: if (dst == (sljit_s32)arg1 && IS_2_LO_REGS(dst, arg2)) return push_inst16(compiler, ANDS | RD3(dst) | RN3(arg2)); @@ -985,37 +1116,44 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s return push_inst16(compiler, EORS | RD3(dst) | RN3(arg2)); return push_inst32(compiler, EOR_W | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2)); case SLJIT_MSHL: - FAIL_IF(push_inst32(compiler, ANDI | RD4(TMP_REG2) | RN4(arg2) | 0x1f)); - arg2 = TMP_REG2; + reg = (arg2 == TMP_REG1) ? TMP_REG1 : TMP_REG2; + FAIL_IF(push_inst32(compiler, ANDI | RD4(reg) | RN4(arg2) | 0x1f)); + arg2 = (sljit_uw)reg; /* fallthrough */ case SLJIT_SHL: if (dst == (sljit_s32)arg1 && IS_2_LO_REGS(dst, arg2)) return push_inst16(compiler, LSLS | RD3(dst) | RN3(arg2)); return push_inst32(compiler, LSL_W | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2)); case SLJIT_MLSHR: - FAIL_IF(push_inst32(compiler, ANDI | RD4(TMP_REG2) | RN4(arg2) | 0x1f)); - arg2 = TMP_REG2; + reg = (arg2 == TMP_REG1) ? TMP_REG1 : TMP_REG2; + FAIL_IF(push_inst32(compiler, ANDI | RD4(reg) | RN4(arg2) | 0x1f)); + arg2 = (sljit_uw)reg; /* fallthrough */ case SLJIT_LSHR: if (dst == (sljit_s32)arg1 && IS_2_LO_REGS(dst, arg2)) return push_inst16(compiler, LSRS | RD3(dst) | RN3(arg2)); return push_inst32(compiler, LSR_W | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2)); case SLJIT_MASHR: - FAIL_IF(push_inst32(compiler, ANDI | RD4(TMP_REG2) | RN4(arg2) | 0x1f)); - arg2 = TMP_REG2; + reg = (arg2 == TMP_REG1) ? TMP_REG1 : TMP_REG2; + FAIL_IF(push_inst32(compiler, ANDI | RD4(reg) | RN4(arg2) | 0x1f)); + arg2 = (sljit_uw)reg; /* fallthrough */ case SLJIT_ASHR: if (dst == (sljit_s32)arg1 && IS_2_LO_REGS(dst, arg2)) return push_inst16(compiler, ASRS | RD3(dst) | RN3(arg2)); return push_inst32(compiler, ASR_W | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2)); case SLJIT_ROTL: - FAIL_IF(push_inst32(compiler, RSB_WI | RD4(TMP_REG2) | RN4(arg2) | 0)); - arg2 = TMP_REG2; + reg = (arg2 == TMP_REG1) ? TMP_REG1 : TMP_REG2; + FAIL_IF(push_inst32(compiler, RSB_WI | RD4(reg) | RN4(arg2) | 0)); + arg2 = (sljit_uw)reg; /* fallthrough */ case SLJIT_ROTR: if (dst == (sljit_s32)arg1 && IS_2_LO_REGS(dst, arg2)) return push_inst16(compiler, RORS | RD3(dst) | RN3(arg2)); return push_inst32(compiler, ROR_W | RD4(dst) | RN4(arg1) | RM4(arg2)); + case SLJIT_MULADD: + compiler->status_flags_state = 0; + return push_inst32(compiler, MLA | RD4(dst) | RN4(arg1) | RM4(arg2) | RT4(dst)); } SLJIT_UNREACHABLE(); @@ -1779,14 +1917,13 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile sljit_s32 src, sljit_sw srcw) { sljit_s32 dst_r, flags; - sljit_s32 op_flags = GET_ALL_FLAGS(op); CHECK_ERROR(); CHECK(check_sljit_emit_op1(compiler, op, dst, dstw, src, srcw)); ADJUST_LOCAL_OFFSET(dst, dstw); ADJUST_LOCAL_OFFSET(src, srcw); - dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1; + dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2; op = GET_OPCODE(op); if (op >= SLJIT_MOV && op <= SLJIT_MOV_P) { @@ -1826,35 +1963,37 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile if (src == SLJIT_IMM) FAIL_IF(emit_op_imm(compiler, SLJIT_MOV | ARG2_IMM, dst_r, TMP_REG2, (sljit_uw)srcw)); - else if (src & SLJIT_MEM) { + else if (src & SLJIT_MEM) FAIL_IF(emit_op_mem(compiler, flags, dst_r, src, srcw, TMP_REG1)); - } else { - if (dst_r != TMP_REG1) - return emit_op_imm(compiler, op, dst_r, TMP_REG2, (sljit_uw)src); + else if (FAST_IS_REG(dst)) + return emit_op_imm(compiler, op, dst_r, TMP_REG2, (sljit_uw)src); + else dst_r = src; - } if (!(dst & SLJIT_MEM)) return SLJIT_SUCCESS; - return emit_op_mem(compiler, flags | STORE, dst_r, dst, dstw, TMP_REG2); + return emit_op_mem(compiler, flags | STORE, dst_r, dst, dstw, TMP_REG1); } SLJIT_COMPILE_ASSERT(WORD_SIZE == 0, word_size_must_be_0); - flags = HAS_FLAGS(op_flags) ? SET_FLAGS : 0; + flags = WORD_SIZE; - if (op == SLJIT_REV_U16 || op == SLJIT_REV_S16) + if (op == SLJIT_REV_U16 || op == SLJIT_REV_S16) { + if (!(dst & SLJIT_MEM) && (!(src & SLJIT_MEM) || op == SLJIT_REV_S16)) + op |= REGISTER_OP; flags |= HALF_SIZE; + } if (src & SLJIT_MEM) { FAIL_IF(emit_op_mem(compiler, flags, TMP_REG1, src, srcw, TMP_REG1)); src = TMP_REG1; } - emit_op_imm(compiler, flags | op, dst_r, TMP_REG2, (sljit_uw)src); + emit_op_imm(compiler, op, dst_r, TMP_REG2, (sljit_uw)src); if (SLJIT_UNLIKELY(dst & SLJIT_MEM)) - return emit_op_mem(compiler, flags | STORE, dst_r, dst, dstw, TMP_REG2); + return emit_op_mem(compiler, flags | STORE, dst_r, dst, dstw, TMP_REG1); return SLJIT_SUCCESS; } @@ -1863,7 +2002,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile sljit_s32 src1, sljit_sw src1w, sljit_s32 src2, sljit_sw src2w) { - sljit_s32 dst_reg, flags, src2_reg; + sljit_s32 dst_reg, src2_tmp_reg, flags; CHECK_ERROR(); CHECK(check_sljit_emit_op2(compiler, op, 0, dst, dstw, src1, src1w, src2, src2w)); @@ -1871,36 +2010,34 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile ADJUST_LOCAL_OFFSET(src1, src1w); ADJUST_LOCAL_OFFSET(src2, src2w); - dst_reg = FAST_IS_REG(dst) ? dst : TMP_REG1; + dst_reg = FAST_IS_REG(dst) ? dst : TMP_REG2; flags = HAS_FLAGS(op) ? SET_FLAGS : 0; if (dst == TMP_REG1) flags |= UNUSED_RETURN; + if (src2 == SLJIT_IMM) + flags |= ARG2_IMM; + else if (src2 & SLJIT_MEM) { + src2_tmp_reg = FAST_IS_REG(src1) ? TMP_REG1 : TMP_REG2; + emit_op_mem(compiler, WORD_SIZE, src2_tmp_reg, src2, src2w, TMP_REG1); + src2w = src2_tmp_reg; + } else + src2w = src2; + if (src1 == SLJIT_IMM) flags |= ARG1_IMM; else if (src1 & SLJIT_MEM) { emit_op_mem(compiler, WORD_SIZE, TMP_REG1, src1, src1w, TMP_REG1); src1w = TMP_REG1; - } - else + } else src1w = src1; - if (src2 == SLJIT_IMM) - flags |= ARG2_IMM; - else if (src2 & SLJIT_MEM) { - src2_reg = (!(flags & ARG1_IMM) && (src1w == TMP_REG1)) ? TMP_REG2 : TMP_REG1; - emit_op_mem(compiler, WORD_SIZE, src2_reg, src2, src2w, src2_reg); - src2w = src2_reg; - } - else - src2w = src2; - emit_op_imm(compiler, flags | GET_OPCODE(op), dst_reg, (sljit_uw)src1w, (sljit_uw)src2w); if (!(dst & SLJIT_MEM)) return SLJIT_SUCCESS; - return emit_op_mem(compiler, WORD_SIZE | STORE, dst_reg, dst, dstw, TMP_REG2); + return emit_op_mem(compiler, WORD_SIZE | STORE, dst_reg, dst, dstw, TMP_REG1); } SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compiler, sljit_s32 op, @@ -1914,6 +2051,23 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compil return sljit_emit_op2(compiler, op, TMP_REG1, 0, src1, src1w, src2, src2w); } +SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2r(struct sljit_compiler *compiler, sljit_s32 op, + sljit_s32 dst_reg, + sljit_s32 src1, sljit_sw src1w, + sljit_s32 src2, sljit_sw src2w) +{ + CHECK_ERROR(); + CHECK(check_sljit_emit_op2r(compiler, op, dst_reg, src1, src1w, src2, src2w)); + + switch (GET_OPCODE(op)) { + case SLJIT_MULADD: + SLJIT_SKIP_CHECKS(compiler); + return sljit_emit_op2(compiler, op, dst_reg, 0, src1, src1w, src2, src2w); + } + + return SLJIT_SUCCESS; +} + SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 dst_reg, sljit_s32 src1_reg, @@ -2228,7 +2382,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compil switch (GET_OPCODE(op)) { case SLJIT_MOV_F64: if (src != dst_r) { - if (dst_r != TMP_FREG1) + if (!(dst & SLJIT_MEM)) FAIL_IF(push_inst32(compiler, VMOV_F32 | (op & SLJIT_32) | VD4(dst_r) | VM4(src))); else dst_r = src; @@ -2519,7 +2673,6 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile set_jump(jump, compiler, type & SLJIT_REWRITABLE_JUMP); type &= 0xff; - PTR_FAIL_IF(emit_imm32_const(compiler, TMP_REG1, 0)); if (type < SLJIT_JUMP) { jump->flags |= IS_COND; cc = get_cc(compiler, type); @@ -2535,6 +2688,8 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile PTR_FAIL_IF(push_inst16(compiler, BLX | RN3(TMP_REG1))); } + /* Maximum number of instructions required for generating a constant. */ + compiler->size += JUMP_MAX_SIZE - 1; return jump; } @@ -2800,8 +2955,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compi set_jump(jump, compiler, JUMP_ADDR | ((type >= SLJIT_FAST_CALL) ? IS_BL : 0)); jump->u.target = (sljit_uw)srcw; - FAIL_IF(emit_imm32_const(compiler, TMP_REG1, 0)); jump->addr = compiler->size; + /* Maximum number of instructions required for generating a constant. */ + compiler->size += JUMP_MAX_SIZE - 1; return push_inst16(compiler, (type <= SLJIT_JUMP ? BX : BLX) | RN3(TMP_REG1)); } @@ -2968,7 +3124,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *comp } if (src1 & SLJIT_MEM) { - FAIL_IF(emit_op_mem(compiler, WORD_SIZE, (src2_reg != dst_reg) ? dst_reg : TMP_REG1, src1, src1w, TMP_REG2)); + FAIL_IF(emit_op_mem(compiler, WORD_SIZE, (src2_reg != dst_reg) ? dst_reg : TMP_REG1, src1, src1w, TMP_REG1)); if (src2_reg != dst_reg) { src1 = src2_reg; @@ -3040,8 +3196,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fselect(struct sljit_compiler *com } if (src1 & SLJIT_MEM) { - FAIL_IF(emit_fop_mem(compiler, (type & SLJIT_32) | FPU_LOAD, TMP_FREG1, src1, src1w)); - src1 = TMP_FREG1; + FAIL_IF(emit_fop_mem(compiler, (type & SLJIT_32) | FPU_LOAD, TMP_FREG2, src1, src1w)); + src1 = TMP_FREG2; } FAIL_IF(push_inst16(compiler, IT | (get_cc(compiler, type & ~SLJIT_32) << 4) | 0x8)); @@ -4106,25 +4262,26 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi return const_; } -SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label* sljit_emit_put_label(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw) +SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_mov_addr(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw) { - struct sljit_put_label *put_label; + struct sljit_jump *jump; sljit_s32 dst_r; CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_put_label(compiler, dst, dstw)); + CHECK_PTR(check_sljit_emit_mov_addr(compiler, dst, dstw)); ADJUST_LOCAL_OFFSET(dst, dstw); - put_label = (struct sljit_put_label*)ensure_abuf(compiler, sizeof(struct sljit_put_label)); - PTR_FAIL_IF(!put_label); - set_put_label(put_label, compiler, 0); + jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump)); + PTR_FAIL_IF(!jump); + set_mov_addr(jump, compiler, 0); dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1; - PTR_FAIL_IF(emit_imm32_const(compiler, dst_r, 0)); + PTR_FAIL_IF(push_inst16(compiler, RDN3(dst_r))); + compiler->size += 3; if (dst & SLJIT_MEM) PTR_FAIL_IF(emit_op_mem(compiler, WORD_SIZE | STORE, dst_r, dst, dstw, TMP_REG2)); - return put_label; + return jump; } SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset) diff --git a/src/sljit/sljitNativeLOONGARCH_64.c b/src/sljit/sljitNativeLOONGARCH_64.c index dbd7605..2e1d742 100644 --- a/src/sljit/sljitNativeLOONGARCH_64.c +++ b/src/sljit/sljitNativeLOONGARCH_64.c @@ -85,10 +85,12 @@ lower parts in the instruction word, denoted by the “L” and “H” suffixes #define FRK(fk) ((sljit_ins)freg_map[fk] << 10) #define FRA(fa) ((sljit_ins)freg_map[fa] << 15) +#define IMM_V(imm) ((sljit_ins)(imm) << 10) #define IMM_I8(imm) (((sljit_ins)(imm)&0xff) << 10) #define IMM_I12(imm) (((sljit_ins)(imm)&0xfff) << 10) #define IMM_I14(imm) (((sljit_ins)(imm)&0xfff3) << 10) #define IMM_I16(imm) (((sljit_ins)(imm)&0xffff) << 10) +#define IMM_I20(imm) (((sljit_ins)(imm)&0xffffffff) >> 12 << 5) #define IMM_I21(imm) ((((sljit_ins)(imm)&0xffff) << 10) | (((sljit_ins)(imm) >> 16) & 0x1f)) #define IMM_I26(imm) ((((sljit_ins)(imm)&0xffff) << 10) | (((sljit_ins)(imm) >> 16) & 0x3ff)) @@ -318,6 +320,36 @@ lower parts in the instruction word, denoted by the “L” and “H” suffixes #define FSTX_S OPC_3R(0x7070) #define FSTX_D OPC_3R(0x7078) +/* Vector Instructions */ + +/* Vector Arithmetic Instructions */ +#define VOR_V OPC_3R(0xe24d) +#define VXOR_V OPC_3R(0xe24e) +#define VAND_V OPC_3R(0xe24c) +#define VMSKLTZ OPC_2R(0x1ca710) + +/* Vector Memory Access Instructions */ +#define VLD OPC_2RI12(0xb0) +#define VST OPC_2RI12(0xb1) +#define XVLD OPC_2RI12(0xb2) +#define XVST OPC_2RI12(0xb3) +#define VSTELM OPC_2RI8(0xc40) + +/* Vector Float Conversion Instructions */ +#define VFCVTL_D_S OPC_2R(0x1ca77c) + +/* Vector Bit Manipulate Instructions */ +#define VSLLWIL OPC_2R(0x1cc200) + +/* Vector Move And Shuffle Instructions */ +#define VLDREPL OPC_2R(0xc0000) +#define VINSGR2VR OPC_2R(0x1cbac0) +#define VPICKVE2GR_U OPC_2R(0x1cbce0) +#define VREPLGR2VR OPC_2R(0x1ca7c0) +#define VREPLVE OPC_3R(0xe244) +#define VREPLVEI OPC_2R(0x1cbde0) +#define XVPERMI OPC_2RI8(0x1dfa) + #define I12_MAX (0x7ff) #define I12_MIN (-0x800) #define BRANCH16_MAX (0x7fff << 2) @@ -337,16 +369,32 @@ lower parts in the instruction word, denoted by the “L” and “H” suffixes /* LoongArch CPUCFG register for feature detection */ #define LOONGARCH_CFG2 0x02 -#define LOONGARCH_FEATURE_LAMCAS (1 << 28) +#define LOONGARCH_CFG2_LAMCAS (1 << 28) -static sljit_u32 cpu_feature_list = 0; +static sljit_u32 cfg2_feature_list = 0; -static SLJIT_INLINE sljit_u32 get_cpu_features(void) -{ - if (cpu_feature_list == 0) - __asm__ ("cpucfg %0, %1" : "+&r"(cpu_feature_list) : "r"(LOONGARCH_CFG2)); - return cpu_feature_list; -} +/* According to Software Development and Build Convention for LoongArch Architectures, ++ the status of LSX and LASX extension must be checked through HWCAP */ +#include + +#define LOONGARCH_HWCAP_LSX (1 << 4) +#define LOONGARCH_HWCAP_LASX (1 << 5) + +static sljit_u32 hwcap_feature_list = 0; + +/* Feature type */ +#define GET_CFG2 0 +#define GET_HWCAP 1 + +static SLJIT_INLINE sljit_u32 get_cpu_features(sljit_u32 feature_type) + { + if (cfg2_feature_list == 0) + __asm__ ("cpucfg %0, %1" : "+&r"(cfg2_feature_list) : "r"(LOONGARCH_CFG2)); + if (hwcap_feature_list == 0) + hwcap_feature_list = (sljit_u32)getauxval(AT_HWCAP); + + return feature_type ? hwcap_feature_list : cfg2_feature_list; + } static sljit_s32 push_inst(struct sljit_compiler *compiler, sljit_ins ins) { @@ -371,24 +419,23 @@ static SLJIT_INLINE sljit_ins* detect_jump_type(struct sljit_jump *jump, sljit_i if (jump->flags & JUMP_ADDR) target_addr = jump->u.target; else { - SLJIT_ASSERT(jump->flags & JUMP_LABEL); + SLJIT_ASSERT(jump->u.label != NULL); target_addr = (sljit_uw)(code + jump->u.label->size) + (sljit_uw)executable_offset; } diff = (sljit_sw)target_addr - (sljit_sw)inst - executable_offset; if (jump->flags & IS_COND) { - inst--; diff += SSIZE_OF(ins); if (diff >= BRANCH16_MIN && diff <= BRANCH16_MAX) { - jump->flags |= PATCH_B; + inst--; inst[0] = (inst[0] & 0xfc0003ff) ^ 0x4000000; + jump->flags |= PATCH_B; jump->addr = (sljit_uw)inst; return inst; } - inst++; diff -= SSIZE_OF(ins); } @@ -435,65 +482,179 @@ exit: return inst + 3; } -static SLJIT_INLINE sljit_sw put_label_get_length(struct sljit_put_label *put_label, sljit_uw max_label) +static SLJIT_INLINE sljit_sw mov_addr_get_length(struct sljit_jump *jump, sljit_ins *code_ptr, sljit_ins *code, sljit_sw executable_offset) { - if (max_label <= (sljit_uw)S32_MAX) { - put_label->flags = PATCH_ABS32; + sljit_uw addr; + sljit_sw diff; + SLJIT_UNUSED_ARG(executable_offset); + + SLJIT_ASSERT(jump->flags < ((sljit_uw)6 << JUMP_SIZE_SHIFT)); + if (jump->flags & JUMP_ADDR) + addr = jump->u.target; + else + addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code + jump->u.label->size, executable_offset); + + diff = (sljit_sw)addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset); + + if (diff >= S32_MIN && diff <= S32_MAX) { + SLJIT_ASSERT(jump->flags >= ((sljit_uw)1 << JUMP_SIZE_SHIFT)); + jump->flags |= PATCH_REL32; + return 1; + } + + if (addr <= S32_MAX) { + SLJIT_ASSERT(jump->flags >= ((sljit_uw)1 << JUMP_SIZE_SHIFT)); + jump->flags |= PATCH_ABS32; return 1; } - if (max_label <= S52_MAX) { - put_label->flags = PATCH_ABS52; + if (addr <= S52_MAX) { + SLJIT_ASSERT(jump->flags >= ((sljit_uw)2 << JUMP_SIZE_SHIFT)); + jump->flags |= PATCH_ABS52; return 2; } - put_label->flags = 0; + SLJIT_ASSERT(jump->flags >= ((sljit_uw)3 << JUMP_SIZE_SHIFT)); return 3; } -static SLJIT_INLINE void load_addr_to_reg(void *dst, sljit_u32 reg) +static SLJIT_INLINE void load_addr_to_reg(struct sljit_jump *jump, sljit_sw executable_offset) { - struct sljit_jump *jump = NULL; - struct sljit_put_label *put_label; - sljit_uw flags; - sljit_ins *inst; - sljit_uw addr; + sljit_uw flags = jump->flags; + sljit_uw addr = (flags & JUMP_ADDR) ? jump->u.target : jump->u.label->u.addr; + sljit_ins *ins = (sljit_ins*)jump->addr; + sljit_u32 reg = (flags & JUMP_MOV_ADDR) ? *ins : TMP_REG1; + SLJIT_UNUSED_ARG(executable_offset); - if (reg != 0) { - jump = (struct sljit_jump*)dst; - flags = jump->flags; - inst = (sljit_ins*)jump->addr; - addr = (flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target; - } else { - put_label = (struct sljit_put_label*)dst; - flags = put_label->flags; - inst = (sljit_ins*)put_label->addr; - addr = put_label->label->addr; - reg = *inst; + if (flags & PATCH_REL32) { + addr -= (sljit_uw)SLJIT_ADD_EXEC_OFFSET(ins, executable_offset); + + SLJIT_ASSERT((sljit_sw)addr >= S32_MIN && (sljit_sw)addr <= S32_MAX); + + if ((addr & 0x800) != 0) + addr += 0x1000; + + ins[0] = PCADDU12I | RD(reg) | IMM_I20(addr); + + if (!(flags & JUMP_MOV_ADDR)) { + SLJIT_ASSERT((ins[1] & OPC_2RI16(0x3f)) == JIRL); + ins[1] = (ins[1] & (OPC_2RI16(0x3f) | 0x3ff)) | IMM_I16((addr & 0xfff) >> 2); + } else + ins[1] = ADDI_D | RD(reg) | RJ(reg) | IMM_I12(addr); + return; } if (flags & PATCH_ABS32) { SLJIT_ASSERT(addr <= S32_MAX); - inst[0] = LU12I_W | RD(reg) | (sljit_ins)(((addr & 0xffffffff) >> 12) << 5); + ins[0] = LU12I_W | RD(reg) | (sljit_ins)(((addr & 0xffffffff) >> 12) << 5); } else if (flags & PATCH_ABS52) { - inst[0] = LU12I_W | RD(reg) | (sljit_ins)(((addr & 0xffffffff) >> 12) << 5); - inst[1] = LU32I_D | RD(reg) | (sljit_ins)(((addr >> 32) & 0xfffff) << 5); - inst += 1; + ins[0] = LU12I_W | RD(reg) | (sljit_ins)(((addr & 0xffffffff) >> 12) << 5); + ins[1] = LU32I_D | RD(reg) | (sljit_ins)(((addr >> 32) & 0xfffff) << 5); + ins += 1; } else { - inst[0] = LU12I_W | RD(reg) | (sljit_ins)(((addr & 0xffffffff) >> 12) << 5); - inst[1] = LU32I_D | RD(reg) | (sljit_ins)(((addr >> 32) & 0xfffff) << 5); - inst[2] = LU52I_D | RD(reg) | RJ(reg) | IMM_I12(addr >> 52); - inst += 2; + ins[0] = LU12I_W | RD(reg) | (sljit_ins)(((addr & 0xffffffff) >> 12) << 5); + ins[1] = LU32I_D | RD(reg) | (sljit_ins)(((addr >> 32) & 0xfffff) << 5); + ins[2] = LU52I_D | RD(reg) | RJ(reg) | IMM_I12(addr >> 52); + ins += 2; } - if (jump != NULL) { - SLJIT_ASSERT((inst[1] & OPC_2RI16(0x3f)) == JIRL); - inst[1] = (inst[1] & (OPC_2RI16(0x3f) | 0x3ff)) | IMM_I16((addr & 0xfff) >> 2); + if (!(flags & JUMP_MOV_ADDR)) { + SLJIT_ASSERT((ins[1] & OPC_2RI16(0x3f)) == JIRL); + ins[1] = (ins[1] & (OPC_2RI16(0x3f) | 0x3ff)) | IMM_I16((addr & 0xfff) >> 2); } else - inst[1] = ORI | RD(reg) | RJ(reg) | IMM_I12(addr); + ins[1] = ORI | RD(reg) | RJ(reg) | IMM_I12(addr); +} + +static void reduce_code_size(struct sljit_compiler *compiler) +{ + struct sljit_label *label; + struct sljit_jump *jump; + struct sljit_const *const_; + SLJIT_NEXT_DEFINE_TYPES; + sljit_uw total_size; + sljit_uw size_reduce = 0; + sljit_sw diff; + + label = compiler->labels; + jump = compiler->jumps; + const_ = compiler->consts; + + SLJIT_NEXT_INIT_TYPES(); + + while (1) { + SLJIT_GET_NEXT_MIN(); + + if (next_min_addr == SLJIT_MAX_ADDRESS) + break; + + if (next_min_addr == next_label_size) { + label->size -= size_reduce; + + label = label->next; + next_label_size = SLJIT_GET_NEXT_SIZE(label); + } + + if (next_min_addr == next_const_addr) { + const_->addr -= size_reduce; + const_ = const_->next; + next_const_addr = SLJIT_GET_NEXT_ADDRESS(const_); + continue; + } + + if (next_min_addr != next_jump_addr) + continue; + + jump->addr -= size_reduce; + if (!(jump->flags & JUMP_MOV_ADDR)) { + total_size = JUMP_MAX_SIZE; + + if (!(jump->flags & SLJIT_REWRITABLE_JUMP)) { + if (jump->flags & JUMP_ADDR) { + if (jump->u.target <= S32_MAX) + total_size = 2; + else if (jump->u.target <= S52_MAX) + total_size = 3; + } else { + /* Unit size: instruction. */ + diff = (sljit_sw)jump->u.label->size - (sljit_sw)jump->addr; + + if ((jump->flags & IS_COND) && (diff + 1) <= (BRANCH16_MAX / SSIZE_OF(ins)) && (diff + 1) >= (BRANCH16_MIN / SSIZE_OF(ins))) + total_size = 0; + else if (diff >= (JUMP_MIN / SSIZE_OF(ins)) && diff <= (JUMP_MAX / SSIZE_OF(ins))) + total_size = 1; + else if (diff >= (S32_MIN / SSIZE_OF(ins)) && diff <= (S32_MAX / SSIZE_OF(ins))) + total_size = 2; + } + } + + size_reduce += JUMP_MAX_SIZE - total_size; + jump->flags |= total_size << JUMP_SIZE_SHIFT; + } else { + total_size = 3; + + if (!(jump->flags & JUMP_ADDR)) { + /* Real size minus 1. Unit size: instruction. */ + diff = (sljit_sw)jump->u.label->size - (sljit_sw)jump->addr; + + if (diff >= (S32_MIN / SSIZE_OF(ins)) && diff <= (S32_MAX / SSIZE_OF(ins))) + total_size = 1; + } else if (jump->u.target < S32_MAX) + total_size = 1; + else if (jump->u.target <= S52_MAX) + total_size = 2; + + size_reduce += 3 - total_size; + jump->flags |= total_size << JUMP_SIZE_SHIFT; + } + + jump = jump->next; + next_jump_addr = SLJIT_GET_NEXT_ADDRESS(jump); + } + + compiler->size -= size_reduce; } -SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler) +SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler, sljit_s32 options, void *exec_allocator_data) { struct sljit_memory_fragment *buf; sljit_ins *code; @@ -501,70 +662,72 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil sljit_ins *buf_ptr; sljit_ins *buf_end; sljit_uw word_count; - sljit_uw next_addr; + SLJIT_NEXT_DEFINE_TYPES; sljit_sw executable_offset; sljit_uw addr; struct sljit_label *label; struct sljit_jump *jump; struct sljit_const *const_; - struct sljit_put_label *put_label; CHECK_ERROR_PTR(); CHECK_PTR(check_sljit_generate_code(compiler)); - reverse_buf(compiler); - code = (sljit_ins*)SLJIT_MALLOC_EXEC(compiler->size * sizeof(sljit_ins), compiler->exec_allocator_data); + reduce_code_size(compiler); + + code = (sljit_ins*)allocate_executable_memory(compiler->size * sizeof(sljit_ins), options, exec_allocator_data, &executable_offset); PTR_FAIL_WITH_EXEC_IF(code); + + reverse_buf(compiler); buf = compiler->buf; code_ptr = code; word_count = 0; - next_addr = 0; - executable_offset = SLJIT_EXEC_OFFSET(code); - label = compiler->labels; jump = compiler->jumps; const_ = compiler->consts; - put_label = compiler->put_labels; + SLJIT_NEXT_INIT_TYPES(); + SLJIT_GET_NEXT_MIN(); do { buf_ptr = (sljit_ins*)buf->memory; buf_end = buf_ptr + (buf->used_size >> 2); do { *code_ptr = *buf_ptr++; - if (next_addr == word_count) { + if (next_min_addr == word_count) { SLJIT_ASSERT(!label || label->size >= word_count); SLJIT_ASSERT(!jump || jump->addr >= word_count); SLJIT_ASSERT(!const_ || const_->addr >= word_count); - SLJIT_ASSERT(!put_label || put_label->addr >= word_count); /* These structures are ordered by their address. */ - if (label && label->size == word_count) { - label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset); + if (next_min_addr == next_label_size) { + label->u.addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset); label->size = (sljit_uw)(code_ptr - code); label = label->next; + next_label_size = SLJIT_GET_NEXT_SIZE(label); } - if (jump && jump->addr == word_count) { - word_count += 3; - jump->addr = (sljit_uw)code_ptr; - code_ptr = detect_jump_type(jump, code, executable_offset); + + if (next_min_addr == next_jump_addr) { + if (!(jump->flags & JUMP_MOV_ADDR)) { + word_count = word_count - 1 + (jump->flags >> JUMP_SIZE_SHIFT); + jump->addr = (sljit_uw)code_ptr; + code_ptr = detect_jump_type(jump, code, executable_offset); + SLJIT_ASSERT((jump->flags & PATCH_B) || ((sljit_uw)code_ptr - jump->addr < (jump->flags >> JUMP_SIZE_SHIFT) * sizeof(sljit_ins))); + } else { + word_count += jump->flags >> JUMP_SIZE_SHIFT; + addr = (sljit_uw)code_ptr; + code_ptr += mov_addr_get_length(jump, code_ptr, code, executable_offset); + jump->addr = addr; + } jump = jump->next; - } - if (const_ && const_->addr == word_count) { + next_jump_addr = SLJIT_GET_NEXT_ADDRESS(jump); + } else if (next_min_addr == next_const_addr) { const_->addr = (sljit_uw)code_ptr; const_ = const_->next; + next_const_addr = SLJIT_GET_NEXT_ADDRESS(const_); } - if (put_label && put_label->addr == word_count) { - SLJIT_ASSERT(put_label->label); - put_label->addr = (sljit_uw)code_ptr; - - code_ptr += put_label_get_length(put_label, (sljit_uw)(SLJIT_ADD_EXEC_OFFSET(code, executable_offset) + put_label->label->size)); - word_count += 3; - put_label = put_label->next; - } - next_addr = compute_next_addr(label, jump, const_, put_label); + SLJIT_GET_NEXT_MIN(); } code_ptr++; word_count++; @@ -574,7 +737,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil } while (buf); if (label && label->size == word_count) { - label->addr = (sljit_uw)code_ptr; + label->u.addr = (sljit_uw)code_ptr; label->size = (sljit_uw)(code_ptr - code); label = label->next; } @@ -582,18 +745,17 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil SLJIT_ASSERT(!label); SLJIT_ASSERT(!jump); SLJIT_ASSERT(!const_); - SLJIT_ASSERT(!put_label); SLJIT_ASSERT(code_ptr - code <= (sljit_sw)compiler->size); jump = compiler->jumps; while (jump) { do { - if (!(jump->flags & (PATCH_B | PATCH_J | PATCH_REL32))) { - load_addr_to_reg(jump, TMP_REG1); + if (!(jump->flags & (PATCH_B | PATCH_J)) || (jump->flags & JUMP_MOV_ADDR)) { + load_addr_to_reg(jump, executable_offset); break; } - addr = (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target; + addr = (jump->flags & JUMP_ADDR) ? jump->u.target : jump->u.label->u.addr; buf_ptr = (sljit_ins *)jump->addr; addr -= (sljit_uw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset); @@ -603,15 +765,6 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil break; } - if (jump->flags & PATCH_REL32) { - SLJIT_ASSERT((sljit_sw)addr >= S32_MIN && (sljit_sw)addr <= S32_MAX); - - buf_ptr[0] = PCADDU12I | RD(TMP_REG1) | (sljit_ins)((sljit_sw)addr & ~0xfff); - SLJIT_ASSERT((buf_ptr[1] & OPC_2RI16(0x3f)) == JIRL); - buf_ptr[1] |= IMM_I16((addr & 0xfff) >> 2); - break; - } - SLJIT_ASSERT((sljit_sw)addr >= JUMP_MIN && (sljit_sw)addr <= JUMP_MAX); if (jump->flags & IS_CALL) buf_ptr[0] = BL | (sljit_ins)IMM_I26(addr >> 2); @@ -621,12 +774,6 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil jump = jump->next; } - put_label = compiler->put_labels; - while (put_label) { - load_addr_to_reg(put_label, 0); - put_label = put_label->next; - } - compiler->error = SLJIT_ERR_COMPILED; compiler->executable_offset = executable_offset; compiler->executable_size = (sljit_uw)(code_ptr - code) * sizeof(sljit_ins); @@ -651,8 +798,14 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type) return 1; #endif + case SLJIT_HAS_LASX: + return (LOONGARCH_HWCAP_LASX & get_cpu_features(GET_HWCAP)); + + case SLJIT_HAS_SIMD: + return (LOONGARCH_HWCAP_LSX & get_cpu_features(GET_HWCAP)); + case SLJIT_HAS_ATOMIC: - return (LOONGARCH_FEATURE_LAMCAS & get_cpu_features()); + return (LOONGARCH_CFG2_LAMCAS & get_cpu_features(GET_CFG2)); case SLJIT_HAS_CLZ: case SLJIT_HAS_CTZ: @@ -707,6 +860,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_cmp_info(sljit_s32 type) #define SLOW_SRC1 0x08000 #define SLOW_SRC2 0x10000 #define SLOW_DEST 0x20000 +#define MEM_USE_TMP2 0x40000 #define STACK_STORE ST_D #define STACK_LOAD LD_D @@ -1039,7 +1193,7 @@ static sljit_s32 can_cache(sljit_s32 arg, sljit_sw argw, sljit_s32 next_arg, slj static sljit_s32 getput_arg(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg, sljit_sw argw, sljit_s32 next_arg, sljit_sw next_argw) { sljit_s32 base = arg & REG_MASK; - sljit_s32 tmp_r = TMP_REG1; + sljit_s32 tmp_r = (flags & MEM_USE_TMP2) ? TMP_REG2 : TMP_REG1; sljit_sw offset; SLJIT_ASSERT(arg & SLJIT_MEM); @@ -1048,11 +1202,6 @@ static sljit_s32 getput_arg(struct sljit_compiler *compiler, sljit_s32 flags, sl next_argw = 0; } - /* Since tmp can be the same as base or offset registers, - * these might be unavailable after modifying tmp. */ - if ((flags & MEM_MASK) <= GPR_REG && (flags & LOAD_DATA)) - tmp_r = reg; - if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) { argw &= 0x3; @@ -1149,8 +1298,7 @@ static SLJIT_INLINE sljit_s32 emit_op_mem2(struct sljit_compiler *compiler, slji FAIL_IF(push_inst(compiler, op_reg | RD(dst) | RJ(src1) | RK(dst))); \ } \ } \ - } \ - else { \ + } else { \ if (op & SLJIT_SET_Z) \ FAIL_IF(push_inst(compiler, op_reg | RD(EQUAL_FLAG) | RJ(src1) | RK(src2))); \ if (!(flags & UNUSED_DEST)) \ @@ -1165,88 +1313,88 @@ static SLJIT_INLINE sljit_s32 emit_op_mem2(struct sljit_compiler *compiler, slji static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 flags, sljit_s32 dst, sljit_s32 src1, sljit_sw src2) { - sljit_s32 is_overflow, is_carry, carry_src_r, is_handled; + sljit_s32 is_overflow, is_carry, carry_src_r, is_handled, reg; sljit_ins op_imm, op_reg; sljit_ins word_size = ((op & SLJIT_32) ? 32 : 64); switch (GET_OPCODE(op)) { case SLJIT_MOV: - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM)); + SLJIT_ASSERT(src1 == TMP_ZERO && !(flags & SRC2_IMM)); if (dst != src2) return push_inst(compiler, INST(ADD, op) | RD(dst) | RJ(src2) | IMM_I12(0)); return SLJIT_SUCCESS; case SLJIT_MOV_U8: - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM)); + SLJIT_ASSERT(src1 == TMP_ZERO && !(flags & SRC2_IMM)); if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) return push_inst(compiler, ANDI | RD(dst) | RJ(src2) | IMM_I12(0xff)); SLJIT_ASSERT(dst == src2); return SLJIT_SUCCESS; case SLJIT_MOV_S8: - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM)); + SLJIT_ASSERT(src1 == TMP_ZERO && !(flags & SRC2_IMM)); if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) return push_inst(compiler, EXT_W_B | RD(dst) | RJ(src2)); SLJIT_ASSERT(dst == src2); return SLJIT_SUCCESS; case SLJIT_MOV_U16: - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM)); + SLJIT_ASSERT(src1 == TMP_ZERO && !(flags & SRC2_IMM)); if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) return push_inst(compiler, INST(BSTRPICK, op) | RD(dst) | RJ(src2) | (15 << 16)); SLJIT_ASSERT(dst == src2); return SLJIT_SUCCESS; case SLJIT_MOV_S16: - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM)); + SLJIT_ASSERT(src1 == TMP_ZERO && !(flags & SRC2_IMM)); if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) return push_inst(compiler, EXT_W_H | RD(dst) | RJ(src2)); SLJIT_ASSERT(dst == src2); return SLJIT_SUCCESS; case SLJIT_MOV_U32: - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM)); + SLJIT_ASSERT(src1 == TMP_ZERO && !(flags & SRC2_IMM)); if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) return push_inst(compiler, BSTRPICK_D | RD(dst) | RJ(src2) | (31 << 16)); SLJIT_ASSERT(dst == src2); return SLJIT_SUCCESS; case SLJIT_MOV_S32: - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM)); + SLJIT_ASSERT(src1 == TMP_ZERO && !(flags & SRC2_IMM)); if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) return push_inst(compiler, SLLI_W | RD(dst) | RJ(src2) | IMM_I12(0)); SLJIT_ASSERT(dst == src2); return SLJIT_SUCCESS; case SLJIT_CLZ: - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM)); + SLJIT_ASSERT(src1 == TMP_ZERO && !(flags & SRC2_IMM)); return push_inst(compiler, INST(CLZ, op) | RD(dst) | RJ(src2)); case SLJIT_CTZ: - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM)); + SLJIT_ASSERT(src1 == TMP_ZERO && !(flags & SRC2_IMM)); return push_inst(compiler, INST(CTZ, op) | RD(dst) | RJ(src2)); case SLJIT_REV: - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM)); + SLJIT_ASSERT(src1 == TMP_ZERO && !(flags & SRC2_IMM)); return push_inst(compiler, ((op & SLJIT_32) ? REVB_2W : REVB_D) | RD(dst) | RJ(src2)); case SLJIT_REV_S16: - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM)); + SLJIT_ASSERT(src1 == TMP_ZERO && !(flags & SRC2_IMM)); FAIL_IF(push_inst(compiler, REVB_2H | RD(dst) | RJ(src2))); return push_inst(compiler, EXT_W_H | RD(dst) | RJ(dst)); case SLJIT_REV_U16: - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM)); + SLJIT_ASSERT(src1 == TMP_ZERO && !(flags & SRC2_IMM)); FAIL_IF(push_inst(compiler, REVB_2H | RD(dst) | RJ(src2))); return push_inst(compiler, INST(BSTRPICK, op) | RD(dst) | RJ(dst) | (15 << 16)); case SLJIT_REV_S32: - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM) && dst != TMP_REG1); + SLJIT_ASSERT(src1 == TMP_ZERO && !(flags & SRC2_IMM) && dst != TMP_REG1); FAIL_IF(push_inst(compiler, REVB_2W | RD(dst) | RJ(src2))); return push_inst(compiler, SLLI_W | RD(dst) | RJ(dst) | IMM_I12(0)); case SLJIT_REV_U32: - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM) && dst != TMP_REG1); + SLJIT_ASSERT(src1 == TMP_ZERO && !(flags & SRC2_IMM) && dst != TMP_REG1); FAIL_IF(push_inst(compiler, REVB_2W | RD(dst) | RJ(src2))); return push_inst(compiler, BSTRPICK_D | RD(dst) | RJ(dst) | (31 << 16)); @@ -1263,15 +1411,13 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl FAIL_IF(push_inst(compiler, INST(ADDI, op) | RD(EQUAL_FLAG) | RJ(TMP_ZERO) | IMM_I12(-1))); FAIL_IF(push_inst(compiler, XOR | RD(EQUAL_FLAG) | RJ(src1) | RK(EQUAL_FLAG))); } - } - else if (op & SLJIT_SET_Z) + } else if (op & SLJIT_SET_Z) FAIL_IF(push_inst(compiler, INST(ADDI, op) | RD(EQUAL_FLAG) | RJ(src1) | IMM_I12(src2))); /* Only the zero flag is needed. */ if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK)) FAIL_IF(push_inst(compiler, INST(ADDI, op) | RD(dst) | RJ(src1) | IMM_I12(src2))); - } - else { + } else { if (is_overflow) FAIL_IF(push_inst(compiler, XOR | RD(EQUAL_FLAG) | RJ(src1) | RK(src2))); else if (op & SLJIT_SET_Z) @@ -1361,8 +1507,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl if (GET_FLAG_TYPE(op) == SLJIT_LESS) { FAIL_IF(push_inst(compiler, SLTUI | RD(OTHER_FLAG) | RJ(src1) | IMM_I12(src2))); is_handled = 1; - } - else if (GET_FLAG_TYPE(op) == SLJIT_SIG_LESS) { + } else if (GET_FLAG_TYPE(op) == SLJIT_SIG_LESS) { FAIL_IF(push_inst(compiler, SLTI | RD(OTHER_FLAG) | RJ(src1) | IMM_I12(src2))); is_handled = 1; } @@ -1372,8 +1517,9 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl is_handled = 1; if (flags & SRC2_IMM) { - FAIL_IF(push_inst(compiler, ADDI_D | RD(TMP_REG2) | RJ(TMP_ZERO) | IMM_I12(src2))); - src2 = TMP_REG2; + reg = (src1 == TMP_REG1) ? TMP_REG2 : TMP_REG1; + FAIL_IF(push_inst(compiler, ADDI_D | RD(reg) | RJ(TMP_ZERO) | IMM_I12(src2))); + src2 = reg; flags &= ~SRC2_IMM; } @@ -1399,8 +1545,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl FAIL_IF(push_inst(compiler, INST(ADDI, op) | RD(EQUAL_FLAG) | RJ(src1) | IMM_I12(-src2))); if (!(flags & UNUSED_DEST)) return push_inst(compiler, INST(ADDI, op) | RD(dst) | RJ(src1) | IMM_I12(-src2)); - } - else { + } else { if (op & SLJIT_SET_Z) FAIL_IF(push_inst(compiler, INST(SUB, op) | RD(EQUAL_FLAG) | RJ(src1) | RK(src2))); if (!(flags & UNUSED_DEST)) @@ -1420,8 +1565,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl FAIL_IF(push_inst(compiler, INST(ADDI, op) | RD(EQUAL_FLAG) | RJ(src1) | IMM_I12(-1))); FAIL_IF(push_inst(compiler, XOR | RD(EQUAL_FLAG) | RJ(src1) | RK(EQUAL_FLAG))); } - } - else if (op & SLJIT_SET_Z) + } else if (op & SLJIT_SET_Z) FAIL_IF(push_inst(compiler, INST(ADDI, op) | RD(EQUAL_FLAG) | RJ(src1) | IMM_I12(-src2))); if (is_overflow || is_carry) @@ -1430,8 +1574,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl /* Only the zero flag is needed. */ if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK)) FAIL_IF(push_inst(compiler, INST(ADDI, op) | RD(dst) | RJ(src1) | IMM_I12(-src2))); - } - else { + } else { if (is_overflow) FAIL_IF(push_inst(compiler, XOR | RD(EQUAL_FLAG) | RJ(src1) | RK(src2))); else if (op & SLJIT_SET_Z) @@ -1468,8 +1611,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl FAIL_IF(push_inst(compiler, SLTUI | RD(EQUAL_FLAG) | RJ(src1) | IMM_I12(src2))); FAIL_IF(push_inst(compiler, INST(ADDI, op) | RD(dst) | RJ(src1) | IMM_I12(-src2))); - } - else { + } else { if (is_carry) FAIL_IF(push_inst(compiler, SLTU | RD(EQUAL_FLAG) | RJ(src1) | RK(src2))); @@ -1550,7 +1692,6 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl if (GET_OPCODE(op) == SLJIT_ROTL) src2 = word_size - src2; return push_inst(compiler, INST(ROTRI, op) | RD(dst) | RJ(src1) | IMM_I12(src2)); - } if (src2 == TMP_ZERO) { @@ -1601,7 +1742,7 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3 sljit_s32 dst_r = TMP_REG2; sljit_s32 src1_r; sljit_sw src2_r = 0; - sljit_s32 sugg_src2_r = TMP_REG2; + sljit_s32 src2_tmp_reg = (GET_OPCODE(op) >= SLJIT_OP2_BASE && FAST_IS_REG(src1)) ? TMP_REG1 : TMP_REG2; if (!(flags & ALT_KEEP_CACHE)) { compiler->cache_arg = 0; @@ -1612,22 +1753,19 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3 SLJIT_ASSERT(HAS_FLAGS(op)); flags |= UNUSED_DEST; dst = TMP_REG2; - } - else if (FAST_IS_REG(dst)) { + } else if (FAST_IS_REG(dst)) { dst_r = dst; flags |= REG_DEST; if (flags & MOVE_OP) - sugg_src2_r = dst_r; - } - else if ((dst & SLJIT_MEM) && !getput_arg_fast(compiler, flags | ARG_TEST, TMP_REG1, dst, dstw)) + src2_tmp_reg = dst_r; + } else if ((dst & SLJIT_MEM) && !getput_arg_fast(compiler, flags | ARG_TEST, TMP_REG1, dst, dstw)) flags |= SLOW_DEST; if (flags & IMM_OP) { if (src2 == SLJIT_IMM && src2w != 0 && src2w <= I12_MAX && src2w >= I12_MIN) { flags |= SRC2_IMM; src2_r = src2w; - } - else if ((flags & CUMULATIVE_OP) && src1 == SLJIT_IMM && src1w != 0 && src1w <= I12_MAX && src1w >= I12_MIN) { + } else if ((flags & CUMULATIVE_OP) && src1 == SLJIT_IMM && src1w != 0 && src1w <= I12_MAX && src1w >= I12_MIN) { flags |= SRC2_IMM; src2_r = src1w; @@ -1643,16 +1781,14 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3 if (FAST_IS_REG(src1)) { src1_r = src1; flags |= REG1_SOURCE; - } - else if (src1 == SLJIT_IMM) { + } else if (src1 == SLJIT_IMM) { if (src1w) { FAIL_IF(load_immediate(compiler, TMP_REG1, src1w)); src1_r = TMP_REG1; } else src1_r = TMP_ZERO; - } - else { + } else { if (getput_arg_fast(compiler, flags | LOAD_DATA, TMP_REG1, src1, src1w)) FAIL_IF(compiler->error); else @@ -1666,14 +1802,12 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3 flags |= REG2_SOURCE; if ((flags & (REG_DEST | MOVE_OP)) == MOVE_OP) dst_r = (sljit_s32)src2_r; - } - else if (src2 == SLJIT_IMM) { + } else if (src2 == SLJIT_IMM) { if (!(flags & SRC2_IMM)) { if (src2w) { - FAIL_IF(load_immediate(compiler, sugg_src2_r, src2w)); - src2_r = sugg_src2_r; - } - else { + FAIL_IF(load_immediate(compiler, src2_tmp_reg, src2w)); + src2_r = src2_tmp_reg; + } else { src2_r = TMP_ZERO; if (flags & MOVE_OP) { if (dst & SLJIT_MEM) @@ -1683,31 +1817,29 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3 } } } - } - else { - if (getput_arg_fast(compiler, flags | LOAD_DATA, sugg_src2_r, src2, src2w)) + } else { + if (getput_arg_fast(compiler, flags | LOAD_DATA, src2_tmp_reg, src2, src2w)) FAIL_IF(compiler->error); else flags |= SLOW_SRC2; - src2_r = sugg_src2_r; + src2_r = src2_tmp_reg; } if ((flags & (SLOW_SRC1 | SLOW_SRC2)) == (SLOW_SRC1 | SLOW_SRC2)) { SLJIT_ASSERT(src2_r == TMP_REG2); - if (!can_cache(src1, src1w, src2, src2w) && can_cache(src1, src1w, dst, dstw)) { + if ((flags & SLOW_DEST) && !can_cache(src2, src2w, src1, src1w) && can_cache(src2, src2w, dst, dstw)) { + FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, TMP_REG1, src1, src1w, src2, src2w)); + FAIL_IF(getput_arg(compiler, flags | LOAD_DATA | MEM_USE_TMP2, TMP_REG2, src2, src2w, dst, dstw)); + } else { FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, TMP_REG2, src2, src2w, src1, src1w)); FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, TMP_REG1, src1, src1w, dst, dstw)); } - else { - FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, TMP_REG1, src1, src1w, src2, src2w)); - FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, TMP_REG2, src2, src2w, dst, dstw)); - } } else if (flags & SLOW_SRC1) FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, TMP_REG1, src1, src1w, dst, dstw)); else if (flags & SLOW_SRC2) - FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, sugg_src2_r, src2, src2w, dst, dstw)); + FAIL_IF(getput_arg(compiler, flags | LOAD_DATA | ((src1_r == TMP_REG1) ? MEM_USE_TMP2 : 0), src2_tmp_reg, src2, src2w, dst, dstw)); FAIL_IF(emit_single_op(compiler, op, flags, dst_r, src1_r, src2_r)); @@ -1778,40 +1910,40 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile switch (GET_OPCODE(op)) { case SLJIT_MOV: case SLJIT_MOV_P: - return emit_op(compiler, SLJIT_MOV, WORD_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, srcw); + return emit_op(compiler, SLJIT_MOV, WORD_DATA | MOVE_OP, dst, dstw, TMP_ZERO, 0, src, srcw); case SLJIT_MOV_U32: - return emit_op(compiler, SLJIT_MOV_U32, INT_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src == SLJIT_IMM) ? (sljit_u32)srcw : srcw); + return emit_op(compiler, SLJIT_MOV_U32, INT_DATA | MOVE_OP, dst, dstw, TMP_ZERO, 0, src, (src == SLJIT_IMM) ? (sljit_u32)srcw : srcw); case SLJIT_MOV_S32: /* Logical operators have no W variant, so sign extended input is necessary for them. */ case SLJIT_MOV32: - return emit_op(compiler, SLJIT_MOV_S32, INT_DATA | SIGNED_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src == SLJIT_IMM) ? (sljit_s32)srcw : srcw); + return emit_op(compiler, SLJIT_MOV_S32, INT_DATA | SIGNED_DATA | MOVE_OP, dst, dstw, TMP_ZERO, 0, src, (src == SLJIT_IMM) ? (sljit_s32)srcw : srcw); case SLJIT_MOV_U8: - return emit_op(compiler, op, BYTE_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src == SLJIT_IMM) ? (sljit_u8)srcw : srcw); + return emit_op(compiler, op, BYTE_DATA | MOVE_OP, dst, dstw, TMP_ZERO, 0, src, (src == SLJIT_IMM) ? (sljit_u8)srcw : srcw); case SLJIT_MOV_S8: - return emit_op(compiler, op, BYTE_DATA | SIGNED_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src == SLJIT_IMM) ? (sljit_s8)srcw : srcw); + return emit_op(compiler, op, BYTE_DATA | SIGNED_DATA | MOVE_OP, dst, dstw, TMP_ZERO, 0, src, (src == SLJIT_IMM) ? (sljit_s8)srcw : srcw); case SLJIT_MOV_U16: - return emit_op(compiler, op, HALF_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src == SLJIT_IMM) ? (sljit_u16)srcw : srcw); + return emit_op(compiler, op, HALF_DATA | MOVE_OP, dst, dstw, TMP_ZERO, 0, src, (src == SLJIT_IMM) ? (sljit_u16)srcw : srcw); case SLJIT_MOV_S16: - return emit_op(compiler, op, HALF_DATA | SIGNED_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src == SLJIT_IMM) ? (sljit_s16)srcw : srcw); + return emit_op(compiler, op, HALF_DATA | SIGNED_DATA | MOVE_OP, dst, dstw, TMP_ZERO, 0, src, (src == SLJIT_IMM) ? (sljit_s16)srcw : srcw); case SLJIT_CLZ: case SLJIT_CTZ: case SLJIT_REV: - return emit_op(compiler, op, flags, dst, dstw, TMP_REG1, 0, src, srcw); + return emit_op(compiler, op, flags, dst, dstw, TMP_ZERO, 0, src, srcw); case SLJIT_REV_U16: case SLJIT_REV_S16: - return emit_op(compiler, op, HALF_DATA, dst, dstw, TMP_REG1, 0, src, srcw); + return emit_op(compiler, op, HALF_DATA, dst, dstw, TMP_ZERO, 0, src, srcw); case SLJIT_REV_U32: case SLJIT_REV_S32: - return emit_op(compiler, op | SLJIT_32, INT_DATA, dst, dstw, TMP_REG1, 0, src, srcw); + return emit_op(compiler, op | SLJIT_32, INT_DATA, dst, dstw, TMP_ZERO, 0, src, srcw); } SLJIT_UNREACHABLE(); @@ -1893,6 +2025,24 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compil return sljit_emit_op2(compiler, op, 0, 0, src1, src1w, src2, src2w); } +SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2r(struct sljit_compiler *compiler, sljit_s32 op, + sljit_s32 dst_reg, + sljit_s32 src1, sljit_sw src1w, + sljit_s32 src2, sljit_sw src2w) +{ + CHECK_ERROR(); + CHECK(check_sljit_emit_op2r(compiler, op, dst_reg, src1, src1w, src2, src2w)); + + switch (GET_OPCODE(op)) { + case SLJIT_MULADD: + SLJIT_SKIP_CHECKS(compiler); + FAIL_IF(sljit_emit_op2(compiler, SLJIT_MUL | (op & SLJIT_32), TMP_REG2, 0, src1, src1w, src2, src2w)); + return push_inst(compiler, ADD_D | RD(dst_reg) | RJ(dst_reg) | RK(TMP_REG2)); + } + + return SLJIT_SUCCESS; +} + SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 dst_reg, sljit_s32 src1_reg, @@ -2045,7 +2195,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 type, slji if (type == SLJIT_GP_REGISTER) return reg_map[reg]; - if (type != SLJIT_FLOAT_REGISTER) + if (type != SLJIT_FLOAT_REGISTER && type != SLJIT_SIMD_REG_128 && type != SLJIT_SIMD_REG_256) return -1; return freg_map[reg]; @@ -2292,7 +2442,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compil switch (GET_OPCODE(op)) { case SLJIT_MOV_F64: if (src != dst_r) { - if (dst_r != TMP_FREG1) + if (!(dst & SLJIT_MEM)) FAIL_IF(push_inst(compiler, FINST(FMOV, op) | FRD(dst_r) | FRJ(src))); else dst_r = src; @@ -2351,11 +2501,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compil } if ((flags & (SLOW_SRC1 | SLOW_SRC2)) == (SLOW_SRC1 | SLOW_SRC2)) { - if (!can_cache(src1, src1w, src2, src2w) && can_cache(src1, src1w, dst, dstw)) { + if ((dst & SLJIT_MEM) && !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 { + } 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)); } @@ -2385,7 +2534,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compil break; } - if (dst_r == TMP_FREG2) + if (dst_r != dst) FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op), TMP_FREG2, dst, dstw, 0, 0)); return SLJIT_SUCCESS; } @@ -2573,8 +2722,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile PTR_FAIL_IF(push_inst(compiler, inst)); /* Maximum number of instructions required for generating a constant. */ - compiler->size += 3; - + compiler->size += JUMP_MAX_SIZE - 1; return jump; } @@ -2601,6 +2749,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler struct sljit_jump *jump; sljit_s32 flags; sljit_ins inst; + sljit_s32 src2_tmp_reg = FAST_IS_REG(src1) ? TMP_REG1 : TMP_REG2; CHECK_ERROR_PTR(); CHECK_PTR(check_sljit_emit_cmp(compiler, type, src1, src1w, src2, src2w)); @@ -2618,8 +2767,8 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler } if (src2 & SLJIT_MEM) { - PTR_FAIL_IF(emit_op_mem2(compiler, flags, TMP_REG2, src2, src2w, 0, 0)); - src2 = TMP_REG2; + PTR_FAIL_IF(emit_op_mem2(compiler, flags, src2_tmp_reg, src2, src2w, 0, 0)); + src2 = src2_tmp_reg; } if (src1 == SLJIT_IMM) { @@ -2633,8 +2782,8 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler if (src2 == SLJIT_IMM) { if (src2w != 0) { - PTR_FAIL_IF(load_immediate(compiler, TMP_REG2, src2w)); - src2 = TMP_REG2; + PTR_FAIL_IF(load_immediate(compiler, src2_tmp_reg, src2w)); + src2 = src2_tmp_reg; } else src2 = TMP_ZERO; @@ -2687,7 +2836,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler PTR_FAIL_IF(push_inst(compiler, JIRL | RD(TMP_ZERO) | RJ(TMP_REG1) | IMM_I12(0))); /* Maximum number of instructions required for generating a constant. */ - compiler->size += 3; + compiler->size += JUMP_MAX_SIZE - 1; return jump; } @@ -2718,7 +2867,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compi FAIL_IF(push_inst(compiler, JIRL | RD((type >= SLJIT_FAST_CALL) ? RETURN_ADDR_REG : TMP_ZERO) | RJ(TMP_REG1) | IMM_I12(0))); /* Maximum number of instructions required for generating a constant. */ - compiler->size += 3; + compiler->size += JUMP_MAX_SIZE - 1; return SLJIT_SUCCESS; } @@ -2860,13 +3009,13 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *comp type ^= 0x1; } else { if (ADDRESSING_DEPENDS_ON(src1, dst_reg)) { - FAIL_IF(push_inst(compiler, ADDI_D | RD(TMP_REG2) | RJ(dst_reg) | IMM_I12(0))); + FAIL_IF(push_inst(compiler, ADDI_D | RD(TMP_REG1) | RJ(dst_reg) | IMM_I12(0))); if ((src1 & REG_MASK) == dst_reg) - src1 = (src1 & ~REG_MASK) | TMP_REG2; + src1 = (src1 & ~REG_MASK) | TMP_REG1; if (OFFS_REG(src1) == dst_reg) - src1 = (src1 & ~OFFS_REG_MASK) | TO_OFFS_REG(TMP_REG2); + src1 = (src1 & ~OFFS_REG_MASK) | TO_OFFS_REG(TMP_REG1); } FAIL_IF(push_inst(compiler, ADDI_D | RD(dst_reg) | RJ(src2_reg) | IMM_I12(0))); @@ -2908,15 +3057,17 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fselect(struct sljit_compiler *com if ((type & ~SLJIT_32) == SLJIT_EQUAL) invert = 1; FAIL_IF(push_inst(compiler, MOVGR2CF | FCD(F_OTHER_FLAG) | RJ(EQUAL_FLAG))); - } - else + } else { + if (get_jump_instruction(type & ~SLJIT_32) == (BNE | RJ(OTHER_FLAG) | RD(TMP_ZERO))) + invert = 1; FAIL_IF(push_inst(compiler, MOVGR2CF | FCD(F_OTHER_FLAG) | RJ(OTHER_FLAG))); + } if (src1 & SLJIT_MEM) { - FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(type) | LOAD_DATA, dst_freg, src1, src1w)); + FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(type) | LOAD_DATA, TMP_FREG2, src1, src1w)); if (invert) - return push_inst(compiler, FSEL | FRD(dst_freg) | FRJ(dst_freg) | FRK(src2_freg) | FCA(F_OTHER_FLAG)); - return push_inst(compiler, FSEL | FRD(dst_freg) | FRJ(src2_freg) | FRK(dst_freg) | FCA(F_OTHER_FLAG)); + return push_inst(compiler, FSEL | FRD(dst_freg) | FRJ(TMP_FREG2) | FRK(src2_freg) | FCA(F_OTHER_FLAG)); + return push_inst(compiler, FSEL | FRD(dst_freg) | FRJ(src2_freg) | FRK(TMP_FREG2) | FCA(F_OTHER_FLAG)); } else { if (invert) return push_inst(compiler, FSEL | FRD(dst_freg) | FRJ(src1) | FRK(src2_freg) | FCA(F_OTHER_FLAG)); @@ -2982,6 +3133,468 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem(struct sljit_compiler *compile #undef TO_ARGW_HI +static sljit_s32 sljit_emit_simd_mem_offset(struct sljit_compiler *compiler, sljit_s32 *mem_ptr, sljit_sw memw) +{ + sljit_s32 mem = *mem_ptr; + + if (SLJIT_UNLIKELY(mem & OFFS_REG_MASK)) { + *mem_ptr = TMP_REG3; + FAIL_IF(push_inst(compiler, SLLI_D | RD(TMP_REG3) | RJ(OFFS_REG(mem)) | IMM_I12(memw & 0x3))); + return push_inst(compiler, ADD_D | RD(TMP_REG3) | RJ(TMP_REG3) | RK(mem & REG_MASK)); + } + + if (!(mem & REG_MASK)) { + *mem_ptr = TMP_REG3; + return load_immediate(compiler, TMP_REG3, memw); + } + + mem &= REG_MASK; + + if (memw == 0) { + *mem_ptr = mem; + return SLJIT_SUCCESS; + } + + *mem_ptr = TMP_REG3; + + FAIL_IF(load_immediate(compiler, TMP_REG3, memw)); + return push_inst(compiler, ADD_D | RD(TMP_REG3) | RJ(TMP_REG3) | RK(mem)); +} + +SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_mov(struct sljit_compiler *compiler, sljit_s32 type, + sljit_s32 freg, + sljit_s32 srcdst, sljit_sw srcdstw) +{ + sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type); + sljit_ins ins = 0; + + CHECK_ERROR(); + CHECK(check_sljit_emit_simd_mov(compiler, type, freg, srcdst, srcdstw)); + + ADJUST_LOCAL_OFFSET(srcdst, srcdstw); + + if (reg_size != 5 && reg_size != 4) + return SLJIT_ERR_UNSUPPORTED; + + if (reg_size == 5 && !(get_cpu_features(GET_HWCAP) & LOONGARCH_HWCAP_LASX)) + return SLJIT_ERR_UNSUPPORTED; + + if (type & SLJIT_SIMD_TEST) + return SLJIT_SUCCESS; + + if (!(srcdst & SLJIT_MEM)) { + if (type & SLJIT_SIMD_STORE) + ins = FRD(srcdst) | FRJ(freg) | FRK(freg); + else + ins = FRD(freg) | FRJ(srcdst) | FRK(srcdst); + + if (reg_size == 5) + ins |= VOR_V | (sljit_ins)1 << 26; + else + ins |= VOR_V; + + return push_inst(compiler, ins); + } + + ins = (type & SLJIT_SIMD_STORE) ? VST : VLD; + + if (reg_size == 5) + ins = (type & SLJIT_SIMD_STORE) ? XVST : XVLD; + + if (FAST_IS_REG(srcdst) && srcdst >= 0 && (srcdstw >= I12_MIN && srcdstw <= I12_MAX)) + return push_inst(compiler, ins | FRD(freg) | RJ((sljit_u8)srcdst) | IMM_I12(srcdstw)); + else { + FAIL_IF(sljit_emit_simd_mem_offset(compiler, &srcdst, srcdstw)); + return push_inst(compiler, ins | FRD(freg) | RJ(srcdst) | IMM_I12(0)); + } +} + +SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_replicate(struct sljit_compiler *compiler, sljit_s32 type, + sljit_s32 freg, + sljit_s32 src, sljit_sw srcw) +{ + sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type); + sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type); + sljit_ins ins = 0; + + CHECK_ERROR(); + CHECK(check_sljit_emit_simd_replicate(compiler, type, freg, src, srcw)); + + ADJUST_LOCAL_OFFSET(src, srcw); + + if (reg_size != 5 && reg_size != 4) + return SLJIT_ERR_UNSUPPORTED; + + if (reg_size == 5 && !(get_cpu_features(GET_HWCAP) & LOONGARCH_HWCAP_LASX)) + return SLJIT_ERR_UNSUPPORTED; + + if (type & SLJIT_SIMD_TEST) + return SLJIT_SUCCESS; + + if (src & SLJIT_MEM) { + FAIL_IF(sljit_emit_simd_mem_offset(compiler, &src, srcw)); + + if (reg_size == 5) + ins = (sljit_ins)1 << 25; + + return push_inst(compiler, VLDREPL | ins | FRD(freg) | RJ(src) | (sljit_ins)1 << (23 - elem_size)); + } + + if (reg_size == 5) + ins = (sljit_ins)1 << 26; + + if (type & SLJIT_SIMD_FLOAT) { + if (src == SLJIT_IMM) + return push_inst(compiler, VREPLGR2VR | ins | FRD(freg) | RJ(TMP_ZERO) | (sljit_ins)elem_size << 10); + + FAIL_IF(push_inst(compiler, VREPLVE | ins | FRD(freg) | FRJ(src) | RK(TMP_ZERO) | (sljit_ins)elem_size << 15)); + + if (reg_size == 5) { + ins = (sljit_ins)(0x44 << 10); + return push_inst(compiler, XVPERMI | ins | FRD(freg) | FRJ(freg)); + } + + return SLJIT_SUCCESS; + } + + ins |= VREPLGR2VR | (sljit_ins)elem_size << 10; + + if (src == SLJIT_IMM) { + FAIL_IF(load_immediate(compiler, TMP_REG2, srcw)); + src = TMP_REG2; + } + + return push_inst(compiler, ins | FRD(freg) | RJ(src)); +} + +SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_mov(struct sljit_compiler *compiler, sljit_s32 type, + sljit_s32 freg, sljit_s32 lane_index, + sljit_s32 srcdst, sljit_sw srcdstw) +{ + sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type); + sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type); + sljit_ins ins = 0; + + CHECK_ERROR(); + CHECK(check_sljit_emit_simd_lane_mov(compiler, type, freg, lane_index, srcdst, srcdstw)); + + ADJUST_LOCAL_OFFSET(srcdst, srcdstw); + + if (reg_size != 5 && reg_size != 4) + return SLJIT_ERR_UNSUPPORTED; + + if (reg_size == 5 && !(get_cpu_features(GET_HWCAP) & LOONGARCH_HWCAP_LASX)) + return SLJIT_ERR_UNSUPPORTED; + + if ((type & SLJIT_SIMD_FLOAT) && (elem_size < 2 || elem_size > 3)) + return SLJIT_ERR_UNSUPPORTED; + + if ((type & SLJIT_SIMD_FLOAT) && (elem_size < 2 || elem_size > 3)) + return SLJIT_ERR_UNSUPPORTED; + + if (type & SLJIT_SIMD_TEST) + return SLJIT_SUCCESS; + + if (type & SLJIT_SIMD_LANE_ZERO) { + ins = (reg_size == 5) ? ((sljit_ins)1 << 26) : 0; + + if ((type & SLJIT_SIMD_FLOAT) && freg == srcdst) { + FAIL_IF(push_inst(compiler, VOR_V | ins | FRD(TMP_FREG1) | FRJ(freg) | FRK(freg))); + srcdst = TMP_FREG1; + srcdstw = 0; + } + + FAIL_IF(push_inst(compiler, VXOR_V | ins | FRD(freg) | FRJ(freg) | FRK(freg))); + } + + if (srcdst & SLJIT_MEM) { + FAIL_IF(sljit_emit_simd_mem_offset(compiler, &srcdst, srcdstw)); + + if (reg_size == 5) + ins = (sljit_ins)1 << 25; + + if (type & SLJIT_SIMD_STORE) { + ins |= (sljit_ins)lane_index << 18 | (sljit_ins)(1 << (23 - elem_size)); + return push_inst(compiler, VSTELM | ins | FRD(freg) | RJ(srcdst)); + } else { + emit_op_mem(compiler, (elem_size == 3 ? WORD_DATA : (elem_size == 2 ? INT_DATA : (elem_size == 1 ? HALF_DATA : BYTE_DATA))) | LOAD_DATA, TMP_REG1, srcdst | SLJIT_MEM, 0); + srcdst = TMP_REG1; + ins = (sljit_ins)(0x3f ^ (0x1f >> elem_size)) << 10; + + if (reg_size == 5) { + if (elem_size < 2) { + FAIL_IF(push_inst(compiler, VOR_V | (sljit_ins)1 << 26 | FRD(TMP_FREG1) | FRJ(freg) | FRK(freg))); + if (lane_index >= (2 << (3 - elem_size))) { + FAIL_IF(push_inst(compiler, XVPERMI | (sljit_ins)1 << 18 | FRD(TMP_FREG1) | FRJ(freg) | IMM_I8(1))); + FAIL_IF(push_inst(compiler, VINSGR2VR | ins | FRD(TMP_FREG1) | RJ(srcdst) | IMM_V(lane_index % (2 << (3 - elem_size))))); + return push_inst(compiler, XVPERMI | (sljit_ins)1 << 18 | FRD(freg) | FRJ(TMP_FREG1) | IMM_I8(2)); + } else { + FAIL_IF(push_inst(compiler, VINSGR2VR | ins | FRD(freg) | RJ(srcdst) | IMM_V(lane_index))); + return push_inst(compiler, XVPERMI | (sljit_ins)1 << 18 | FRD(freg) | FRJ(TMP_FREG1) | IMM_I8(18)); + } + } else + ins = (sljit_ins)(0x3f ^ (0x3f >> elem_size)) << 10 | (sljit_ins)1 << 26; + } + + return push_inst(compiler, VINSGR2VR | ins | FRD(freg) | RJ(srcdst) | IMM_V(lane_index)); + } + } + + if (type & SLJIT_SIMD_FLOAT) { + ins = (reg_size == 5) ? (sljit_ins)(0x3f ^ (0x3f >> elem_size)) << 10 | (sljit_ins)1 << 26 : (sljit_ins)(0x3f ^ (0x1f >> elem_size)) << 10; + + if (type & SLJIT_SIMD_STORE) { + FAIL_IF(push_inst(compiler, VPICKVE2GR_U | ins | RD(TMP_REG1) | FRJ(freg) | IMM_V(lane_index))); + return push_inst(compiler, VINSGR2VR | ins | FRD(srcdst) | RJ(TMP_REG1) | IMM_V(0)); + } else { + FAIL_IF(push_inst(compiler, VPICKVE2GR_U | ins | RD(TMP_REG1) | FRJ(srcdst) | IMM_V(0))); + return push_inst(compiler, VINSGR2VR | ins | FRD(freg) | RJ(TMP_REG1) | IMM_V(lane_index)); + } + } + + if (srcdst == SLJIT_IMM) { + FAIL_IF(load_immediate(compiler, TMP_REG1, srcdstw)); + srcdst = TMP_REG1; + } + + if (type & SLJIT_SIMD_STORE) { + ins = (sljit_ins)(0x3f ^ (0x1f >> elem_size)) << 10; + + if (type & SLJIT_SIMD_LANE_SIGNED) + ins |= (sljit_ins)(VPICKVE2GR_U ^ (0x7 << 18)); + else + ins |= VPICKVE2GR_U; + + if (reg_size == 5) { + if (elem_size < 2) { + if (lane_index >= (2 << (3 - elem_size))) { + if (type & SLJIT_SIMD_LANE_SIGNED) + ins |= (sljit_ins)(VPICKVE2GR_U ^ (0x7 << 18)); + else + ins |= VPICKVE2GR_U; + + FAIL_IF(push_inst(compiler, VOR_V | (sljit_ins)1 << 26 | FRD(TMP_FREG1) | FRJ(freg) | FRK(freg))); + FAIL_IF(push_inst(compiler, XVPERMI | (sljit_ins)1 << 18 | FRD(TMP_FREG1) | FRJ(freg) | IMM_I8(1))); + return push_inst(compiler, ins | RD(srcdst) | FRJ(TMP_FREG1) | IMM_V(lane_index % (2 << (3 - elem_size)))); + } + } else { + ins ^= (sljit_ins)1 << (15 - elem_size); + ins |= (sljit_ins)1 << 26; + } + } + + return push_inst(compiler, ins | RD(srcdst) | FRJ(freg) | IMM_V(lane_index)); + } else { + ins = (sljit_ins)(0x3f ^ (0x1f >> elem_size)) << 10; + + if (reg_size == 5) { + if (elem_size < 2) { + FAIL_IF(push_inst(compiler, VOR_V | (sljit_ins)1 << 26 | FRD(TMP_FREG1) | FRJ(freg) | FRK(freg))); + if (lane_index >= (2 << (3 - elem_size))) { + FAIL_IF(push_inst(compiler, XVPERMI | (sljit_ins)1 << 18 | FRD(TMP_FREG1) | FRJ(freg) | IMM_I8(1))); + FAIL_IF(push_inst(compiler, VINSGR2VR | ins | FRD(TMP_FREG1) | RJ(srcdst) | IMM_V(lane_index % (2 << (3 - elem_size))))); + return push_inst(compiler, XVPERMI | (sljit_ins)1 << 18 | FRD(freg) | FRJ(TMP_FREG1) | IMM_I8(2)); + } else { + FAIL_IF(push_inst(compiler, VINSGR2VR | ins | FRD(freg) | RJ(srcdst) | IMM_V(lane_index))); + return push_inst(compiler, XVPERMI | (sljit_ins)1 << 18 | FRD(freg) | FRJ(TMP_FREG1) | IMM_I8(18)); + } + } else + ins = (sljit_ins)(0x3f ^ (0x3f >> elem_size)) << 10 | (sljit_ins)1 << 26; + } + + return push_inst(compiler, VINSGR2VR | ins | FRD(freg) | RJ(srcdst) | IMM_V(lane_index)); + } + + return SLJIT_ERR_UNSUPPORTED; +} + +SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_replicate(struct sljit_compiler *compiler, sljit_s32 type, + sljit_s32 freg, + sljit_s32 src, sljit_s32 src_lane_index) +{ + sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type); + sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type); + sljit_ins ins = 0; + + CHECK_ERROR(); + CHECK(check_sljit_emit_simd_lane_replicate(compiler, type, freg, src, src_lane_index)); + + if (reg_size != 5 && reg_size != 4) + return SLJIT_ERR_UNSUPPORTED; + + if (reg_size == 5 && !(get_cpu_features(GET_HWCAP) & LOONGARCH_HWCAP_LASX)) + return SLJIT_ERR_UNSUPPORTED; + + if (type & SLJIT_SIMD_TEST) + return SLJIT_SUCCESS; + + ins = (sljit_ins)(0x3f ^ (0x1f >> elem_size)) << 10; + + if (reg_size == 5) { + FAIL_IF(push_inst(compiler, VREPLVEI | (sljit_ins)1 << 26 | ins | FRD(freg) | FRJ(src) | IMM_V(src_lane_index % (2 << (3 - elem_size))))); + + ins = (src_lane_index < (2 << (3 - elem_size))) ? (sljit_ins)(0x44 << 10) : (sljit_ins)(0xee << 10); + + return push_inst(compiler, XVPERMI | ins | FRD(freg) | FRJ(freg)); + } + + return push_inst(compiler, VREPLVEI | ins | FRD(freg) | FRJ(src) | IMM_V(src_lane_index)); +} + +SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_extend(struct sljit_compiler *compiler, sljit_s32 type, + sljit_s32 freg, + sljit_s32 src, sljit_sw srcw) +{ + sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type); + sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type); + sljit_s32 elem2_size = SLJIT_SIMD_GET_ELEM2_SIZE(type); + sljit_ins ins = 0; + + CHECK_ERROR(); + CHECK(check_sljit_emit_simd_extend(compiler, type, freg, src, srcw)); + + ADJUST_LOCAL_OFFSET(src, srcw); + + if (reg_size != 5 && reg_size != 4) + return SLJIT_ERR_UNSUPPORTED; + + if (reg_size == 5 && !(get_cpu_features(GET_HWCAP) & LOONGARCH_HWCAP_LASX)) + return SLJIT_ERR_UNSUPPORTED; + + if (type & SLJIT_SIMD_TEST) + return SLJIT_SUCCESS; + + if (src & SLJIT_MEM) { + ins = (type & SLJIT_SIMD_STORE) ? VST : VLD; + + if (reg_size == 5) + ins = (type & SLJIT_SIMD_STORE) ? XVST : XVLD; + + if (FAST_IS_REG(src) && src >= 0 && (srcw >= I12_MIN && srcw <= I12_MAX)) + FAIL_IF(push_inst(compiler, ins | FRD(freg) | RJ(src) | IMM_I12(srcw))); + else { + FAIL_IF(sljit_emit_simd_mem_offset(compiler, &src, srcw)); + FAIL_IF(push_inst(compiler, ins | FRD(freg) | RJ(src) | IMM_I12(0))); + } + src = freg; + } + + if (type & SLJIT_SIMD_FLOAT) { + if (elem_size != 2 || elem2_size != 3) + return SLJIT_ERR_UNSUPPORTED; + + ins = 0; + if (reg_size == 5) { + ins = (sljit_ins)1 << 26; + FAIL_IF(push_inst(compiler, XVPERMI | FRD(src) | FRJ(src) | IMM_I8(16))); + } + + return push_inst(compiler, VFCVTL_D_S | ins | FRD(freg) | FRJ(src)); + } + + ins = (type & SLJIT_SIMD_EXTEND_SIGNED) ? VSLLWIL : (VSLLWIL | (sljit_ins)1 << 18); + + if (reg_size == 5) + ins |= (sljit_ins)1 << 26; + + do { + if (reg_size == 5) + FAIL_IF(push_inst(compiler, XVPERMI | FRD(src) | FRJ(src) | IMM_I8(16))); + + FAIL_IF(push_inst(compiler, ins | ((sljit_ins)1 << (13 + elem_size)) | FRD(freg) | FRJ(src))); + src = freg; + } while (++elem_size < elem2_size); + + return SLJIT_SUCCESS; +} + +SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_sign(struct sljit_compiler *compiler, sljit_s32 type, + sljit_s32 freg, + sljit_s32 dst, sljit_sw dstw) +{ + sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type); + sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type); + sljit_ins ins = 0; + sljit_s32 dst_r; + + CHECK_ERROR(); + CHECK(check_sljit_emit_simd_sign(compiler, type, freg, dst, dstw)); + + ADJUST_LOCAL_OFFSET(dst, dstw); + + if (reg_size != 5 && reg_size != 4) + return SLJIT_ERR_UNSUPPORTED; + + if (reg_size == 5 && !(get_cpu_features(GET_HWCAP) & LOONGARCH_HWCAP_LASX)) + return SLJIT_ERR_UNSUPPORTED; + + if (elem_size > 3 || ((type & SLJIT_SIMD_FLOAT) && elem_size < 2)) + return SLJIT_ERR_UNSUPPORTED; + + if (type & SLJIT_SIMD_TEST) + return SLJIT_SUCCESS; + + dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2; + + if (reg_size == 5) + ins = (sljit_ins)1 << 26; + + FAIL_IF(push_inst(compiler, VMSKLTZ | ins | (sljit_ins)(elem_size << 10) | FRD(TMP_FREG1) | FRJ(freg))); + + FAIL_IF(push_inst(compiler, VPICKVE2GR_U | (sljit_ins)(0x3c << 10) | RD(dst_r) | FRJ(TMP_FREG1))); + + if (reg_size == 5) { + FAIL_IF(push_inst(compiler, VPICKVE2GR_U | (sljit_ins)(0x38 << 10) | ins | RD(TMP_REG3) | FRJ(TMP_FREG1) | IMM_V(2))); + FAIL_IF(push_inst(compiler, SLLI_W | RD(TMP_REG3) | RJ(TMP_REG3) | IMM_I12(2 << (3 - elem_size)))); + FAIL_IF(push_inst(compiler, OR | RD(dst_r) | RJ(dst_r) | RK(TMP_REG3))); + } + + if (dst_r == TMP_REG2) + return emit_op_mem(compiler, ((type & SLJIT_32) ? INT_DATA : WORD_DATA), TMP_REG2, dst, dstw); + + return SLJIT_SUCCESS; +} + +SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_op2(struct sljit_compiler *compiler, sljit_s32 type, + sljit_s32 dst_freg, sljit_s32 src1_freg, sljit_s32 src2_freg) +{ + sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type); + sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type); + sljit_ins ins = 0; + + CHECK_ERROR(); + CHECK(check_sljit_emit_simd_op2(compiler, type, dst_freg, src1_freg, src2_freg)); + + if (reg_size != 5 && reg_size != 4) + return SLJIT_ERR_UNSUPPORTED; + + if (reg_size == 5 && !(get_cpu_features(GET_HWCAP) & LOONGARCH_HWCAP_LASX)) + return SLJIT_ERR_UNSUPPORTED; + + if ((type & SLJIT_SIMD_FLOAT) && (elem_size < 2 || elem_size > 3)) + return SLJIT_ERR_UNSUPPORTED; + + if (type & SLJIT_SIMD_TEST) + return SLJIT_SUCCESS; + + switch (SLJIT_SIMD_GET_OPCODE(type)) { + case SLJIT_SIMD_OP2_AND: + ins = VAND_V; + break; + case SLJIT_SIMD_OP2_OR: + ins = VOR_V; + break; + case SLJIT_SIMD_OP2_XOR: + ins = VXOR_V; + break; + } + + if (reg_size == 5) + ins |= (sljit_ins)1 << 26; + + return push_inst(compiler, ins | FRD(dst_freg) | FRJ(src1_freg) | FRK(src2_freg)); +} + SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_atomic_load(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 dst_reg, @@ -2992,9 +3605,6 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_atomic_load(struct sljit_compiler CHECK_ERROR(); CHECK(check_sljit_emit_atomic_load(compiler, op, dst_reg, mem_reg)); - if (!(LOONGARCH_FEATURE_LAMCAS & get_cpu_features())) - return SLJIT_ERR_UNSUPPORTED; - switch(GET_OPCODE(op)) { case SLJIT_MOV_U8: ins = LD_BU; @@ -3029,9 +3639,6 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_atomic_store(struct sljit_compiler CHECK_ERROR(); CHECK(check_sljit_emit_atomic_store(compiler, op, src_reg, mem_reg, temp_reg)); - if (!(LOONGARCH_FEATURE_LAMCAS & get_cpu_features())) - return SLJIT_ERR_UNSUPPORTED; - switch (GET_OPCODE(op)) { case SLJIT_MOV_U8: ins = AMCAS_B; @@ -3128,28 +3735,28 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi return const_; } -SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label* sljit_emit_put_label(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw) +SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_mov_addr(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw) { - struct sljit_put_label *put_label; + struct sljit_jump *jump; sljit_s32 dst_r; CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_put_label(compiler, dst, dstw)); + CHECK_PTR(check_sljit_emit_mov_addr(compiler, dst, dstw)); ADJUST_LOCAL_OFFSET(dst, dstw); - put_label = (struct sljit_put_label*)ensure_abuf(compiler, sizeof(struct sljit_put_label)); - PTR_FAIL_IF(!put_label); - set_put_label(put_label, compiler, 0); + jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump)); + PTR_FAIL_IF(!jump); + set_mov_addr(jump, compiler, 0); dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2; PTR_FAIL_IF(push_inst(compiler, (sljit_ins)dst_r)); - compiler->size += 3; + compiler->size += JUMP_MAX_SIZE - 1; if (dst & SLJIT_MEM) PTR_FAIL_IF(emit_op_mem(compiler, WORD_DATA, TMP_REG2, dst, dstw)); - return put_label; + return jump; } SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset) diff --git a/src/sljit/sljitNativeMIPS_32.c b/src/sljit/sljitNativeMIPS_32.c index 9620b94..91153e5 100644 --- a/src/sljit/sljitNativeMIPS_32.c +++ b/src/sljit/sljitNativeMIPS_32.c @@ -225,7 +225,7 @@ static sljit_s32 call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_t sljit_ins f64_hi = TA(6), f64_lo = TA(7); #endif /* SLJIT_LITTLE_ENDIAN */ - SLJIT_ASSERT(reg_map[TMP_REG1] == 4 && freg_map[TMP_FREG1] == 12); + SLJIT_ASSERT(reg_map[TMP_REG2] == 4 && freg_map[TMP_FREG1] == 12); arg_types >>= SLJIT_ARG_SHIFT; @@ -370,7 +370,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_call(struct sljit_compile } else if (type & SLJIT_CALL_RETURN) PTR_FAIL_IF(emit_stack_frame_release(compiler, 0, &ins)); - SLJIT_ASSERT(DR(PIC_ADDR_REG) == 25 && PIC_ADDR_REG == TMP_REG2); + SLJIT_ASSERT(DR(PIC_ADDR_REG) == 25); if (ins == NOP && compiler->delay_slot != UNMOVABLE_INS) jump->flags |= IS_MOVABLE; @@ -441,7 +441,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compi return sljit_emit_ijump(compiler, type, src, srcw); } - SLJIT_ASSERT(DR(PIC_ADDR_REG) == 25 && PIC_ADDR_REG == TMP_REG2); + SLJIT_ASSERT(DR(PIC_ADDR_REG) == 25); if (src == SLJIT_IMM) FAIL_IF(load_immediate(compiler, DR(PIC_ADDR_REG), srcw)); diff --git a/src/sljit/sljitNativeMIPS_64.c b/src/sljit/sljitNativeMIPS_64.c index 52a0d3f..b9f03a7 100644 --- a/src/sljit/sljitNativeMIPS_64.c +++ b/src/sljit/sljitNativeMIPS_64.c @@ -225,7 +225,7 @@ static sljit_s32 call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_t sljit_ins prev_ins = *ins_ptr; sljit_ins ins = NOP; - SLJIT_ASSERT(reg_map[TMP_REG1] == 4 && freg_map[TMP_FREG1] == 12); + SLJIT_ASSERT(reg_map[TMP_REG2] == 4 && freg_map[TMP_FREG1] == 12); arg_types >>= SLJIT_ARG_SHIFT; @@ -309,7 +309,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_call(struct sljit_compile if ((type & 0xff) != SLJIT_CALL_REG_ARG) PTR_FAIL_IF(call_with_args(compiler, arg_types, &ins)); - SLJIT_ASSERT(DR(PIC_ADDR_REG) == 25 && PIC_ADDR_REG == TMP_REG2); + SLJIT_ASSERT(DR(PIC_ADDR_REG) == 25); if (ins == NOP && compiler->delay_slot != UNMOVABLE_INS) jump->flags |= IS_MOVABLE; @@ -366,7 +366,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compi return sljit_emit_ijump(compiler, type, src, srcw); } - SLJIT_ASSERT(DR(PIC_ADDR_REG) == 25 && PIC_ADDR_REG == TMP_REG2); + SLJIT_ASSERT(DR(PIC_ADDR_REG) == 25 && PIC_ADDR_REG == TMP_REG1); if (src == SLJIT_IMM) FAIL_IF(load_immediate(compiler, DR(PIC_ADDR_REG), srcw)); diff --git a/src/sljit/sljitNativeMIPS_common.c b/src/sljit/sljitNativeMIPS_common.c index 807b347..88eb30b 100644 --- a/src/sljit/sljitNativeMIPS_common.c +++ b/src/sljit/sljitNativeMIPS_common.c @@ -83,7 +83,7 @@ typedef sljit_u32 sljit_ins; #define TMP_REG3 (SLJIT_NUMBER_OF_REGISTERS + 4) /* For position independent code, t9 must contain the function address. */ -#define PIC_ADDR_REG TMP_REG2 +#define PIC_ADDR_REG TMP_REG1 /* Floating point status register. */ #define FCSR_REG 31 @@ -95,7 +95,7 @@ typedef sljit_u32 sljit_ins; #define OTHER_FLAG 1 static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 7] = { - 0, 2, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 24, 23, 22, 21, 20, 19, 18, 17, 16, 29, 4, 25, 31, 3, 1 + 0, 2, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 24, 23, 22, 21, 20, 19, 18, 17, 16, 29, 25, 4, 31, 3, 1 }; #define TMP_FREG1 (SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1) @@ -504,7 +504,7 @@ static SLJIT_INLINE sljit_ins* detect_jump_type(struct sljit_jump *jump, sljit_i if (jump->flags & JUMP_ADDR) target_addr = jump->u.target; else { - SLJIT_ASSERT(jump->flags & JUMP_LABEL); + SLJIT_ASSERT(jump->u.label != NULL); target_addr = (sljit_uw)(code + jump->u.label->size) + (sljit_uw)executable_offset; } @@ -635,75 +635,66 @@ static __attribute__ ((noinline)) void sljit_cache_flush(void* code, void* code_ #if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) -static SLJIT_INLINE sljit_sw put_label_get_length(struct sljit_put_label *put_label, sljit_uw max_label) +static SLJIT_INLINE sljit_sw mov_addr_get_length(struct sljit_jump *jump, sljit_ins *code, sljit_sw executable_offset) { - if (max_label < 0x80000000l) { - put_label->flags = PATCH_ABS32; + sljit_uw addr; + SLJIT_UNUSED_ARG(executable_offset); + + if (jump->flags & JUMP_ADDR) + addr = jump->u.target; + else + addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code + jump->u.label->size, executable_offset); + + if (addr < 0x80000000l) { + jump->flags |= PATCH_ABS32; return 1; } - if (max_label < 0x800000000000l) { - put_label->flags = PATCH_ABS48; + if (addr < 0x800000000000l) { + jump->flags |= PATCH_ABS48; return 3; } - put_label->flags = 0; return 5; } #endif /* SLJIT_CONFIG_MIPS_64 */ -static SLJIT_INLINE void load_addr_to_reg(void *dst, sljit_u32 reg) +static SLJIT_INLINE void load_addr_to_reg(struct sljit_jump *jump) { - struct sljit_jump *jump; - struct sljit_put_label *put_label; - sljit_uw flags; - sljit_ins *inst; - sljit_uw addr; - - if (reg != 0) { - jump = (struct sljit_jump*)dst; - flags = jump->flags; - inst = (sljit_ins*)jump->addr; - addr = (flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target; - } else { - put_label = (struct sljit_put_label*)dst; -#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) - flags = put_label->flags; -#endif - inst = (sljit_ins*)put_label->addr; - addr = put_label->label->addr; - reg = *inst; - } + sljit_uw flags = jump->flags; + sljit_ins *ins = (sljit_ins*)jump->addr; + sljit_uw addr = (flags & JUMP_ADDR) ? jump->u.target : jump->u.label->u.addr; + sljit_u32 reg = (flags & JUMP_MOV_ADDR) ? *ins : PIC_ADDR_REG; #if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) - inst[0] = LUI | T(reg) | IMM(addr >> 16); + ins[0] = LUI | T(reg) | IMM(addr >> 16); #else /* !SLJIT_CONFIG_MIPS_32 */ if (flags & PATCH_ABS32) { SLJIT_ASSERT(addr < 0x80000000l); - inst[0] = LUI | T(reg) | IMM(addr >> 16); + ins[0] = LUI | T(reg) | IMM(addr >> 16); } else if (flags & PATCH_ABS48) { SLJIT_ASSERT(addr < 0x800000000000l); - inst[0] = LUI | T(reg) | IMM(addr >> 32); - inst[1] = ORI | S(reg) | T(reg) | IMM((addr >> 16) & 0xffff); - inst[2] = DSLL | T(reg) | D(reg) | SH_IMM(16); - inst += 2; + ins[0] = LUI | T(reg) | IMM(addr >> 32); + ins[1] = ORI | S(reg) | T(reg) | IMM((addr >> 16) & 0xffff); + ins[2] = DSLL | T(reg) | D(reg) | SH_IMM(16); + ins += 2; } else { - inst[0] = LUI | T(reg) | IMM(addr >> 48); - inst[1] = ORI | S(reg) | T(reg) | IMM((addr >> 32) & 0xffff); - inst[2] = DSLL | T(reg) | D(reg) | SH_IMM(16); - inst[3] = ORI | S(reg) | T(reg) | IMM((addr >> 16) & 0xffff); - inst[4] = DSLL | T(reg) | D(reg) | SH_IMM(16); - inst += 4; + ins[0] = LUI | T(reg) | IMM(addr >> 48); + ins[1] = ORI | S(reg) | T(reg) | IMM((addr >> 32) & 0xffff); + ins[2] = DSLL | T(reg) | D(reg) | SH_IMM(16); + ins[3] = ORI | S(reg) | T(reg) | IMM((addr >> 16) & 0xffff); + ins[4] = DSLL | T(reg) | D(reg) | SH_IMM(16); + ins += 4; } #endif /* SLJIT_CONFIG_MIPS_32 */ - inst[1] = ORI | S(reg) | T(reg) | IMM(addr & 0xffff); + ins[1] = ORI | S(reg) | T(reg) | IMM(addr & 0xffff); } -SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler) +SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler, sljit_s32 options, void *exec_allocator_data) { struct sljit_memory_fragment *buf; sljit_ins *code; @@ -711,77 +702,76 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil sljit_ins *buf_ptr; sljit_ins *buf_end; sljit_uw word_count; - sljit_uw next_addr; + SLJIT_NEXT_DEFINE_TYPES; sljit_sw executable_offset; sljit_uw addr; - struct sljit_label *label; struct sljit_jump *jump; struct sljit_const *const_; - struct sljit_put_label *put_label; CHECK_ERROR_PTR(); CHECK_PTR(check_sljit_generate_code(compiler)); reverse_buf(compiler); - code = (sljit_ins*)SLJIT_MALLOC_EXEC(compiler->size * sizeof(sljit_ins), compiler->exec_allocator_data); + code = (sljit_ins*)allocate_executable_memory(compiler->size * sizeof(sljit_ins), options, exec_allocator_data, &executable_offset); PTR_FAIL_WITH_EXEC_IF(code); buf = compiler->buf; code_ptr = code; word_count = 0; - next_addr = 0; - executable_offset = SLJIT_EXEC_OFFSET(code); - label = compiler->labels; jump = compiler->jumps; const_ = compiler->consts; - put_label = compiler->put_labels; + SLJIT_NEXT_INIT_TYPES(); + SLJIT_GET_NEXT_MIN(); do { buf_ptr = (sljit_ins*)buf->memory; buf_end = buf_ptr + (buf->used_size >> 2); do { *code_ptr = *buf_ptr++; - if (next_addr == word_count) { + if (next_min_addr == word_count) { SLJIT_ASSERT(!label || label->size >= word_count); SLJIT_ASSERT(!jump || jump->addr >= word_count); SLJIT_ASSERT(!const_ || const_->addr >= word_count); - SLJIT_ASSERT(!put_label || put_label->addr >= word_count); /* These structures are ordered by their address. */ - if (label && label->size == word_count) { - label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset); + if (next_min_addr == next_label_size) { + label->u.addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset); label->size = (sljit_uw)(code_ptr - code); label = label->next; + next_label_size = SLJIT_GET_NEXT_SIZE(label); } - if (jump && jump->addr == word_count) { + + if (next_min_addr == next_jump_addr) { + if (!(jump->flags & JUMP_MOV_ADDR)) { #if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) - word_count += 2; -#else - word_count += 6; -#endif - jump->addr = (sljit_uw)(code_ptr - 1); - code_ptr = detect_jump_type(jump, code, executable_offset); + word_count += 2; +#else /* !SLJIT_CONFIG_MIPS_32 */ + word_count += 6; +#endif /* SLJIT_CONFIG_MIPS_32 */ + jump->addr = (sljit_uw)(code_ptr - 1); + code_ptr = detect_jump_type(jump, code, executable_offset); + } else { + jump->addr = (sljit_uw)code_ptr; +#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) + code_ptr += 1; + word_count += 1; +#else /* !SLJIT_CONFIG_MIPS_32 */ + code_ptr += mov_addr_get_length(jump, code, executable_offset); + word_count += 5; +#endif /* SLJIT_CONFIG_MIPS_32 */ + } + jump = jump->next; - } - if (const_ && const_->addr == word_count) { + next_jump_addr = SLJIT_GET_NEXT_ADDRESS(jump); + } else if (next_min_addr == next_const_addr) { const_->addr = (sljit_uw)code_ptr; const_ = const_->next; + next_const_addr = SLJIT_GET_NEXT_ADDRESS(const_); } - if (put_label && put_label->addr == word_count) { - SLJIT_ASSERT(put_label->label); - put_label->addr = (sljit_uw)code_ptr; -#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) - code_ptr += 1; - word_count += 1; -#else - code_ptr += put_label_get_length(put_label, (sljit_uw)(SLJIT_ADD_EXEC_OFFSET(code, executable_offset) + put_label->label->size)); - word_count += 5; -#endif - put_label = put_label->next; - } - next_addr = compute_next_addr(label, jump, const_, put_label); + + SLJIT_GET_NEXT_MIN(); } code_ptr++; word_count++; @@ -791,7 +781,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil } while (buf); if (label && label->size == word_count) { - label->addr = (sljit_uw)code_ptr; + label->u.addr = (sljit_uw)code_ptr; label->size = (sljit_uw)(code_ptr - code); label = label->next; } @@ -799,13 +789,12 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil SLJIT_ASSERT(!label); SLJIT_ASSERT(!jump); SLJIT_ASSERT(!const_); - SLJIT_ASSERT(!put_label); SLJIT_ASSERT(code_ptr - code <= (sljit_sw)compiler->size); jump = compiler->jumps; while (jump) { do { - addr = (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target; + addr = (jump->flags & JUMP_ADDR) ? jump->u.target : jump->u.label->u.addr; buf_ptr = (sljit_ins *)jump->addr; if (jump->flags & PATCH_B) { @@ -821,15 +810,10 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil break; } - load_addr_to_reg(jump, PIC_ADDR_REG); + load_addr_to_reg(jump); } while (0); - jump = jump->next; - } - put_label = compiler->put_labels; - while (put_label) { - load_addr_to_reg(put_label, 0); - put_label = put_label->next; + jump = jump->next; } compiler->error = SLJIT_ERR_COMPILED; @@ -932,9 +916,9 @@ static sljit_s32 emit_op_mem(struct sljit_compiler *compiler, sljit_s32 flags, s static sljit_s32 emit_stack_frame_release(struct sljit_compiler *compiler, sljit_s32 frame_size, sljit_ins *ins_ptr); #if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) -#define SELECT_OP(a, b) (b) +#define SELECT_OP(d, w) (w) #else -#define SELECT_OP(a, b) (!(op & SLJIT_32) ? a : b) +#define SELECT_OP(d, w) (!(op & SLJIT_32) ? (d) : (w)) #endif #if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) @@ -1001,9 +985,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compi offset = local_size - SSIZE_OF(sw); } else { FAIL_IF(load_immediate(compiler, OTHER_FLAG, local_size)); - FAIL_IF(push_inst(compiler, ADDU_W | S(SLJIT_SP) | TA(0) | D(TMP_REG2), DR(TMP_REG2))); + FAIL_IF(push_inst(compiler, ADDU_W | S(SLJIT_SP) | TA(0) | D(TMP_REG1), DR(TMP_REG1))); FAIL_IF(push_inst(compiler, SUBU_W | S(SLJIT_SP) | TA(OTHER_FLAG) | D(SLJIT_SP), DR(SLJIT_SP))); - base = S(TMP_REG2); + base = S(TMP_REG1); offset = -SSIZE_OF(sw); #if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) local_size = 0; @@ -1212,8 +1196,8 @@ static sljit_s32 emit_stack_frame_release(struct sljit_compiler *compiler, sljit if (tmp < frame_size) tmp = frame_size; - FAIL_IF(load_immediate(compiler, DR(TMP_REG1), local_size - tmp)); - FAIL_IF(push_inst(compiler, ADDU_W | S(SLJIT_SP) | T(TMP_REG1) | D(SLJIT_SP), DR(SLJIT_SP))); + FAIL_IF(load_immediate(compiler, DR(TMP_REG2), local_size - tmp)); + FAIL_IF(push_inst(compiler, ADDU_W | S(SLJIT_SP) | T(TMP_REG2) | D(SLJIT_SP), DR(SLJIT_SP))); local_size = tmp; } @@ -1711,7 +1695,7 @@ static sljit_s32 emit_rev16(struct sljit_compiler *compiler, sljit_s32 op, sljit static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 flags, sljit_s32 dst, sljit_s32 src1, sljit_sw src2) { - sljit_s32 is_overflow, is_carry, carry_src_ar, is_handled; + sljit_s32 is_overflow, is_carry, carry_src_ar, is_handled, reg; sljit_ins op_imm, op_v; #if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) sljit_ins ins, op_dimm, op_dimm32, op_dv; @@ -1963,8 +1947,9 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl is_handled = 1; if (flags & SRC2_IMM) { - FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(TMP_REG2) | IMM(src2), DR(TMP_REG2))); - src2 = TMP_REG2; + reg = (src1 == TMP_REG1) ? TMP_REG2 : TMP_REG1; + FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(reg) | IMM(src2), DR(reg))); + src2 = reg; flags &= ~SRC2_IMM; } @@ -2283,7 +2268,7 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3 sljit_s32 dst_r = TMP_REG2; sljit_s32 src1_r; sljit_sw src2_r = 0; - sljit_s32 sugg_src2_r = TMP_REG2; + sljit_s32 src2_tmp_reg = (GET_OPCODE(op) >= SLJIT_OP2_BASE && FAST_IS_REG(src1)) ? TMP_REG1 : TMP_REG2; if (!(flags & ALT_KEEP_CACHE)) { compiler->cache_arg = 0; @@ -2299,7 +2284,7 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3 dst_r = dst; flags |= REG_DEST; if (flags & MOVE_OP) - sugg_src2_r = dst_r; + src2_tmp_reg = dst_r; } else if ((dst & SLJIT_MEM) && !getput_arg_fast(compiler, flags | ARG_TEST, DR(TMP_REG1), dst, dstw)) flags |= SLOW_DEST; @@ -2351,8 +2336,8 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3 else if (src2 == SLJIT_IMM) { if (!(flags & SRC2_IMM)) { if (src2w) { - FAIL_IF(load_immediate(compiler, DR(sugg_src2_r), src2w)); - src2_r = sugg_src2_r; + FAIL_IF(load_immediate(compiler, DR(src2_tmp_reg), src2w)); + src2_r = src2_tmp_reg; } else { src2_r = 0; @@ -2366,16 +2351,16 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3 } } else { - if (getput_arg_fast(compiler, flags | LOAD_DATA, DR(sugg_src2_r), src2, src2w)) + if (getput_arg_fast(compiler, flags | LOAD_DATA, DR(src2_tmp_reg), src2, src2w)) FAIL_IF(compiler->error); else flags |= SLOW_SRC2; - src2_r = sugg_src2_r; + src2_r = src2_tmp_reg; } if ((flags & (SLOW_SRC1 | SLOW_SRC2)) == (SLOW_SRC1 | SLOW_SRC2)) { SLJIT_ASSERT(src2_r == TMP_REG2); - if (!can_cache(src1, src1w, src2, src2w) && can_cache(src1, src1w, dst, dstw)) { + if ((flags & SLOW_DEST) && !can_cache(src1, src1w, src2, src2w) && can_cache(src1, src1w, dst, dstw)) { FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, DR(TMP_REG2), src2, src2w, src1, src1w)); FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, DR(TMP_REG1), src1, src1w, dst, dstw)); } @@ -2387,7 +2372,7 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3 else if (flags & SLOW_SRC1) FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, DR(TMP_REG1), src1, src1w, dst, dstw)); else if (flags & SLOW_SRC2) - FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, DR(sugg_src2_r), src2, src2w, dst, dstw)); + FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, DR(src2_tmp_reg), src2, src2w, dst, dstw)); FAIL_IF(emit_single_op(compiler, op, flags, dst_r, src1_r, src2_r)); @@ -2659,12 +2644,28 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compil #if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) #define SELECT_OP3(op, src2w, D, D32, W) (((op & SLJIT_32) ? (W) : ((src2w) < 32) ? (D) : (D32)) | (((sljit_ins)src2w & 0x1f) << 6)) -#define SELECT_OP2(op, D, W) ((op & SLJIT_32) ? (W) : (D)) #else /* !SLJIT_CONFIG_MIPS_64 */ #define SELECT_OP3(op, src2w, D, D32, W) ((W) | ((sljit_ins)(src2w) << 6)) -#define SELECT_OP2(op, D, W) (W) #endif /* SLJIT_CONFIG_MIPS_64 */ +SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2r(struct sljit_compiler *compiler, sljit_s32 op, + sljit_s32 dst_reg, + sljit_s32 src1, sljit_sw src1w, + sljit_s32 src2, sljit_sw src2w) +{ + CHECK_ERROR(); + CHECK(check_sljit_emit_op2r(compiler, op, dst_reg, src1, src1w, src2, src2w)); + + switch (GET_OPCODE(op)) { + case SLJIT_MULADD: + SLJIT_SKIP_CHECKS(compiler); + FAIL_IF(sljit_emit_op2(compiler, SLJIT_MUL | (op & SLJIT_32), TMP_REG2, 0, src1, src1w, src2, src2w)); + return push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(dst_reg) | T(TMP_REG2) | D(dst_reg), DR(dst_reg)); + } + + return SLJIT_SUCCESS; +} + SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 dst_reg, sljit_s32 src1_reg, @@ -2718,18 +2719,18 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler * FAIL_IF(emit_op_mem(compiler, inp_flags, DR(TMP_REG2), src3, src3w)); src3 = TMP_REG2; } else if (dst_reg == src3) { - FAIL_IF(push_inst(compiler, SELECT_OP2(op, DADDU, ADDU) | S(src3) | TA(0) | D(TMP_REG2), DR(TMP_REG2))); + FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(src3) | TA(0) | D(TMP_REG2), DR(TMP_REG2))); src3 = TMP_REG2; } if (is_left) { - ins1 = SELECT_OP2(op, DSRL, SRL); - ins2 = SELECT_OP2(op, DSLLV, SLLV); - ins3 = SELECT_OP2(op, DSRLV, SRLV); + ins1 = SELECT_OP(DSRL, SRL); + ins2 = SELECT_OP(DSLLV, SLLV); + ins3 = SELECT_OP(DSRLV, SRLV); } else { - ins1 = SELECT_OP2(op, DSLL, SLL); - ins2 = SELECT_OP2(op, DSRLV, SRLV); - ins3 = SELECT_OP2(op, DSLLV, SLLV); + ins1 = SELECT_OP(DSLL, SLL); + ins2 = SELECT_OP(DSRLV, SRLV); + ins3 = SELECT_OP(DSLLV, SLLV); } FAIL_IF(push_inst(compiler, ins2 | S(src3) | T(src1_reg) | D(dst_reg), DR(dst_reg))); @@ -2739,14 +2740,13 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler * FAIL_IF(push_inst(compiler, XORI | S(src3) | T(TMP_REG2) | ((sljit_ins)bit_length - 1), DR(TMP_REG2))); src2_reg = TMP_REG1; } else - FAIL_IF(push_inst(compiler, SELECT_OP2(op, DSUBU, SUBU) | SA(0) | T(src3) | D(TMP_REG2), DR(TMP_REG2))); + FAIL_IF(push_inst(compiler, SELECT_OP(DSUBU, SUBU) | SA(0) | T(src3) | D(TMP_REG2), DR(TMP_REG2))); FAIL_IF(push_inst(compiler, ins3 | S(TMP_REG2) | T(src2_reg) | D(TMP_REG1), DR(TMP_REG1))); return push_inst(compiler, OR | S(dst_reg) | T(TMP_REG1) | D(dst_reg), DR(dst_reg)); } #undef SELECT_OP3 -#undef SELECT_OP2 SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw) @@ -3103,7 +3103,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compil switch (GET_OPCODE(op)) { case SLJIT_MOV_F64: if (src != dst_r) { - if (dst_r != TMP_FREG1) + if (!(dst & SLJIT_MEM)) FAIL_IF(push_inst(compiler, MOV_fmt(FMT(op)) | FS(src) | FD(dst_r), MOVABLE_INS)); else dst_r = src; @@ -3162,11 +3162,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compil } if ((flags & (SLOW_SRC1 | SLOW_SRC2)) == (SLOW_SRC1 | SLOW_SRC2)) { - if (!can_cache(src1, src1w, src2, src2w) && can_cache(src1, src1w, dst, dstw)) { + if ((dst & SLJIT_MEM) && !can_cache(src1, src1w, src2, src2w) && can_cache(src1, src1w, dst, dstw)) { FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, FR(TMP_FREG2), src2, src2w, src1, src1w)); FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, FR(TMP_FREG1), src1, src1w, dst, dstw)); - } - else { + } else { FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, FR(TMP_FREG1), src1, src1w, src2, src2w)); FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, FR(TMP_FREG2), src2, src2w, dst, dstw)); } @@ -3361,10 +3360,10 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile PTR_FAIL_IF(push_inst(compiler, inst, UNMOVABLE_INS)); if (type <= SLJIT_JUMP) - PTR_FAIL_IF(push_inst(compiler, JR | S(TMP_REG2), UNMOVABLE_INS)); + PTR_FAIL_IF(push_inst(compiler, JR | S(PIC_ADDR_REG), UNMOVABLE_INS)); else { jump->flags |= IS_JAL; - PTR_FAIL_IF(push_inst(compiler, JALR | S(TMP_REG2) | DA(RETURN_ADDR_REG), UNMOVABLE_INS)); + PTR_FAIL_IF(push_inst(compiler, JALR | S(PIC_ADDR_REG) | DA(RETURN_ADDR_REG), UNMOVABLE_INS)); } jump->addr = compiler->size; @@ -3392,8 +3391,8 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile #define RESOLVE_IMM2() \ if (src2 == SLJIT_IMM) { \ if (src2w) { \ - PTR_FAIL_IF(load_immediate(compiler, DR(TMP_REG2), src2w)); \ - src2 = TMP_REG2; \ + PTR_FAIL_IF(load_immediate(compiler, DR(src2_tmp_reg), src2w)); \ + src2 = src2_tmp_reg; \ } \ else \ src2 = 0; \ @@ -3406,6 +3405,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler struct sljit_jump *jump; sljit_s32 flags; sljit_ins inst; + sljit_s32 src2_tmp_reg = FAST_IS_REG(src1) ? TMP_REG1 : TMP_REG2; CHECK_ERROR_PTR(); CHECK_PTR(check_sljit_emit_cmp(compiler, type, src1, src1w, src2, src2w)); @@ -3426,8 +3426,8 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler } if (src2 & SLJIT_MEM) { - PTR_FAIL_IF(emit_op_mem2(compiler, flags, DR(TMP_REG2), src2, src2w, 0, 0)); - src2 = TMP_REG2; + PTR_FAIL_IF(emit_op_mem2(compiler, flags, DR(src2_tmp_reg), src2, src2w, 0, 0)); + src2 = src2_tmp_reg; } jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump)); @@ -3515,7 +3515,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler PTR_FAIL_IF(push_inst(compiler, (type == SLJIT_EQUAL ? BNE : BEQ) | S(TMP_REG1) | TA(0) | BRANCH_LENGTH, UNMOVABLE_INS)); } - PTR_FAIL_IF(push_inst(compiler, JR | S(TMP_REG2), UNMOVABLE_INS)); + PTR_FAIL_IF(push_inst(compiler, JR | S(PIC_ADDR_REG), UNMOVABLE_INS)); jump->addr = compiler->size; PTR_FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS)); @@ -3553,11 +3553,11 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compi if (compiler->delay_slot != UNMOVABLE_INS) jump->flags |= IS_MOVABLE; - src = TMP_REG2; + src = PIC_ADDR_REG; } else if (src & SLJIT_MEM) { ADJUST_LOCAL_OFFSET(src, srcw); - FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, DR(TMP_REG2), src, srcw)); - src = TMP_REG2; + FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, DR(PIC_ADDR_REG), src, srcw)); + src = PIC_ADDR_REG; } if (type <= SLJIT_JUMP) @@ -3755,8 +3755,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *comp #if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1 && SLJIT_MIPS_REV < 6) if (src1 & SLJIT_MEM) { - FAIL_IF(emit_op_mem(compiler, inp_flags, DR(TMP_REG2), src1, src1w)); - src1 = TMP_REG2; + FAIL_IF(emit_op_mem(compiler, inp_flags, DR(TMP_REG1), src1, src1w)); + src1 = TMP_REG1; } else if (src1 == SLJIT_IMM) { #if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) if (type & SLJIT_32) @@ -3784,13 +3784,13 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *comp type ^= 0x1; } else { if (ADDRESSING_DEPENDS_ON(src1, dst_reg)) { - FAIL_IF(push_inst(compiler, ADDU_W | S(dst_reg) | TA(0) | D(TMP_REG2), DR(TMP_REG2))); + FAIL_IF(push_inst(compiler, ADDU_W | S(dst_reg) | TA(0) | D(TMP_REG1), DR(TMP_REG1))); if ((src1 & REG_MASK) == dst_reg) - src1 = (src1 & ~REG_MASK) | TMP_REG2; + src1 = (src1 & ~REG_MASK) | TMP_REG1; if (OFFS_REG(src1) == dst_reg) - src1 = (src1 & ~OFFS_REG_MASK) | TO_OFFS_REG(TMP_REG2); + src1 = (src1 & ~OFFS_REG_MASK) | TO_OFFS_REG(TMP_REG1); } FAIL_IF(push_inst(compiler, mov_ins | S(src2_reg) | TA(0) | D(dst_reg), DR(dst_reg))); @@ -3847,8 +3847,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fselect(struct sljit_compiler *com #if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1 && SLJIT_MIPS_REV < 6) if (src1 & SLJIT_MEM) { - FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(type) | LOAD_DATA, FR(TMP_FREG1), src1, src1w)); - src1 = TMP_FREG1; + FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(type) | LOAD_DATA, FR(TMP_FREG2), src1, src1w)); + src1 = TMP_FREG2; } return push_inst(compiler, get_select_cc(type, 1) | FMT(type) | FS(src1) | FD(dst_freg), MOVABLE_INS); @@ -4231,18 +4231,18 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi return const_; } -SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label* sljit_emit_put_label(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw) +SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_mov_addr(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw) { - struct sljit_put_label *put_label; + struct sljit_jump *jump; sljit_s32 dst_r; CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_put_label(compiler, dst, dstw)); + CHECK_PTR(check_sljit_emit_mov_addr(compiler, dst, dstw)); ADJUST_LOCAL_OFFSET(dst, dstw); - put_label = (struct sljit_put_label*)ensure_abuf(compiler, sizeof(struct sljit_put_label)); - PTR_FAIL_IF(!put_label); - set_put_label(put_label, compiler, 0); + jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump)); + PTR_FAIL_IF(!jump); + set_mov_addr(jump, compiler, 0); dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2; PTR_FAIL_IF(push_inst(compiler, (sljit_ins)dst_r, UNMOVABLE_INS)); @@ -4255,5 +4255,5 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label* sljit_emit_put_label(struct slj if (dst & SLJIT_MEM) PTR_FAIL_IF(emit_op_mem(compiler, WORD_DATA, DR(TMP_REG2), dst, dstw)); - return put_label; + return jump; } diff --git a/src/sljit/sljitNativePPC_common.c b/src/sljit/sljitNativePPC_common.c index 54977f0..1f17d90 100644 --- a/src/sljit/sljitNativePPC_common.c +++ b/src/sljit/sljitNativePPC_common.c @@ -98,7 +98,7 @@ static void ppc_cache_flush(sljit_ins *from, sljit_ins *to) #if (defined SLJIT_PASS_ENTRY_ADDR_TO_CALL && SLJIT_PASS_ENTRY_ADDR_TO_CALL) #define TMP_CALL_REG (SLJIT_NUMBER_OF_REGISTERS + 5) #else -#define TMP_CALL_REG TMP_REG2 +#define TMP_CALL_REG TMP_REG1 #endif #define TMP_FREG1 (SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1) @@ -310,24 +310,23 @@ static sljit_s32 push_inst(struct sljit_compiler *compiler, sljit_ins ins) return SLJIT_SUCCESS; } -static SLJIT_INLINE sljit_s32 detect_jump_type(struct sljit_jump *jump, sljit_ins *code_ptr, sljit_ins *code, sljit_sw executable_offset) +static SLJIT_INLINE sljit_ins* detect_jump_type(struct sljit_jump *jump, sljit_ins *code_ptr, sljit_ins *code, sljit_sw executable_offset) { sljit_sw diff; sljit_uw target_addr; - sljit_uw extra_jump_flags; #if (defined SLJIT_PASS_ENTRY_ADDR_TO_CALL && SLJIT_PASS_ENTRY_ADDR_TO_CALL) && (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) if (jump->flags & (SLJIT_REWRITABLE_JUMP | IS_CALL)) - return 0; + goto exit; #else if (jump->flags & SLJIT_REWRITABLE_JUMP) - return 0; + goto exit; #endif if (jump->flags & JUMP_ADDR) target_addr = jump->u.target; else { - SLJIT_ASSERT(jump->flags & JUMP_LABEL); + SLJIT_ASSERT(jump->u.label != NULL); target_addr = (sljit_uw)(code + jump->u.label->size) + (sljit_uw)executable_offset; } @@ -336,101 +335,256 @@ static SLJIT_INLINE sljit_s32 detect_jump_type(struct sljit_jump *jump, sljit_in goto keep_address; #endif - diff = ((sljit_sw)target_addr - (sljit_sw)(code_ptr) - executable_offset) & ~0x3l; + diff = (sljit_sw)target_addr - (sljit_sw)code_ptr - executable_offset; - extra_jump_flags = 0; if (jump->flags & IS_COND) { if (diff <= 0x7fff && diff >= -0x8000) { jump->flags |= PATCH_B; - return 1; + return code_ptr; } if (target_addr <= 0xffff) { jump->flags |= PATCH_B | PATCH_ABS_B; - return 1; + return code_ptr; } - extra_jump_flags = REMOVE_COND; diff -= SSIZE_OF(ins); } if (diff <= 0x01ffffff && diff >= -0x02000000) { - jump->flags |= PATCH_B | extra_jump_flags; - return 1; + jump->flags |= PATCH_B; + } else if (target_addr <= 0x01ffffff) { + jump->flags |= PATCH_B | PATCH_ABS_B; } - if (target_addr <= 0x03ffffff) { - jump->flags |= PATCH_B | PATCH_ABS_B | extra_jump_flags; - return 1; + if (jump->flags & PATCH_B) { + if (!(jump->flags & IS_COND)) + return code_ptr; + + code_ptr[0] = BCx | (2 << 2) | ((code_ptr[0] ^ (8 << 21)) & 0x03ff0001); + code_ptr[1] = Bx; + jump->addr += sizeof(sljit_ins); + jump->flags -= IS_COND; + return code_ptr + 1; } #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) #if (defined SLJIT_PASS_ENTRY_ADDR_TO_CALL && SLJIT_PASS_ENTRY_ADDR_TO_CALL) keep_address: -#endif - if (target_addr <= 0x7fffffff) { +#endif /* SLJIT_PASS_ENTRY_ADDR_TO_CALL */ + if (target_addr < 0x80000000l) { jump->flags |= PATCH_ABS32; - return 1; + code_ptr[2] = MTCTR | S(TMP_CALL_REG); + code_ptr[3] = code_ptr[0]; + return code_ptr + 3; } - if (target_addr <= 0x7fffffffffffl) { + if (target_addr < 0x800000000000l) { jump->flags |= PATCH_ABS48; - return 1; + code_ptr[4] = MTCTR | S(TMP_CALL_REG); + code_ptr[5] = code_ptr[0]; + return code_ptr + 5; } -#endif +#endif /* SLJIT_CONFIG_PPC_64 */ - return 0; +exit: +#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) + code_ptr[2] = MTCTR | S(TMP_CALL_REG); + code_ptr[3] = code_ptr[0]; +#else /* !SLJIT_CONFIG_PPC_32 */ + code_ptr[5] = MTCTR | S(TMP_CALL_REG); + code_ptr[6] = code_ptr[0]; +#endif /* SLJIT_CONFIG_PPC_32 */ + return code_ptr + JUMP_MAX_SIZE - 1; } #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) -static SLJIT_INLINE sljit_sw put_label_get_length(struct sljit_put_label *put_label, sljit_uw max_label) +static SLJIT_INLINE sljit_sw mov_addr_get_length(struct sljit_jump *jump, sljit_ins *code, sljit_sw executable_offset) { - if (max_label < 0x100000000l) { - put_label->flags = 0; + sljit_uw addr; + SLJIT_UNUSED_ARG(executable_offset); + + SLJIT_ASSERT(jump->flags < ((sljit_uw)5 << JUMP_SIZE_SHIFT)); + if (jump->flags & JUMP_ADDR) + addr = jump->u.target; + else + addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code + jump->u.label->size, executable_offset); + + if (addr < 0x80000000l) { + SLJIT_ASSERT(jump->flags >= ((sljit_uw)1 << JUMP_SIZE_SHIFT)); + jump->flags |= PATCH_ABS32; return 1; } - if (max_label < 0x1000000000000l) { - put_label->flags = 1; + if (addr < 0x800000000000l) { + SLJIT_ASSERT(jump->flags >= ((sljit_uw)3 << JUMP_SIZE_SHIFT)); + jump->flags |= PATCH_ABS48; return 3; } - put_label->flags = 2; + SLJIT_ASSERT(jump->flags >= ((sljit_uw)4 << JUMP_SIZE_SHIFT)); return 4; } -static SLJIT_INLINE void put_label_set(struct sljit_put_label *put_label) -{ - sljit_uw addr = put_label->label->addr; - sljit_ins *inst = (sljit_ins *)put_label->addr; - sljit_u32 reg = *inst; +#endif /* SLJIT_CONFIG_PPC_64 */ - if (put_label->flags == 0) { - SLJIT_ASSERT(addr < 0x100000000l); - inst[0] = ORIS | S(TMP_ZERO) | A(reg) | IMM(addr >> 16); - } - else { - if (put_label->flags == 1) { - SLJIT_ASSERT(addr < 0x1000000000000l); - inst[0] = ORI | S(TMP_ZERO) | A(reg) | IMM(addr >> 32); +static void generate_jump_or_mov_addr(struct sljit_jump *jump, sljit_sw executable_offset) +{ + sljit_uw flags = jump->flags; + sljit_uw addr = (flags & JUMP_ADDR) ? jump->u.target : jump->u.label->u.addr; + sljit_ins *ins = (sljit_ins*)jump->addr; + sljit_s32 reg; + SLJIT_UNUSED_ARG(executable_offset); + + if (flags & PATCH_B) { + if (flags & IS_COND) { + if (!(flags & PATCH_ABS_B)) { + addr -= (sljit_uw)SLJIT_ADD_EXEC_OFFSET(ins, executable_offset); + SLJIT_ASSERT((sljit_sw)addr <= 0x7fff && (sljit_sw)addr >= -0x8000); + ins[0] = BCx | ((sljit_ins)addr & 0xfffc) | (ins[0] & 0x03ff0001); + } else { + SLJIT_ASSERT(addr <= 0xffff); + ins[0] = BCx | ((sljit_ins)addr & 0xfffc) | 0x2 | ((*ins) & 0x03ff0001); + } + return; } - else { - inst[0] = ORIS | S(TMP_ZERO) | A(reg) | IMM(addr >> 48); - inst[1] = ORI | S(reg) | A(reg) | IMM((addr >> 32) & 0xffff); - inst++; + + if (!(flags & PATCH_ABS_B)) { + addr -= (sljit_uw)SLJIT_ADD_EXEC_OFFSET(ins, executable_offset); + SLJIT_ASSERT((sljit_sw)addr <= 0x01ffffff && (sljit_sw)addr >= -0x02000000); + ins[0] = Bx | ((sljit_ins)addr & 0x03fffffc) | (ins[0] & 0x1); + } else { + SLJIT_ASSERT(addr <= 0x03ffffff); + ins[0] = Bx | ((sljit_ins)addr & 0x03fffffc) | 0x2 | (ins[0] & 0x1); } + return; + } + + reg = (flags & JUMP_MOV_ADDR) ? (sljit_s32)ins[0] : TMP_CALL_REG; + +#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) + ins[0] = ADDIS | D(reg) | A(0) | IMM(addr >> 16); + ins[1] = ORI | S(reg) | A(reg) | IMM(addr); +#else /* !SLJIT_CONFIG_PPC_32 */ + + /* The TMP_ZERO cannot be used because it is restored for tail calls. */ + if (flags & PATCH_ABS32) { + SLJIT_ASSERT(addr < 0x80000000l); + ins[0] = ADDIS | D(reg) | A(0) | IMM(addr >> 16); + ins[1] = ORI | S(reg) | A(reg) | IMM(addr); + return; + } - inst[1] = SLDI(32) | S(reg) | A(reg); - inst[2] = ORIS | S(reg) | A(reg) | IMM((addr >> 16) & 0xffff); - inst += 2; + if (flags & PATCH_ABS48) { + SLJIT_ASSERT(addr < 0x800000000000l); + ins[0] = ADDIS | D(reg) | A(0) | IMM(addr >> 32); + ins[1] = ORI | S(reg) | A(reg) | IMM(addr >> 16); + ins[2] = SLDI(16) | S(reg) | A(reg); + ins[3] = ORI | S(reg) | A(reg) | IMM(addr); + return; } - inst[1] = ORI | S(reg) | A(reg) | IMM(addr & 0xffff); + ins[0] = ADDIS | D(reg) | A(0) | IMM(addr >> 48); + ins[1] = ORI | S(reg) | A(reg) | IMM(addr >> 32); + ins[2] = SLDI(32) | S(reg) | A(reg); + ins[3] = ORIS | S(reg) | A(reg) | IMM(addr >> 16); + ins[4] = ORI | S(reg) | A(reg) | IMM(addr); +#endif /* SLJIT_CONFIG_PPC_32 */ } +static void reduce_code_size(struct sljit_compiler *compiler) +{ + struct sljit_label *label; + struct sljit_jump *jump; + struct sljit_const *const_; + SLJIT_NEXT_DEFINE_TYPES; + sljit_uw total_size; + sljit_uw size_reduce = 0; + sljit_sw diff; + + label = compiler->labels; + jump = compiler->jumps; + const_ = compiler->consts; + SLJIT_NEXT_INIT_TYPES(); + + while (1) { + SLJIT_GET_NEXT_MIN(); + + if (next_min_addr == SLJIT_MAX_ADDRESS) + break; + + if (next_min_addr == next_label_size) { + label->size -= size_reduce; + + label = label->next; + next_label_size = SLJIT_GET_NEXT_SIZE(label); + } + + if (next_min_addr == next_const_addr) { + const_->addr -= size_reduce; + const_ = const_->next; + next_const_addr = SLJIT_GET_NEXT_ADDRESS(const_); + continue; + } + + if (next_min_addr != next_jump_addr) + continue; + + jump->addr -= size_reduce; + if (!(jump->flags & JUMP_MOV_ADDR)) { + total_size = JUMP_MAX_SIZE - 1; + + if (!(jump->flags & SLJIT_REWRITABLE_JUMP)) { + if (jump->flags & JUMP_ADDR) { + if (jump->u.target <= 0x01ffffff) + total_size = 1 - 1; +#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) + else if (jump->u.target < 0x80000000l) + total_size = 4 - 1; + else if (jump->u.target < 0x800000000000l) + total_size = 6 - 1; +#endif /* SLJIT_CONFIG_PPC_64 */ + } else { + /* Unit size: instruction. */ + diff = (sljit_sw)jump->u.label->size - (sljit_sw)jump->addr; + + if (jump->flags & IS_COND) { + if (diff <= (0x7fff / SSIZE_OF(ins)) && diff >= (-0x8000 / SSIZE_OF(ins))) + total_size = 1 - 1; + else if ((diff - 1) <= (0x01ffffff / SSIZE_OF(ins)) && (diff - 1) >= (-0x02000000 / SSIZE_OF(ins))) + total_size = 2 - 1; + } else if (diff <= (0x01ffffff / SSIZE_OF(ins)) && diff >= (-0x02000000 / SSIZE_OF(ins))) + total_size = 1 - 1; + } + } + + size_reduce += (JUMP_MAX_SIZE - 1) - total_size; + jump->flags |= total_size << JUMP_SIZE_SHIFT; +#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) + } else { + total_size = (sljit_uw)4 << JUMP_SIZE_SHIFT; + + if (jump->flags & JUMP_ADDR) { + if (jump->u.target < 0x80000000l) { + total_size = (sljit_uw)1 << JUMP_SIZE_SHIFT; + size_reduce += 3; + } else if (jump->u.target < 0x800000000000l) { + total_size = (sljit_uw)3 << JUMP_SIZE_SHIFT; + size_reduce += 1; + } + } + jump->flags |= total_size; #endif /* SLJIT_CONFIG_PPC_64 */ + } -SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler) + jump = jump->next; + next_jump_addr = SLJIT_GET_NEXT_ADDRESS(jump); + } + + compiler->size -= size_reduce; +} + +SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler, sljit_s32 options, void *exec_allocator_data) { struct sljit_memory_fragment *buf; sljit_ins *code; @@ -438,18 +592,17 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil sljit_ins *buf_ptr; sljit_ins *buf_end; sljit_uw word_count; - sljit_uw next_addr; + SLJIT_NEXT_DEFINE_TYPES; sljit_sw executable_offset; - sljit_uw addr; struct sljit_label *label; struct sljit_jump *jump; struct sljit_const *const_; - struct sljit_put_label *put_label; CHECK_ERROR_PTR(); CHECK_PTR(check_sljit_generate_code(compiler)); - reverse_buf(compiler); + + reduce_code_size(compiler); #if (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL) /* add to compiler->size additional instruction space to hold the trampoline and padding */ @@ -459,93 +612,64 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil compiler->size += (sizeof(struct sljit_function_context) / sizeof(sljit_ins)); #endif #endif - code = (sljit_ins*)SLJIT_MALLOC_EXEC(compiler->size * sizeof(sljit_ins), compiler->exec_allocator_data); + code = (sljit_ins*)allocate_executable_memory(compiler->size * sizeof(sljit_ins), options, exec_allocator_data, &executable_offset); PTR_FAIL_WITH_EXEC_IF(code); + + reverse_buf(compiler); buf = compiler->buf; code_ptr = code; word_count = 0; - next_addr = 0; - executable_offset = SLJIT_EXEC_OFFSET(code); - label = compiler->labels; jump = compiler->jumps; const_ = compiler->consts; - put_label = compiler->put_labels; + SLJIT_NEXT_INIT_TYPES(); + SLJIT_GET_NEXT_MIN(); do { buf_ptr = (sljit_ins*)buf->memory; buf_end = buf_ptr + (buf->used_size >> 2); do { *code_ptr = *buf_ptr++; - if (next_addr == word_count) { + if (next_min_addr == word_count) { SLJIT_ASSERT(!label || label->size >= word_count); SLJIT_ASSERT(!jump || jump->addr >= word_count); SLJIT_ASSERT(!const_ || const_->addr >= word_count); - SLJIT_ASSERT(!put_label || put_label->addr >= word_count); /* These structures are ordered by their address. */ - if (label && label->size == word_count) { + if (next_min_addr == next_label_size) { /* Just recording the address. */ - label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset); + label->u.addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset); label->size = (sljit_uw)(code_ptr - code); label = label->next; + next_label_size = SLJIT_GET_NEXT_SIZE(label); } - if (jump && jump->addr == word_count) { -#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) - jump->addr = (sljit_uw)(code_ptr - 3); -#else - jump->addr = (sljit_uw)(code_ptr - 6); -#endif - if (detect_jump_type(jump, code_ptr, code, executable_offset)) { -#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) - code_ptr[-3] = code_ptr[0]; - code_ptr -= 3; -#else - if (jump->flags & PATCH_ABS32) { - code_ptr -= 3; - code_ptr[-1] = code_ptr[2]; - code_ptr[0] = code_ptr[3]; - } - else if (jump->flags & PATCH_ABS48) { - code_ptr--; - code_ptr[-1] = code_ptr[0]; - code_ptr[0] = code_ptr[1]; - /* rldicr rX,rX,32,31 -> rX,rX,16,47 */ - SLJIT_ASSERT((code_ptr[-3] & 0xfc00ffff) == 0x780007c6); - code_ptr[-3] ^= 0x8422; - /* oris -> ori */ - code_ptr[-2] ^= 0x4000000; - } - else { - code_ptr[-6] = code_ptr[0]; - code_ptr -= 6; - } -#endif - if (jump->flags & REMOVE_COND) { - code_ptr[0] = BCx | (2 << 2) | ((code_ptr[0] ^ (8 << 21)) & 0x03ff0001); - code_ptr++; - jump->addr += sizeof(sljit_ins); - code_ptr[0] = Bx; - jump->flags -= IS_COND; - } + + if (next_min_addr == next_jump_addr) { + if (!(jump->flags & JUMP_MOV_ADDR)) { + word_count += jump->flags >> JUMP_SIZE_SHIFT; + jump->addr = (sljit_uw)code_ptr; + code_ptr = detect_jump_type(jump, code_ptr, code, executable_offset); + SLJIT_ASSERT(((sljit_uw)code_ptr - jump->addr <= (jump->flags >> JUMP_SIZE_SHIFT) * sizeof(sljit_ins))); + } else { + jump->addr = (sljit_uw)code_ptr; +#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) + word_count += jump->flags >> JUMP_SIZE_SHIFT; + code_ptr += mov_addr_get_length(jump, code, executable_offset); +#else /* !SLJIT_CONFIG_PPC_64 */ + word_count++; + code_ptr++; +#endif /* SLJIT_CONFIG_PPC_64 */ } jump = jump->next; - } - if (const_ && const_->addr == word_count) { + next_jump_addr = SLJIT_GET_NEXT_ADDRESS(jump); + } else if (next_min_addr == next_const_addr) { const_->addr = (sljit_uw)code_ptr; const_ = const_->next; + next_const_addr = SLJIT_GET_NEXT_ADDRESS(const_); } - if (put_label && put_label->addr == word_count) { - SLJIT_ASSERT(put_label->label); - put_label->addr = (sljit_uw)code_ptr; -#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) - code_ptr += put_label_get_length(put_label, (sljit_uw)(SLJIT_ADD_EXEC_OFFSET(code, executable_offset) + put_label->label->size)); - word_count += 4; -#endif - put_label = put_label->next; - } - next_addr = compute_next_addr(label, jump, const_, put_label); + + SLJIT_GET_NEXT_MIN(); } code_ptr++; word_count++; @@ -555,7 +679,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil } while (buf); if (label && label->size == word_count) { - label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset); + label->u.addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset); label->size = (sljit_uw)(code_ptr - code); label = label->next; } @@ -563,7 +687,6 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil SLJIT_ASSERT(!label); SLJIT_ASSERT(!jump); SLJIT_ASSERT(!const_); - SLJIT_ASSERT(!put_label); #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)))); @@ -573,84 +696,10 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil jump = compiler->jumps; while (jump) { - do { - addr = (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target; - buf_ptr = (sljit_ins *)jump->addr; - - if (jump->flags & PATCH_B) { - if (jump->flags & IS_COND) { - if (!(jump->flags & PATCH_ABS_B)) { - addr -= (sljit_uw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset); - SLJIT_ASSERT((sljit_sw)addr <= 0x7fff && (sljit_sw)addr >= -0x8000); - *buf_ptr = BCx | ((sljit_ins)addr & 0xfffc) | ((*buf_ptr) & 0x03ff0001); - } - else { - SLJIT_ASSERT(addr <= 0xffff); - *buf_ptr = BCx | ((sljit_ins)addr & 0xfffc) | 0x2 | ((*buf_ptr) & 0x03ff0001); - } - } - else { - if (!(jump->flags & PATCH_ABS_B)) { - addr -= (sljit_uw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset); - SLJIT_ASSERT((sljit_sw)addr <= 0x01ffffff && (sljit_sw)addr >= -0x02000000); - *buf_ptr = Bx | ((sljit_ins)addr & 0x03fffffc) | ((*buf_ptr) & 0x1); - } - else { - SLJIT_ASSERT(addr <= 0x03ffffff); - *buf_ptr = Bx | ((sljit_ins)addr & 0x03fffffc) | 0x2 | ((*buf_ptr) & 0x1); - } - } - break; - } - - /* Set the fields of immediate loads. */ -#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) - SLJIT_ASSERT(((buf_ptr[0] | buf_ptr[1]) & 0xffff) == 0); - buf_ptr[0] |= (sljit_ins)(addr >> 16) & 0xffff; - buf_ptr[1] |= (sljit_ins)addr & 0xffff; -#else - if (jump->flags & PATCH_ABS32) { - SLJIT_ASSERT(addr <= 0x7fffffff); - SLJIT_ASSERT(((buf_ptr[0] | buf_ptr[1]) & 0xffff) == 0); - buf_ptr[0] |= (sljit_ins)(addr >> 16) & 0xffff; - buf_ptr[1] |= (sljit_ins)addr & 0xffff; - break; - } - - if (jump->flags & PATCH_ABS48) { - SLJIT_ASSERT(addr <= 0x7fffffffffff); - SLJIT_ASSERT(((buf_ptr[0] | buf_ptr[1] | buf_ptr[3]) & 0xffff) == 0); - buf_ptr[0] |= (sljit_ins)(addr >> 32) & 0xffff; - buf_ptr[1] |= (sljit_ins)(addr >> 16) & 0xffff; - buf_ptr[3] |= (sljit_ins)addr & 0xffff; - break; - } - - SLJIT_ASSERT(((buf_ptr[0] | buf_ptr[1] | buf_ptr[3] | buf_ptr[4]) & 0xffff) == 0); - buf_ptr[0] |= (sljit_ins)(addr >> 48) & 0xffff; - buf_ptr[1] |= (sljit_ins)(addr >> 32) & 0xffff; - buf_ptr[3] |= (sljit_ins)(addr >> 16) & 0xffff; - buf_ptr[4] |= (sljit_ins)addr & 0xffff; -#endif - } while (0); + generate_jump_or_mov_addr(jump, executable_offset); jump = jump->next; } - put_label = compiler->put_labels; - while (put_label) { -#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) - addr = put_label->label->addr; - buf_ptr = (sljit_ins *)put_label->addr; - - SLJIT_ASSERT((buf_ptr[0] & 0xfc1f0000) == ADDIS && (buf_ptr[1] & 0xfc000000) == ORI); - buf_ptr[0] |= (addr >> 16) & 0xffff; - buf_ptr[1] |= addr & 0xffff; -#else - put_label_set(put_label); -#endif - put_label = put_label->next; - } - compiler->error = SLJIT_ERR_COMPILED; compiler->executable_offset = executable_offset; @@ -671,11 +720,9 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil #if (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL) compiler->executable_size = (sljit_uw)(code_ptr - code) * sizeof(sljit_ins) + sizeof(struct sljit_function_context); - return code_ptr; #else compiler->executable_size = (sljit_uw)(code_ptr - code) * sizeof(sljit_ins); - return code; #endif } @@ -937,14 +984,16 @@ static sljit_s32 emit_stack_frame_release(struct sljit_compiler *compiler, sljit sljit_s32 i, tmp, base, offset; sljit_s32 local_size = compiler->local_size; + SLJIT_ASSERT(TMP_CALL_REG != TMP_REG2); + base = SLJIT_SP; if (local_size > STACK_MAX_DISTANCE) { - base = TMP_REG1; + base = TMP_REG2; if (local_size > 2 * STACK_MAX_DISTANCE + LR_SAVE_OFFSET) { FAIL_IF(push_inst(compiler, STACK_LOAD | D(base) | A(SLJIT_SP) | IMM(0))); local_size = 0; } else { - FAIL_IF(push_inst(compiler, ADDI | D(TMP_REG1) | A(SLJIT_SP) | IMM(local_size - STACK_MAX_DISTANCE))); + FAIL_IF(push_inst(compiler, ADDI | D(TMP_REG2) | A(SLJIT_SP) | IMM(local_size - STACK_MAX_DISTANCE))); local_size = STACK_MAX_DISTANCE; } } @@ -986,7 +1035,7 @@ static sljit_s32 emit_stack_frame_release(struct sljit_compiler *compiler, sljit if (local_size > 0) return push_inst(compiler, ADDI | D(SLJIT_SP) | A(base) | IMM(local_size)); - SLJIT_ASSERT(base == TMP_REG1); + SLJIT_ASSERT(base == TMP_REG2); return push_inst(compiler, OR | S(base) | A(SLJIT_SP) | B(base)); } @@ -1253,7 +1302,7 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3 sljit_s32 dst_r = TMP_REG2; sljit_s32 src1_r; sljit_s32 src2_r; - sljit_s32 sugg_src2_r = TMP_REG2; + sljit_s32 src2_tmp_reg = (!(input_flags & ALT_SIGN_EXT) && GET_OPCODE(op) >= SLJIT_OP2_BASE && FAST_IS_REG(src1)) ? TMP_REG1 : TMP_REG2; sljit_s32 flags = input_flags & (ALT_FORM1 | ALT_FORM2 | ALT_FORM3 | ALT_FORM4 | ALT_FORM5 | ALT_SIGN_EXT | ALT_SET_FLAGS); /* Destination check. */ @@ -1264,24 +1313,7 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3 flags |= REG_DEST; if (op >= SLJIT_MOV && op <= SLJIT_MOV_P) - sugg_src2_r = dst_r; - } - - /* Source 1. */ - if (FAST_IS_REG(src1)) { - src1_r = src1; - flags |= REG1_SOURCE; - } - else if (src1 == SLJIT_IMM) { - src1_r = TMP_ZERO; - if (src1w != 0) { - FAIL_IF(load_immediate(compiler, TMP_REG1, src1w)); - src1_r = TMP_REG1; - } - } - else { - FAIL_IF(emit_op_mem(compiler, input_flags | LOAD_DATA, TMP_REG1, src1, src1w, TMP_REG1)); - src1_r = TMP_REG1; + src2_tmp_reg = dst_r; } /* Source 2. */ @@ -1291,17 +1323,30 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3 if (!(flags & REG_DEST) && op >= SLJIT_MOV && op <= SLJIT_MOV_P) dst_r = src2_r; - } - else if (src2 == SLJIT_IMM) { + } else if (src2 == SLJIT_IMM) { src2_r = TMP_ZERO; if (src2w != 0) { - FAIL_IF(load_immediate(compiler, sugg_src2_r, src2w)); - src2_r = sugg_src2_r; + FAIL_IF(load_immediate(compiler, src2_tmp_reg, src2w)); + src2_r = src2_tmp_reg; } + } else { + FAIL_IF(emit_op_mem(compiler, input_flags | LOAD_DATA, src2_tmp_reg, src2, src2w, TMP_REG1)); + src2_r = src2_tmp_reg; } - else { - FAIL_IF(emit_op_mem(compiler, input_flags | LOAD_DATA, sugg_src2_r, src2, src2w, TMP_REG2)); - src2_r = sugg_src2_r; + + /* Source 1. */ + if (FAST_IS_REG(src1)) { + src1_r = src1; + flags |= REG1_SOURCE; + } else if (src1 == SLJIT_IMM) { + src1_r = TMP_ZERO; + if (src1w != 0) { + FAIL_IF(load_immediate(compiler, TMP_REG1, src1w)); + src1_r = TMP_REG1; + } + } else { + FAIL_IF(emit_op_mem(compiler, input_flags | LOAD_DATA, TMP_REG1, src1, src1w, TMP_REG1)); + src1_r = TMP_REG1; } FAIL_IF(emit_single_op(compiler, op, flags, dst_r, src1_r, src2_r)); @@ -1757,7 +1802,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile compiler->status_flags_state = SLJIT_CURRENT_FLAGS_SUB; if (GET_FLAG_TYPE(op) >= SLJIT_LESS && GET_FLAG_TYPE(op) <= SLJIT_LESS_EQUAL) { - if (dst == TMP_REG2) { + if (dst == TMP_REG1) { if (TEST_UL_IMM(src2, src2w)) { compiler->imm = (sljit_ins)src2w & 0xffff; return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM1 | ALT_FORM2, dst, dstw, src1, src1w, TMP_REG2, 0); @@ -1772,7 +1817,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM1 | ALT_FORM3, dst, dstw, src1, src1w, src2, src2w); } - if (dst == TMP_REG2 && GET_FLAG_TYPE(op) <= SLJIT_SIG_LESS_EQUAL) { + if (dst == TMP_REG1 && GET_FLAG_TYPE(op) <= SLJIT_SIG_LESS_EQUAL) { if (TEST_SL_IMM(src2, src2w)) { compiler->imm = (sljit_ins)src2w & 0xffff; return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM2 | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0); @@ -1911,13 +1956,31 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compil CHECK(check_sljit_emit_op2(compiler, op, 1, 0, 0, src1, src1w, src2, src2w)); SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_op2(compiler, op, TMP_REG2, 0, src1, src1w, src2, src2w); + return sljit_emit_op2(compiler, op, TMP_REG1, 0, src1, src1w, src2, src2w); } #undef TEST_ADD_FORM1 #undef TEST_SUB_FORM2 #undef TEST_SUB_FORM3 +SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2r(struct sljit_compiler *compiler, sljit_s32 op, + sljit_s32 dst_reg, + sljit_s32 src1, sljit_sw src1w, + sljit_s32 src2, sljit_sw src2w) +{ + CHECK_ERROR(); + CHECK(check_sljit_emit_op2r(compiler, op, dst_reg, src1, src1w, src2, src2w)); + + switch (GET_OPCODE(op)) { + case SLJIT_MULADD: + SLJIT_SKIP_CHECKS(compiler); + FAIL_IF(sljit_emit_op2(compiler, SLJIT_MUL | (op & SLJIT_32), TMP_REG2, 0, src1, src1w, src2, src2w)); + return push_inst(compiler, ADD | D(dst_reg) | A(dst_reg) | B(TMP_REG2)); + } + + return SLJIT_SUCCESS; +} + SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 dst_reg, sljit_s32 src1_reg, @@ -2228,7 +2291,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compil /* Fall through. */ case SLJIT_MOV_F64: if (src != dst_r) { - if (dst_r != TMP_FREG1) + if (!(dst & SLJIT_MEM)) FAIL_IF(push_inst(compiler, FMR | FD(dst_r) | FB(src))); else dst_r = src; @@ -2268,7 +2331,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compil } if (src2 & SLJIT_MEM) { - FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w, TMP_REG2)); + FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w, TMP_REG1)); src2 = TMP_FREG2; } @@ -2451,7 +2514,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile type &= 0xff; if ((type | 0x1) == SLJIT_NOT_CARRY) - PTR_FAIL_IF(push_inst(compiler, ADDE | RC(ALT_SET_FLAGS) | D(TMP_REG1) | A(TMP_ZERO) | B(TMP_ZERO))); + PTR_FAIL_IF(push_inst(compiler, ADDE | RC(ALT_SET_FLAGS) | D(TMP_REG2) | A(TMP_ZERO) | B(TMP_ZERO))); /* In PPC, we don't need to touch the arguments. */ if (type < SLJIT_JUMP) @@ -2461,10 +2524,11 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile jump->flags |= IS_CALL; #endif - PTR_FAIL_IF(emit_const(compiler, TMP_CALL_REG, 0)); - PTR_FAIL_IF(push_inst(compiler, MTCTR | S(TMP_CALL_REG))); jump->addr = compiler->size; PTR_FAIL_IF(push_inst(compiler, BCCTR | bo_bi_flags | (type >= SLJIT_FAST_CALL ? 1 : 0))); + + /* Maximum number of instructions required for generating a constant. */ + compiler->size += JUMP_MAX_SIZE - 1; return jump; } @@ -2498,18 +2562,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compi CHECK_ERROR(); CHECK(check_sljit_emit_ijump(compiler, type, src, srcw)); - if (FAST_IS_REG(src)) { -#if (defined SLJIT_PASS_ENTRY_ADDR_TO_CALL && SLJIT_PASS_ENTRY_ADDR_TO_CALL) - if (type >= SLJIT_CALL && src != TMP_CALL_REG) { - FAIL_IF(push_inst(compiler, OR | S(src) | A(TMP_CALL_REG) | B(src))); - src_r = TMP_CALL_REG; - } - else - src_r = src; -#else /* SLJIT_PASS_ENTRY_ADDR_TO_CALL */ - src_r = src; -#endif /* SLJIT_PASS_ENTRY_ADDR_TO_CALL */ - } else if (src == SLJIT_IMM) { + if (src == SLJIT_IMM) { /* These jumps are converted to jump/call instructions when possible. */ jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump)); FAIL_IF(!jump); @@ -2521,8 +2574,24 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compi jump->flags |= IS_CALL; #endif /* SLJIT_PASS_ENTRY_ADDR_TO_CALL */ - FAIL_IF(emit_const(compiler, TMP_CALL_REG, 0)); - src_r = TMP_CALL_REG; + jump->addr = compiler->size; + FAIL_IF(push_inst(compiler, BCCTR | (20 << 21) | (type >= SLJIT_FAST_CALL ? 1 : 0))); + + /* Maximum number of instructions required for generating a constant. */ + compiler->size += JUMP_MAX_SIZE - 1; + return SLJIT_SUCCESS; + } + + if (FAST_IS_REG(src)) { +#if (defined SLJIT_PASS_ENTRY_ADDR_TO_CALL && SLJIT_PASS_ENTRY_ADDR_TO_CALL) + if (type >= SLJIT_CALL && src != TMP_CALL_REG) { + FAIL_IF(push_inst(compiler, OR | S(src) | A(TMP_CALL_REG) | B(src))); + src_r = TMP_CALL_REG; + } else + src_r = src; +#else /* SLJIT_PASS_ENTRY_ADDR_TO_CALL */ + src_r = src; +#endif /* SLJIT_PASS_ENTRY_ADDR_TO_CALL */ } else { ADJUST_LOCAL_OFFSET(src, srcw); FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, TMP_CALL_REG, src, srcw, TMP_CALL_REG)); @@ -2530,8 +2599,6 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compi } FAIL_IF(push_inst(compiler, MTCTR | S(src_r))); - if (jump) - jump->addr = compiler->size; return push_inst(compiler, BCCTR | (20 << 21) | (type >= SLJIT_FAST_CALL ? 1 : 0)); } @@ -2748,13 +2815,13 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *comp type ^= 0x1; } else { if (ADDRESSING_DEPENDS_ON(src1, dst_reg)) { - FAIL_IF(push_inst(compiler, OR | S(dst_reg) | A(TMP_REG2) | B(dst_reg))); + FAIL_IF(push_inst(compiler, OR | S(dst_reg) | A(TMP_REG1) | B(dst_reg))); if ((src1 & REG_MASK) == dst_reg) - src1 = (src1 & ~REG_MASK) | TMP_REG2; + src1 = (src1 & ~REG_MASK) | TMP_REG1; if (OFFS_REG(src1) == dst_reg) - src1 = (src1 & ~OFFS_REG_MASK) | TO_OFFS_REG(TMP_REG2); + src1 = (src1 & ~OFFS_REG_MASK) | TO_OFFS_REG(TMP_REG1); } FAIL_IF(push_inst(compiler, OR | S(src2_reg) | A(dst_reg) | B(src2_reg))); @@ -3061,31 +3128,31 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi return const_; } -SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label* sljit_emit_put_label(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw) +SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_mov_addr(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw) { - struct sljit_put_label *put_label; + struct sljit_jump *jump; sljit_s32 dst_r; CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_put_label(compiler, dst, dstw)); + CHECK_PTR(check_sljit_emit_mov_addr(compiler, dst, dstw)); ADJUST_LOCAL_OFFSET(dst, dstw); - put_label = (struct sljit_put_label*)ensure_abuf(compiler, sizeof(struct sljit_put_label)); - PTR_FAIL_IF(!put_label); - set_put_label(put_label, compiler, 0); + jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump)); + PTR_FAIL_IF(!jump); + set_mov_addr(jump, compiler, 0); dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2; + PTR_FAIL_IF(push_inst(compiler, (sljit_ins)dst_r)); #if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) - PTR_FAIL_IF(emit_const(compiler, dst_r, 0)); + compiler->size++; #else - PTR_FAIL_IF(push_inst(compiler, (sljit_ins)dst_r)); compiler->size += 4; #endif if (dst & SLJIT_MEM) PTR_FAIL_IF(emit_op(compiler, SLJIT_MOV, WORD_DATA, dst, dstw, TMP_REG1, 0, TMP_REG2, 0)); - return put_label; + return jump; } SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset) diff --git a/src/sljit/sljitNativeRISCV_common.c b/src/sljit/sljitNativeRISCV_common.c index 64bd411..d86100a 100644 --- a/src/sljit/sljitNativeRISCV_common.c +++ b/src/sljit/sljitNativeRISCV_common.c @@ -181,24 +181,23 @@ static SLJIT_INLINE sljit_ins* detect_jump_type(struct sljit_jump *jump, sljit_i if (jump->flags & JUMP_ADDR) target_addr = jump->u.target; else { - SLJIT_ASSERT(jump->flags & JUMP_LABEL); + SLJIT_ASSERT(jump->u.label != NULL); target_addr = (sljit_uw)(code + jump->u.label->size) + (sljit_uw)executable_offset; } diff = (sljit_sw)target_addr - (sljit_sw)inst - executable_offset; if (jump->flags & IS_COND) { - inst--; diff += SSIZE_OF(ins); if (diff >= BRANCH_MIN && diff <= BRANCH_MAX) { - jump->flags |= PATCH_B; + inst--; inst[0] = (inst[0] & 0x1fff07f) ^ 0x1000; + jump->flags |= PATCH_B; jump->addr = (sljit_uw)inst; return inst; } - inst++; diff -= SSIZE_OF(ins); } @@ -265,83 +264,109 @@ exit: #if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64) -static SLJIT_INLINE sljit_sw put_label_get_length(struct sljit_put_label *put_label, sljit_uw max_label) +static SLJIT_INLINE sljit_sw mov_addr_get_length(struct sljit_jump *jump, sljit_ins *code_ptr, sljit_ins *code, sljit_sw executable_offset) { - if (max_label <= (sljit_uw)S32_MAX) { - put_label->flags = PATCH_ABS32; + sljit_uw addr; + sljit_sw diff; + SLJIT_UNUSED_ARG(executable_offset); + + SLJIT_ASSERT(jump->flags < ((sljit_uw)6 << JUMP_SIZE_SHIFT)); + if (jump->flags & JUMP_ADDR) + addr = jump->u.target; + else + addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code + jump->u.label->size, executable_offset); + + diff = (sljit_sw)addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset); + + if (diff >= S32_MIN && diff <= S32_MAX) { + SLJIT_ASSERT(jump->flags >= ((sljit_uw)1 << JUMP_SIZE_SHIFT)); + jump->flags |= PATCH_REL32; + return 1; + } + + if (addr <= S32_MAX) { + SLJIT_ASSERT(jump->flags >= ((sljit_uw)1 << JUMP_SIZE_SHIFT)); + jump->flags |= PATCH_ABS32; return 1; } - if (max_label <= S44_MAX) { - put_label->flags = PATCH_ABS44; + if (addr <= S44_MAX) { + SLJIT_ASSERT(jump->flags >= ((sljit_uw)3 << JUMP_SIZE_SHIFT)); + jump->flags |= PATCH_ABS44; return 3; } - if (max_label <= S52_MAX) { - put_label->flags = PATCH_ABS52; + if (addr <= S52_MAX) { + SLJIT_ASSERT(jump->flags >= ((sljit_uw)4 << JUMP_SIZE_SHIFT)); + jump->flags |= PATCH_ABS52; return 4; } - put_label->flags = 0; + SLJIT_ASSERT(jump->flags >= ((sljit_uw)5 << JUMP_SIZE_SHIFT)); return 5; } #endif /* SLJIT_CONFIG_RISCV_64 */ -static SLJIT_INLINE void load_addr_to_reg(void *dst, sljit_u32 reg) +static SLJIT_INLINE void load_addr_to_reg(struct sljit_jump *jump, sljit_sw executable_offset) { - struct sljit_jump *jump = NULL; - struct sljit_put_label *put_label; - sljit_uw flags; - sljit_ins *inst; + sljit_uw flags = jump->flags; + sljit_uw addr = (flags & JUMP_ADDR) ? jump->u.target : jump->u.label->u.addr; + sljit_ins *ins = (sljit_ins*)jump->addr; + sljit_u32 reg = (flags & JUMP_MOV_ADDR) ? *ins : TMP_REG1; #if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64) sljit_sw high; #endif - sljit_uw addr; + SLJIT_UNUSED_ARG(executable_offset); - if (reg != 0) { - jump = (struct sljit_jump*)dst; - flags = jump->flags; - inst = (sljit_ins*)jump->addr; - addr = (flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target; - } else { - put_label = (struct sljit_put_label*)dst; #if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64) - flags = put_label->flags; -#endif - inst = (sljit_ins*)put_label->addr; - addr = put_label->label->addr; - reg = *inst; + if (flags & PATCH_REL32) { + addr -= (sljit_uw)SLJIT_ADD_EXEC_OFFSET(ins, executable_offset); + + SLJIT_ASSERT((sljit_sw)addr >= S32_MIN && (sljit_sw)addr <= S32_MAX); + + if ((addr & 0x800) != 0) + addr += 0x1000; + + ins[0] = AUIPC | RD(reg) | (sljit_ins)((sljit_sw)addr & ~0xfff); + + if (!(flags & JUMP_MOV_ADDR)) { + SLJIT_ASSERT((ins[1] & 0x707f) == JALR); + ins[1] = (ins[1] & 0xfffff) | IMM_I(addr); + } else + ins[1] = ADDI | RD(reg) | RS1(reg) | IMM_I(addr); + return; } +#endif if ((addr & 0x800) != 0) addr += 0x1000; #if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) - inst[0] = LUI | RD(reg) | (sljit_ins)((sljit_sw)addr & ~0xfff); + ins[0] = LUI | RD(reg) | (sljit_ins)((sljit_sw)addr & ~0xfff); #else /* !SLJIT_CONFIG_RISCV_32 */ if (flags & PATCH_ABS32) { SLJIT_ASSERT(addr <= S32_MAX); - inst[0] = LUI | RD(reg) | (sljit_ins)((sljit_sw)addr & ~0xfff); + ins[0] = LUI | RD(reg) | (sljit_ins)((sljit_sw)addr & ~0xfff); } else if (flags & PATCH_ABS44) { high = (sljit_sw)addr >> 12; SLJIT_ASSERT((sljit_uw)high <= 0x7fffffff); if (high > S32_MAX) { SLJIT_ASSERT((high & 0x800) != 0); - inst[0] = LUI | RD(reg) | (sljit_ins)0x80000000u; - inst[1] = XORI | RD(reg) | RS1(reg) | IMM_I(high); + ins[0] = LUI | RD(reg) | (sljit_ins)0x80000000u; + ins[1] = XORI | RD(reg) | RS1(reg) | IMM_I(high); } else { if ((high & 0x800) != 0) high += 0x1000; - inst[0] = LUI | RD(reg) | (sljit_ins)(high & ~0xfff); - inst[1] = ADDI | RD(reg) | RS1(reg) | IMM_I(high); + ins[0] = LUI | RD(reg) | (sljit_ins)(high & ~0xfff); + ins[1] = ADDI | RD(reg) | RS1(reg) | IMM_I(high); } - inst[2] = SLLI | RD(reg) | RS1(reg) | IMM_I(12); - inst += 2; + ins[2] = SLLI | RD(reg) | RS1(reg) | IMM_I(12); + ins += 2; } else { high = (sljit_sw)addr >> 32; @@ -350,30 +375,128 @@ static SLJIT_INLINE void load_addr_to_reg(void *dst, sljit_u32 reg) if (flags & PATCH_ABS52) { SLJIT_ASSERT(addr <= S52_MAX); - inst[0] = LUI | RD(TMP_REG3) | (sljit_ins)(high << 12); + ins[0] = LUI | RD(TMP_REG3) | (sljit_ins)(high << 12); } else { if ((high & 0x800) != 0) high += 0x1000; - inst[0] = LUI | RD(TMP_REG3) | (sljit_ins)(high & ~0xfff); - inst[1] = ADDI | RD(TMP_REG3) | RS1(TMP_REG3) | IMM_I(high); - inst++; + ins[0] = LUI | RD(TMP_REG3) | (sljit_ins)(high & ~0xfff); + ins[1] = ADDI | RD(TMP_REG3) | RS1(TMP_REG3) | IMM_I(high); + ins++; } - inst[1] = LUI | RD(reg) | (sljit_ins)((sljit_sw)addr & ~0xfff); - inst[2] = SLLI | RD(TMP_REG3) | RS1(TMP_REG3) | IMM_I((flags & PATCH_ABS52) ? 20 : 32); - inst[3] = XOR | RD(reg) | RS1(reg) | RS2(TMP_REG3); - inst += 3; + ins[1] = LUI | RD(reg) | (sljit_ins)((sljit_sw)addr & ~0xfff); + ins[2] = SLLI | RD(TMP_REG3) | RS1(TMP_REG3) | IMM_I((flags & PATCH_ABS52) ? 20 : 32); + ins[3] = XOR | RD(reg) | RS1(reg) | RS2(TMP_REG3); + ins += 3; } #endif /* !SLJIT_CONFIG_RISCV_32 */ - if (jump != NULL) { - SLJIT_ASSERT((inst[1] & 0x707f) == JALR); - inst[1] = (inst[1] & 0xfffff) | IMM_I(addr); + if (!(flags & JUMP_MOV_ADDR)) { + SLJIT_ASSERT((ins[1] & 0x707f) == JALR); + ins[1] = (ins[1] & 0xfffff) | IMM_I(addr); } else - inst[1] = ADDI | RD(reg) | RS1(reg) | IMM_I(addr); + ins[1] = ADDI | RD(reg) | RS1(reg) | IMM_I(addr); +} + +static void reduce_code_size(struct sljit_compiler *compiler) +{ + struct sljit_label *label; + struct sljit_jump *jump; + struct sljit_const *const_; + SLJIT_NEXT_DEFINE_TYPES; + sljit_uw total_size; + sljit_uw size_reduce = 0; + sljit_sw diff; + + label = compiler->labels; + jump = compiler->jumps; + const_ = compiler->consts; + SLJIT_NEXT_INIT_TYPES(); + + while (1) { + SLJIT_GET_NEXT_MIN(); + + if (next_min_addr == SLJIT_MAX_ADDRESS) + break; + + if (next_min_addr == next_label_size) { + label->size -= size_reduce; + + label = label->next; + next_label_size = SLJIT_GET_NEXT_SIZE(label); + } + + if (next_min_addr == next_const_addr) { + const_->addr -= size_reduce; + const_ = const_->next; + next_const_addr = SLJIT_GET_NEXT_ADDRESS(const_); + continue; + } + + if (next_min_addr != next_jump_addr) + continue; + + jump->addr -= size_reduce; + if (!(jump->flags & JUMP_MOV_ADDR)) { + total_size = JUMP_MAX_SIZE; + + if (!(jump->flags & SLJIT_REWRITABLE_JUMP)) { + if (jump->flags & JUMP_ADDR) { +#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64) + if (jump->u.target <= S32_MAX) + total_size = 2; + else if (jump->u.target <= S44_MAX) + total_size = 4; + else if (jump->u.target <= S52_MAX) + total_size = 5; +#endif /* SLJIT_CONFIG_RISCV_64 */ + } else { + /* Unit size: instruction. */ + diff = (sljit_sw)jump->u.label->size - (sljit_sw)jump->addr; + + if ((jump->flags & IS_COND) && (diff + 1) <= (BRANCH_MAX / SSIZE_OF(ins)) && (diff + 1) >= (BRANCH_MIN / SSIZE_OF(ins))) + total_size = 0; + else if (diff >= (JUMP_MIN / SSIZE_OF(ins)) && diff <= (JUMP_MAX / SSIZE_OF(ins))) + total_size = 1; +#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64) + else if (diff >= (S32_MIN / SSIZE_OF(ins)) && diff <= (S32_MAX / SSIZE_OF(ins))) + total_size = 2; +#endif /* SLJIT_CONFIG_RISCV_64 */ + } + } + + size_reduce += JUMP_MAX_SIZE - total_size; + jump->flags |= total_size << JUMP_SIZE_SHIFT; +#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64) + } else { + total_size = 5; + + if (!(jump->flags & JUMP_ADDR)) { + /* Real size minus 1. Unit size: instruction. */ + diff = (sljit_sw)jump->u.label->size - (sljit_sw)jump->addr; + + if (diff >= (S32_MIN / SSIZE_OF(ins)) && diff <= (S32_MAX / SSIZE_OF(ins))) + total_size = 1; + } else if (jump->u.target < S32_MAX) + total_size = 1; + else if (jump->u.target < S44_MAX) + total_size = 3; + else if (jump->u.target <= S52_MAX) + total_size = 4; + + size_reduce += 5 - total_size; + jump->flags |= total_size << JUMP_SIZE_SHIFT; +#endif /* !SLJIT_CONFIG_RISCV_64 */ + } + + jump = jump->next; + next_jump_addr = SLJIT_GET_NEXT_ADDRESS(jump); + } + + compiler->size -= size_reduce; } -SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler) +SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler, sljit_s32 options, void *exec_allocator_data) { struct sljit_memory_fragment *buf; sljit_ins *code; @@ -381,77 +504,78 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil sljit_ins *buf_ptr; sljit_ins *buf_end; sljit_uw word_count; - sljit_uw next_addr; + SLJIT_NEXT_DEFINE_TYPES; sljit_sw executable_offset; sljit_uw addr; struct sljit_label *label; struct sljit_jump *jump; struct sljit_const *const_; - struct sljit_put_label *put_label; CHECK_ERROR_PTR(); CHECK_PTR(check_sljit_generate_code(compiler)); - reverse_buf(compiler); - code = (sljit_ins*)SLJIT_MALLOC_EXEC(compiler->size * sizeof(sljit_ins), compiler->exec_allocator_data); + reduce_code_size(compiler); + + code = (sljit_ins*)allocate_executable_memory(compiler->size * sizeof(sljit_ins), options, exec_allocator_data, &executable_offset); PTR_FAIL_WITH_EXEC_IF(code); + + reverse_buf(compiler); buf = compiler->buf; code_ptr = code; word_count = 0; - next_addr = 0; - executable_offset = SLJIT_EXEC_OFFSET(code); - label = compiler->labels; jump = compiler->jumps; const_ = compiler->consts; - put_label = compiler->put_labels; + SLJIT_NEXT_INIT_TYPES(); + SLJIT_GET_NEXT_MIN(); do { buf_ptr = (sljit_ins*)buf->memory; buf_end = buf_ptr + (buf->used_size >> 2); do { *code_ptr = *buf_ptr++; - if (next_addr == word_count) { + if (next_min_addr == word_count) { SLJIT_ASSERT(!label || label->size >= word_count); SLJIT_ASSERT(!jump || jump->addr >= word_count); SLJIT_ASSERT(!const_ || const_->addr >= word_count); - SLJIT_ASSERT(!put_label || put_label->addr >= word_count); /* These structures are ordered by their address. */ - if (label && label->size == word_count) { - label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset); + if (next_min_addr == next_label_size) { + label->u.addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset); label->size = (sljit_uw)(code_ptr - code); label = label->next; + next_label_size = SLJIT_GET_NEXT_SIZE(label); } - if (jump && jump->addr == word_count) { + + if (next_min_addr == next_jump_addr) { + if (!(jump->flags & JUMP_MOV_ADDR)) { + word_count = word_count - 1 + (jump->flags >> JUMP_SIZE_SHIFT); + jump->addr = (sljit_uw)code_ptr; + code_ptr = detect_jump_type(jump, code, executable_offset); + SLJIT_ASSERT((jump->flags & PATCH_B) || ((sljit_uw)code_ptr - jump->addr < (jump->flags >> JUMP_SIZE_SHIFT) * sizeof(sljit_ins))); + } else { #if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) - word_count += 1; -#else - word_count += 5; -#endif - jump->addr = (sljit_uw)code_ptr; - code_ptr = detect_jump_type(jump, code, executable_offset); + word_count += 1; + jump->addr = (sljit_uw)code_ptr; + code_ptr += 1; +#else /* !SLJIT_CONFIG_RISCV_32 */ + word_count += jump->flags >> JUMP_SIZE_SHIFT; + addr = (sljit_uw)code_ptr; + code_ptr += mov_addr_get_length(jump, code_ptr, code, executable_offset); + jump->addr = addr; +#endif /* SLJIT_CONFIG_RISCV_32 */ + } jump = jump->next; - } - if (const_ && const_->addr == word_count) { + next_jump_addr = SLJIT_GET_NEXT_ADDRESS(jump); + } else if (next_min_addr == next_const_addr) { const_->addr = (sljit_uw)code_ptr; const_ = const_->next; + next_const_addr = SLJIT_GET_NEXT_ADDRESS(const_); } - if (put_label && put_label->addr == word_count) { - SLJIT_ASSERT(put_label->label); - put_label->addr = (sljit_uw)code_ptr; -#if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) - code_ptr += 1; - word_count += 1; -#else - code_ptr += put_label_get_length(put_label, (sljit_uw)(SLJIT_ADD_EXEC_OFFSET(code, executable_offset) + put_label->label->size)); - word_count += 5; -#endif - put_label = put_label->next; - } - next_addr = compute_next_addr(label, jump, const_, put_label); + + SLJIT_GET_NEXT_MIN(); } code_ptr++; word_count++; @@ -461,7 +585,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil } while (buf); if (label && label->size == word_count) { - label->addr = (sljit_uw)code_ptr; + label->u.addr = (sljit_uw)code_ptr; label->size = (sljit_uw)(code_ptr - code); label = label->next; } @@ -469,18 +593,17 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil SLJIT_ASSERT(!label); SLJIT_ASSERT(!jump); SLJIT_ASSERT(!const_); - SLJIT_ASSERT(!put_label); SLJIT_ASSERT(code_ptr - code <= (sljit_sw)compiler->size); jump = compiler->jumps; while (jump) { do { - if (!(jump->flags & (PATCH_B | PATCH_J | PATCH_REL32))) { - load_addr_to_reg(jump, TMP_REG1); + if (!(jump->flags & (PATCH_B | PATCH_J)) || (jump->flags & JUMP_MOV_ADDR)) { + load_addr_to_reg(jump, executable_offset); break; } - addr = (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target; + addr = (jump->flags & JUMP_ADDR) ? jump->u.target : jump->u.label->u.addr; buf_ptr = (sljit_ins *)jump->addr; addr -= (sljit_uw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset); @@ -491,31 +614,12 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil break; } -#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64) - if (jump->flags & PATCH_REL32) { - SLJIT_ASSERT((sljit_sw)addr >= S32_MIN && (sljit_sw)addr <= S32_MAX); - - if ((addr & 0x800) != 0) - addr += 0x1000; - - buf_ptr[0] = AUIPC | RD(TMP_REG1) | (sljit_ins)((sljit_sw)addr & ~0xfff); - SLJIT_ASSERT((buf_ptr[1] & 0x707f) == JALR); - buf_ptr[1] |= IMM_I(addr); - break; - } -#endif - SLJIT_ASSERT((sljit_sw)addr >= JUMP_MIN && (sljit_sw)addr <= JUMP_MAX); addr = (addr & 0xff000) | ((addr & 0x800) << 9) | ((addr & 0x7fe) << 20) | ((addr & 0x100000) << 11); buf_ptr[0] = JAL | RD((jump->flags & IS_CALL) ? RETURN_ADDR_REG : TMP_ZERO) | (sljit_ins)addr; } while (0); - jump = jump->next; - } - put_label = compiler->put_labels; - while (put_label) { - load_addr_to_reg(put_label, 0); - put_label = put_label->next; + jump = jump->next; } compiler->error = SLJIT_ERR_COMPILED; @@ -599,6 +703,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_cmp_info(sljit_s32 type) #define SLOW_SRC1 0x08000 #define SLOW_SRC2 0x10000 #define SLOW_DEST 0x20000 +#define MEM_USE_TMP2 0x40000 #if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) #define STACK_STORE SW @@ -883,7 +988,6 @@ static sljit_s32 push_mem_inst(struct sljit_compiler *compiler, sljit_s32 flags, /* Can perform an operation using at most 1 instruction. */ static sljit_s32 getput_arg_fast(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg, sljit_sw argw) { - SLJIT_ASSERT(arg & SLJIT_MEM); if (!(arg & OFFS_REG_MASK) && argw <= SIMM_MAX && argw >= SIMM_MIN) { @@ -928,7 +1032,7 @@ static sljit_s32 can_cache(sljit_s32 arg, sljit_sw argw, sljit_s32 next_arg, slj static sljit_s32 getput_arg(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg, sljit_sw argw, sljit_s32 next_arg, sljit_sw next_argw) { sljit_s32 base = arg & REG_MASK; - sljit_s32 tmp_r = TMP_REG1; + sljit_s32 tmp_r = (flags & MEM_USE_TMP2) ? TMP_REG2 : TMP_REG1; sljit_sw offset, argw_hi; SLJIT_ASSERT(arg & SLJIT_MEM); @@ -937,11 +1041,6 @@ static sljit_s32 getput_arg(struct sljit_compiler *compiler, sljit_s32 flags, sl next_argw = 0; } - /* Since tmp can be the same as base or offset registers, - * these might be unavailable after modifying tmp. */ - if ((flags & MEM_MASK) <= GPR_REG && (flags & LOAD_DATA) && reg == TMP_REG2) - tmp_r = reg; - if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) { argw &= 0x3; @@ -1187,7 +1286,7 @@ static sljit_s32 emit_rev16(struct sljit_compiler *compiler, sljit_s32 op, sljit static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 flags, sljit_s32 dst, sljit_s32 src1, sljit_sw src2) { - sljit_s32 is_overflow, is_carry, carry_src_r, is_handled; + sljit_s32 is_overflow, is_carry, carry_src_r, is_handled, reg; sljit_ins op_imm, op_reg; #if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64) sljit_ins word = (sljit_ins)(op & SLJIT_32) >> 5; @@ -1197,20 +1296,20 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl switch (GET_OPCODE(op)) { case SLJIT_MOV: - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM)); + SLJIT_ASSERT(src1 == TMP_ZERO && !(flags & SRC2_IMM)); if (dst != src2) return push_inst(compiler, ADDI | RD(dst) | RS1(src2) | IMM_I(0)); return SLJIT_SUCCESS; case SLJIT_MOV_U8: - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM)); + SLJIT_ASSERT(src1 == TMP_ZERO && !(flags & SRC2_IMM)); if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) return push_inst(compiler, ANDI | RD(dst) | RS1(src2) | IMM_I(0xff)); SLJIT_ASSERT(dst == src2); return SLJIT_SUCCESS; case SLJIT_MOV_S8: - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM)); + SLJIT_ASSERT(src1 == TMP_ZERO && !(flags & SRC2_IMM)); if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) { FAIL_IF(push_inst(compiler, SLLI | WORD | RD(dst) | RS1(src2) | IMM_EXTEND(24))); return push_inst(compiler, SRAI | WORD | RD(dst) | RS1(dst) | IMM_EXTEND(24)); @@ -1219,7 +1318,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl return SLJIT_SUCCESS; case SLJIT_MOV_U16: - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM)); + SLJIT_ASSERT(src1 == TMP_ZERO && !(flags & SRC2_IMM)); if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) { FAIL_IF(push_inst(compiler, SLLI | WORD | RD(dst) | RS1(src2) | IMM_EXTEND(16))); return push_inst(compiler, SRLI | WORD | RD(dst) | RS1(dst) | IMM_EXTEND(16)); @@ -1228,7 +1327,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl return SLJIT_SUCCESS; case SLJIT_MOV_S16: - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM)); + SLJIT_ASSERT(src1 == TMP_ZERO && !(flags & SRC2_IMM)); if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) { FAIL_IF(push_inst(compiler, SLLI | WORD | RD(dst) | RS1(src2) | IMM_EXTEND(16))); return push_inst(compiler, SRAI | WORD | RD(dst) | RS1(dst) | IMM_EXTEND(16)); @@ -1238,7 +1337,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl #if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64) case SLJIT_MOV_U32: - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM)); + SLJIT_ASSERT(src1 == TMP_ZERO && !(flags & SRC2_IMM)); if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) { FAIL_IF(push_inst(compiler, SLLI | RD(dst) | RS1(src2) | IMM_I(32))); return push_inst(compiler, SRLI | RD(dst) | RS1(dst) | IMM_I(32)); @@ -1247,7 +1346,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl return SLJIT_SUCCESS; case SLJIT_MOV_S32: - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM)); + SLJIT_ASSERT(src1 == TMP_ZERO && !(flags & SRC2_IMM)); if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) return push_inst(compiler, ADDI | 0x8 | RD(dst) | RS1(src2) | IMM_I(0)); SLJIT_ASSERT(dst == src2); @@ -1256,7 +1355,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl case SLJIT_CLZ: case SLJIT_CTZ: - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM)); + SLJIT_ASSERT(src1 == TMP_ZERO && !(flags & SRC2_IMM)); return emit_clz_ctz(compiler, op, dst, src2); case SLJIT_REV: @@ -1264,17 +1363,17 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl #if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) case SLJIT_REV_U32: #endif /* SLJIT_CONFIG_RISCV_32 */ - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM)); + SLJIT_ASSERT(src1 == TMP_ZERO && !(flags & SRC2_IMM)); return emit_rev(compiler, op, dst, src2); case SLJIT_REV_U16: case SLJIT_REV_S16: - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM)); + SLJIT_ASSERT(src1 == TMP_ZERO && !(flags & SRC2_IMM)); return emit_rev16(compiler, op, dst, src2); #if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64) case SLJIT_REV_U32: - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM) && dst != TMP_REG1); + SLJIT_ASSERT(src1 == TMP_ZERO && !(flags & SRC2_IMM) && dst != TMP_REG1); FAIL_IF(emit_rev(compiler, op, dst, src2)); if (dst == TMP_REG2) return SLJIT_SUCCESS; @@ -1402,8 +1501,9 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl is_handled = 1; if (flags & SRC2_IMM) { - FAIL_IF(push_inst(compiler, ADDI | RD(TMP_REG2) | RS1(TMP_ZERO) | IMM_I(src2))); - src2 = TMP_REG2; + reg = (src1 == TMP_REG1) ? TMP_REG2 : TMP_REG1; + FAIL_IF(push_inst(compiler, ADDI | RD(reg) | RS1(TMP_ZERO) | IMM_I(src2))); + src2 = reg; flags &= ~SRC2_IMM; } @@ -1631,7 +1731,7 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3 sljit_s32 dst_r = TMP_REG2; sljit_s32 src1_r; sljit_sw src2_r = 0; - sljit_s32 sugg_src2_r = TMP_REG2; + sljit_s32 src2_tmp_reg = (GET_OPCODE(op) >= SLJIT_OP2_BASE && FAST_IS_REG(src1)) ? TMP_REG1 : TMP_REG2; if (!(flags & ALT_KEEP_CACHE)) { compiler->cache_arg = 0; @@ -1647,7 +1747,7 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3 dst_r = dst; flags |= REG_DEST; if (flags & MOVE_OP) - sugg_src2_r = dst_r; + src2_tmp_reg = dst_r; } else if ((dst & SLJIT_MEM) && !getput_arg_fast(compiler, flags | ARG_TEST, TMP_REG1, dst, dstw)) flags |= SLOW_DEST; @@ -1673,16 +1773,14 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3 if (FAST_IS_REG(src1)) { src1_r = src1; flags |= REG1_SOURCE; - } - else if (src1 == SLJIT_IMM) { + } else if (src1 == SLJIT_IMM) { if (src1w) { FAIL_IF(load_immediate(compiler, TMP_REG1, src1w, TMP_REG3)); src1_r = TMP_REG1; } else src1_r = TMP_ZERO; - } - else { + } else { if (getput_arg_fast(compiler, flags | LOAD_DATA, TMP_REG1, src1, src1w)) FAIL_IF(compiler->error); else @@ -1696,14 +1794,12 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3 flags |= REG2_SOURCE; if ((flags & (REG_DEST | MOVE_OP)) == MOVE_OP) dst_r = (sljit_s32)src2_r; - } - else if (src2 == SLJIT_IMM) { + } else if (src2 == SLJIT_IMM) { if (!(flags & SRC2_IMM)) { if (src2w) { - FAIL_IF(load_immediate(compiler, sugg_src2_r, src2w, TMP_REG3)); - src2_r = sugg_src2_r; - } - else { + FAIL_IF(load_immediate(compiler, src2_tmp_reg, src2w, TMP_REG3)); + src2_r = src2_tmp_reg; + } else { src2_r = TMP_ZERO; if (flags & MOVE_OP) { if (dst & SLJIT_MEM) @@ -1713,30 +1809,28 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3 } } } - } - else { - if (getput_arg_fast(compiler, flags | LOAD_DATA, sugg_src2_r, src2, src2w)) + } else { + if (getput_arg_fast(compiler, flags | LOAD_DATA, src2_tmp_reg, src2, src2w)) FAIL_IF(compiler->error); else flags |= SLOW_SRC2; - src2_r = sugg_src2_r; + src2_r = src2_tmp_reg; } if ((flags & (SLOW_SRC1 | SLOW_SRC2)) == (SLOW_SRC1 | SLOW_SRC2)) { SLJIT_ASSERT(src2_r == TMP_REG2); - if (!can_cache(src1, src1w, src2, src2w) && can_cache(src1, src1w, dst, dstw)) { + if ((flags & SLOW_DEST) && !can_cache(src2, src2w, src1, src1w) && can_cache(src2, src2w, dst, dstw)) { + FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, TMP_REG1, src1, src1w, src2, src2w)); + FAIL_IF(getput_arg(compiler, flags | LOAD_DATA | MEM_USE_TMP2, TMP_REG2, src2, src2w, dst, dstw)); + } else { FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, TMP_REG2, src2, src2w, src1, src1w)); FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, TMP_REG1, src1, src1w, dst, dstw)); } - else { - FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, TMP_REG1, src1, src1w, src2, src2w)); - FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, TMP_REG2, src2, src2w, dst, dstw)); - } } else if (flags & SLOW_SRC1) FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, TMP_REG1, src1, src1w, dst, dstw)); else if (flags & SLOW_SRC2) - FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, sugg_src2_r, src2, src2w, dst, dstw)); + FAIL_IF(getput_arg(compiler, flags | LOAD_DATA | ((src1_r == TMP_REG1) ? MEM_USE_TMP2 : 0), src2_tmp_reg, src2, src2w, dst, dstw)); FAIL_IF(emit_single_op(compiler, op, flags, dst_r, src1_r, src2_r)); @@ -1819,42 +1913,42 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile case SLJIT_MOV32: #endif case SLJIT_MOV_P: - return emit_op(compiler, SLJIT_MOV, WORD_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, srcw); + return emit_op(compiler, SLJIT_MOV, WORD_DATA | MOVE_OP, dst, dstw, TMP_ZERO, 0, src, srcw); #if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64) case SLJIT_MOV_U32: - return emit_op(compiler, SLJIT_MOV_U32, INT_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src == SLJIT_IMM) ? (sljit_u32)srcw : srcw); + return emit_op(compiler, SLJIT_MOV_U32, INT_DATA | MOVE_OP, dst, dstw, TMP_ZERO, 0, src, (src == SLJIT_IMM) ? (sljit_u32)srcw : srcw); case SLJIT_MOV_S32: /* Logical operators have no W variant, so sign extended input is necessary for them. */ case SLJIT_MOV32: - return emit_op(compiler, SLJIT_MOV_S32, INT_DATA | SIGNED_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src == SLJIT_IMM) ? (sljit_s32)srcw : srcw); + return emit_op(compiler, SLJIT_MOV_S32, INT_DATA | SIGNED_DATA | MOVE_OP, dst, dstw, TMP_ZERO, 0, src, (src == SLJIT_IMM) ? (sljit_s32)srcw : srcw); #endif case SLJIT_MOV_U8: - return emit_op(compiler, op, BYTE_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src == SLJIT_IMM) ? (sljit_u8)srcw : srcw); + return emit_op(compiler, op, BYTE_DATA | MOVE_OP, dst, dstw, TMP_ZERO, 0, src, (src == SLJIT_IMM) ? (sljit_u8)srcw : srcw); case SLJIT_MOV_S8: - return emit_op(compiler, op, BYTE_DATA | SIGNED_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src == SLJIT_IMM) ? (sljit_s8)srcw : srcw); + return emit_op(compiler, op, BYTE_DATA | SIGNED_DATA | MOVE_OP, dst, dstw, TMP_ZERO, 0, src, (src == SLJIT_IMM) ? (sljit_s8)srcw : srcw); case SLJIT_MOV_U16: - return emit_op(compiler, op, HALF_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src == SLJIT_IMM) ? (sljit_u16)srcw : srcw); + return emit_op(compiler, op, HALF_DATA | MOVE_OP, dst, dstw, TMP_ZERO, 0, src, (src == SLJIT_IMM) ? (sljit_u16)srcw : srcw); case SLJIT_MOV_S16: - return emit_op(compiler, op, HALF_DATA | SIGNED_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src == SLJIT_IMM) ? (sljit_s16)srcw : srcw); + return emit_op(compiler, op, HALF_DATA | SIGNED_DATA | MOVE_OP, dst, dstw, TMP_ZERO, 0, src, (src == SLJIT_IMM) ? (sljit_s16)srcw : srcw); case SLJIT_CLZ: case SLJIT_CTZ: case SLJIT_REV: - return emit_op(compiler, op, flags, dst, dstw, TMP_REG1, 0, src, srcw); + return emit_op(compiler, op, flags, dst, dstw, TMP_ZERO, 0, src, srcw); case SLJIT_REV_U16: case SLJIT_REV_S16: - return emit_op(compiler, op, HALF_DATA, dst, dstw, TMP_REG1, 0, src, srcw); + return emit_op(compiler, op, HALF_DATA, dst, dstw, TMP_ZERO, 0, src, srcw); case SLJIT_REV_U32: case SLJIT_REV_S32: - return emit_op(compiler, op | SLJIT_32, INT_DATA, dst, dstw, TMP_REG1, 0, src, srcw); + return emit_op(compiler, op | SLJIT_32, INT_DATA, dst, dstw, TMP_ZERO, 0, src, srcw); } SLJIT_UNREACHABLE(); @@ -1941,6 +2035,30 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compil return sljit_emit_op2(compiler, op, 0, 0, src1, src1w, src2, src2w); } +SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2r(struct sljit_compiler *compiler, sljit_s32 op, + sljit_s32 dst_reg, + sljit_s32 src1, sljit_sw src1w, + sljit_s32 src2, sljit_sw src2w) +{ +#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64) + sljit_ins word = (sljit_ins)(op & SLJIT_32) >> 5; +#endif /* SLJIT_CONFIG_RISCV_64 */ + + CHECK_ERROR(); + CHECK(check_sljit_emit_op2r(compiler, op, dst_reg, src1, src1w, src2, src2w)); + + SLJIT_ASSERT(WORD == 0 || WORD == 0x8); + + switch (GET_OPCODE(op)) { + case SLJIT_MULADD: + SLJIT_SKIP_CHECKS(compiler); + FAIL_IF(sljit_emit_op2(compiler, SLJIT_MUL | (op & SLJIT_32), TMP_REG2, 0, src1, src1w, src2, src2w)); + return push_inst(compiler, ADD | WORD | RD(dst_reg) | RS1(dst_reg) | RS2(TMP_REG2)); + } + + return SLJIT_SUCCESS; +} + SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 dst_reg, sljit_s32 src1_reg, @@ -2292,7 +2410,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compil switch (GET_OPCODE(op)) { case SLJIT_MOV_F64: if (src != dst_r) { - if (dst_r != TMP_FREG1) + if (!(dst & SLJIT_MEM)) FAIL_IF(push_inst(compiler, FSGNJ_S | FMT(op) | FRD(dst_r) | FRS1(src) | FRS2(src))); else dst_r = src; @@ -2351,11 +2469,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compil } if ((flags & (SLOW_SRC1 | SLOW_SRC2)) == (SLOW_SRC1 | SLOW_SRC2)) { - if (!can_cache(src1, src1w, src2, src2w) && can_cache(src1, src1w, dst, dstw)) { + if ((dst & SLJIT_MEM) && !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 { + } 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)); } @@ -2391,7 +2508,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compil return push_inst(compiler, FSGNJ_S | FMT(op) | FRD(dst_r) | FRS1(src1) | FRS2(src2)); } - if (dst_r == TMP_FREG2) + if (dst_r != dst) FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op), TMP_FREG2, dst, dstw, 0, 0)); return SLJIT_SUCCESS; @@ -2522,11 +2639,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile PTR_FAIL_IF(push_inst(compiler, inst)); /* Maximum number of instructions required for generating a constant. */ -#if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) - compiler->size += 1; -#else - compiler->size += 5; -#endif + compiler->size += JUMP_MAX_SIZE - 1; return jump; } @@ -2553,6 +2666,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler struct sljit_jump *jump; sljit_s32 flags; sljit_ins inst; + sljit_s32 src2_tmp_reg = FAST_IS_REG(src1) ? TMP_REG1 : TMP_REG2; CHECK_ERROR_PTR(); CHECK_PTR(check_sljit_emit_cmp(compiler, type, src1, src1w, src2, src2w)); @@ -2573,8 +2687,8 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler } if (src2 & SLJIT_MEM) { - PTR_FAIL_IF(emit_op_mem2(compiler, flags, TMP_REG2, src2, src2w, 0, 0)); - src2 = TMP_REG2; + PTR_FAIL_IF(emit_op_mem2(compiler, flags, src2_tmp_reg, src2, src2w, 0, 0)); + src2 = src2_tmp_reg; } if (src1 == SLJIT_IMM) { @@ -2588,8 +2702,8 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler if (src2 == SLJIT_IMM) { if (src2w != 0) { - PTR_FAIL_IF(load_immediate(compiler, TMP_REG2, src2w, TMP_REG3)); - src2 = TMP_REG2; + PTR_FAIL_IF(load_immediate(compiler, src2_tmp_reg, src2w, TMP_REG3)); + src2 = src2_tmp_reg; } else src2 = TMP_ZERO; @@ -2639,11 +2753,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler PTR_FAIL_IF(push_inst(compiler, JALR | RD(TMP_ZERO) | RS1(TMP_REG1) | IMM_I(0))); /* Maximum number of instructions required for generating a constant. */ -#if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) - compiler->size += 1; -#else - compiler->size += 5; -#endif + compiler->size += JUMP_MAX_SIZE - 1; return jump; } @@ -2675,11 +2785,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compi FAIL_IF(push_inst(compiler, JALR | RD((type >= SLJIT_FAST_CALL) ? RETURN_ADDR_REG : TMP_ZERO) | RS1(TMP_REG1) | IMM_I(0))); /* Maximum number of instructions required for generating a constant. */ -#if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) - compiler->size += 1; -#else - compiler->size += 5; -#endif + compiler->size += JUMP_MAX_SIZE - 1; return SLJIT_SUCCESS; } @@ -2826,13 +2932,13 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *comp type ^= 0x1; } else { if (ADDRESSING_DEPENDS_ON(src1, dst_reg)) { - FAIL_IF(push_inst(compiler, ADDI | RD(TMP_REG2) | RS1(dst_reg) | IMM_I(0))); + FAIL_IF(push_inst(compiler, ADDI | RD(TMP_REG1) | RS1(dst_reg) | IMM_I(0))); if ((src1 & REG_MASK) == dst_reg) - src1 = (src1 & ~REG_MASK) | TMP_REG2; + src1 = (src1 & ~REG_MASK) | TMP_REG1; if (OFFS_REG(src1) == dst_reg) - src1 = (src1 & ~OFFS_REG_MASK) | TO_OFFS_REG(TMP_REG2); + src1 = (src1 & ~OFFS_REG_MASK) | TO_OFFS_REG(TMP_REG1); } FAIL_IF(push_inst(compiler, ADDI | WORD | RD(dst_reg) | RS1(src2_reg) | IMM_I(0))); @@ -2856,7 +2962,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *comp } else FAIL_IF(push_inst(compiler, ADDI | WORD | RD(dst_reg) | RS1(src1) | IMM_I(0))); - *ptr = get_jump_instruction(type & ~SLJIT_32) | (sljit_ins)((compiler->size - size) << 9); + size = compiler->size - size; + *ptr = get_jump_instruction(type & ~SLJIT_32) | (sljit_ins)((size & 0x7) << 9) | (sljit_ins)((size >> 3) << 25); return SLJIT_SUCCESS; } @@ -2895,7 +3002,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fselect(struct sljit_compiler *com else FAIL_IF(push_inst(compiler, FSGNJ_S | FMT(type) | FRD(dst_freg) | FRS1(src1) | FRS2(src1))); - *ptr = get_jump_instruction(type & ~SLJIT_32) | (sljit_ins)((compiler->size - size) << 9); + size = compiler->size - size; + *ptr = get_jump_instruction(type & ~SLJIT_32) | (sljit_ins)((size & 0x7) << 9) | (sljit_ins)((size >> 3) << 25); return SLJIT_SUCCESS; } @@ -2980,31 +3088,31 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi return const_; } -SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label* sljit_emit_put_label(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw) +SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_mov_addr(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw) { - struct sljit_put_label *put_label; + struct sljit_jump *jump; sljit_s32 dst_r; CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_put_label(compiler, dst, dstw)); + CHECK_PTR(check_sljit_emit_mov_addr(compiler, dst, dstw)); ADJUST_LOCAL_OFFSET(dst, dstw); - put_label = (struct sljit_put_label*)ensure_abuf(compiler, sizeof(struct sljit_put_label)); - PTR_FAIL_IF(!put_label); - set_put_label(put_label, compiler, 0); + jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump)); + PTR_FAIL_IF(!jump); + set_mov_addr(jump, compiler, 0); dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2; PTR_FAIL_IF(push_inst(compiler, (sljit_ins)dst_r)); #if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) compiler->size += 1; -#else +#else /* !SLJIT_CONFIG_RISCV_32 */ compiler->size += 5; -#endif +#endif /* SLJIT_CONFIG_RISCV_32 */ if (dst & SLJIT_MEM) PTR_FAIL_IF(emit_op_mem(compiler, WORD_DATA, TMP_REG2, dst, dstw)); - return put_label; + return jump; } SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset) diff --git a/src/sljit/sljitNativeS390X.c b/src/sljit/sljitNativeS390X.c index 67516f9..99e8463 100644 --- a/src/sljit/sljitNativeS390X.c +++ b/src/sljit/sljitNativeS390X.c @@ -38,12 +38,9 @@ SLJIT_API_FUNC_ATTRIBUTE const char* sljit_get_platform_name(void) return "s390x" SLJIT_CPUINFO; } -/* Instructions. */ +/* Instructions are stored as 64 bit values regardless their size. */ typedef sljit_uw sljit_ins; -/* Instruction tags (most significant halfword). */ -static const sljit_ins sljit_ins_const = (sljit_ins)1 << 48; - #define TMP_REG1 (SLJIT_NUMBER_OF_REGISTERS + 2) #define TMP_REG2 (SLJIT_NUMBER_OF_REGISTERS + 3) @@ -140,50 +137,21 @@ static SLJIT_INLINE sljit_gpr gpr(sljit_s32 r) return reg_map[r]; } -/* Size of instruction in bytes. Tags must already be cleared. */ -static SLJIT_INLINE sljit_uw sizeof_ins(sljit_ins ins) -{ - /* keep faulting instructions */ - if (ins == 0) - return 2; - - if ((ins & 0x00000000ffffL) == ins) - return 2; - if ((ins & 0x0000ffffffffL) == ins) - return 4; - if ((ins & 0xffffffffffffL) == ins) - return 6; - - SLJIT_UNREACHABLE(); - return (sljit_uw)-1; -} - static sljit_s32 push_inst(struct sljit_compiler *compiler, sljit_ins ins) { sljit_ins *ibuf = (sljit_ins *)ensure_buf(compiler, sizeof(sljit_ins)); FAIL_IF(!ibuf); *ibuf = ins; + + SLJIT_ASSERT(ins <= 0xffffffffffffL); + compiler->size++; - return SLJIT_SUCCESS; -} + if (ins & 0xffff00000000L) + compiler->size++; -static sljit_s32 encode_inst(void **ptr, sljit_ins ins) -{ - sljit_u16 *ibuf = (sljit_u16 *)*ptr; - sljit_uw size = sizeof_ins(ins); + if (ins & 0xffffffff0000L) + compiler->size++; - SLJIT_ASSERT((size & 6) == size); - switch (size) { - case 6: - *ibuf++ = (sljit_u16)(ins >> 32); - /* fallthrough */ - case 4: - *ibuf++ = (sljit_u16)(ins >> 16); - /* fallthrough */ - case 2: - *ibuf++ = (sljit_u16)(ins); - } - *ptr = (void*)ibuf; return SLJIT_SUCCESS; } @@ -1424,97 +1392,60 @@ static sljit_s32 emit_non_commutative(struct sljit_compiler *compiler, const str return emit_rrf(compiler, ins, dst, src1, src1w, src2, src2w); } -SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler) +SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler, sljit_s32 options, void *exec_allocator_data) { struct sljit_label *label; struct sljit_jump *jump; - struct sljit_s390x_const *const_; - struct sljit_put_label *put_label; + struct sljit_const *const_; sljit_sw executable_offset; - sljit_uw ins_size = 0; /* instructions */ + sljit_uw ins_size = compiler->size << 1; sljit_uw pool_size = 0; /* literal pool */ sljit_uw pad_size; - sljit_uw i, j = 0; + sljit_uw half_count; + SLJIT_NEXT_DEFINE_TYPES; struct sljit_memory_fragment *buf; - void *code, *code_ptr; + sljit_ins *buf_ptr; + sljit_ins *buf_end; + sljit_u16 *code; + sljit_u16 *code_ptr; sljit_uw *pool, *pool_ptr; - sljit_sw source, offset; /* TODO(carenas): only need 32 bit */ + sljit_ins ins; + sljit_sw source, offset; CHECK_ERROR_PTR(); CHECK_PTR(check_sljit_generate_code(compiler)); reverse_buf(compiler); - /* branch handling */ - label = compiler->labels; jump = compiler->jumps; - put_label = compiler->put_labels; - - /* TODO(carenas): compiler->executable_size could be calculated - * before to avoid the following loop (except for - * pool_size) - */ - /* calculate the size of the code */ - for (buf = compiler->buf; buf != NULL; buf = buf->next) { - sljit_uw len = buf->used_size / sizeof(sljit_ins); - sljit_ins *ibuf = (sljit_ins *)buf->memory; - for (i = 0; i < len; ++i, ++j) { - sljit_ins ins = ibuf[i]; - - /* TODO(carenas): instruction tag vs size/addr == j - * using instruction tags for const is creative - * but unlike all other architectures, and is not - * done consistently for all other objects. - * This might need reviewing later. - */ - if (ins & sljit_ins_const) { - pool_size += sizeof(*pool); - ins &= ~sljit_ins_const; - } - if (label && label->size == j) { - label->size = ins_size; - label = label->next; - } - if (jump && jump->addr == j) { - if ((jump->flags & SLJIT_REWRITABLE_JUMP) || (jump->flags & JUMP_ADDR)) { - /* encoded: */ - /* brasl %r14, (or brcl , ) */ - /* replace with: */ - /* lgrl %r1, */ - /* bras %r14, %r1 (or bcr , %r1) */ - pool_size += sizeof(*pool); - ins_size += 2; - } - jump = jump->next; - } - if (put_label && put_label->addr == j) { - pool_size += sizeof(*pool); - put_label = put_label->next; - } - ins_size += sizeof_ins(ins); + while (jump != NULL) { + if (jump->flags & (SLJIT_REWRITABLE_JUMP | JUMP_ADDR | JUMP_MOV_ADDR)) { + /* encoded: */ + /* brasl %r14, (or brcl , ) */ + /* replace with: */ + /* lgrl %r1, */ + /* bras %r14, %r1 (or bcr , %r1) */ + pool_size += sizeof(*pool); + if (!(jump->flags & JUMP_MOV_ADDR)) + ins_size += 2; } + jump = jump->next; } - /* emit trailing label */ - if (label && label->size == j) { - label->size = ins_size; - label = label->next; + const_ = compiler->consts; + while (const_) { + pool_size += sizeof(*pool); + const_ = const_->next; } - SLJIT_ASSERT(!label); - SLJIT_ASSERT(!jump); - SLJIT_ASSERT(!put_label); - /* pad code size to 8 bytes so is accessible with half word offsets */ /* the literal pool needs to be doubleword aligned */ pad_size = ((ins_size + 7UL) & ~7UL) - ins_size; SLJIT_ASSERT(pad_size < 8UL); /* allocate target buffer */ - code = SLJIT_MALLOC_EXEC(ins_size + pad_size + pool_size, - compiler->exec_allocator_data); + code = (sljit_u16*)allocate_executable_memory(ins_size + pad_size + pool_size, options, exec_allocator_data, &executable_offset); PTR_FAIL_WITH_EXEC_IF(code); code_ptr = code; - executable_offset = SLJIT_EXEC_OFFSET(code); /* TODO(carenas): pool is optional, and the ABI recommends it to * be created before the function code, instead of @@ -1523,130 +1454,166 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil */ pool = (sljit_uw *)((sljit_uw)code + ins_size + pad_size); pool_ptr = pool; - const_ = (struct sljit_s390x_const *)compiler->consts; + buf = compiler->buf; + half_count = 0; - /* update label addresses */ label = compiler->labels; - while (label) { - label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET( - (sljit_uw)code_ptr + label->size, executable_offset); - label = label->next; - } - - /* reset jumps */ jump = compiler->jumps; - put_label = compiler->put_labels; + const_ = compiler->consts; + SLJIT_NEXT_INIT_TYPES(); + SLJIT_GET_NEXT_MIN(); - /* emit the code */ - j = 0; - for (buf = compiler->buf; buf != NULL; buf = buf->next) { - sljit_uw len = buf->used_size / sizeof(sljit_ins); - sljit_ins *ibuf = (sljit_ins *)buf->memory; - for (i = 0; i < len; ++i, ++j) { - sljit_ins ins = ibuf[i]; - if (ins & sljit_ins_const) { - /* clear the const tag */ - ins &= ~sljit_ins_const; + do { + buf_ptr = (sljit_ins*)buf->memory; + buf_end = buf_ptr + (buf->used_size >> 3); + do { + ins = *buf_ptr++; + + if (next_min_addr == half_count) { + SLJIT_ASSERT(!label || label->size >= half_count); + SLJIT_ASSERT(!jump || jump->addr >= half_count); + SLJIT_ASSERT(!const_ || const_->addr >= half_count); + + if (next_min_addr == next_label_size) { + label->u.addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset); + label = label->next; + next_label_size = SLJIT_GET_NEXT_SIZE(label); + } - /* update instruction with relative address of constant */ - source = (sljit_sw)code_ptr; - offset = (sljit_sw)pool_ptr - source; + if (next_min_addr == next_jump_addr) { + if (SLJIT_UNLIKELY(jump->flags & JUMP_MOV_ADDR)) { + source = (sljit_sw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset); + + jump->addr = (sljit_uw)pool_ptr; + + /* store target into pool */ + offset = (sljit_sw)SLJIT_ADD_EXEC_OFFSET(pool_ptr, executable_offset) - source; + pool_ptr++; + + SLJIT_ASSERT(!(offset & 1)); + offset >>= 1; + SLJIT_ASSERT(is_s32(offset)); + ins |= (sljit_ins)offset & 0xffffffff; + } else if (jump->flags & (SLJIT_REWRITABLE_JUMP | JUMP_ADDR)) { + sljit_ins arg; + + jump->addr = (sljit_uw)pool_ptr; + + /* load address into tmp1 */ + source = (sljit_sw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset); + offset = (sljit_sw)SLJIT_ADD_EXEC_OFFSET(pool_ptr, executable_offset) - source; + + SLJIT_ASSERT(!(offset & 1)); + offset >>= 1; + SLJIT_ASSERT(is_s32(offset)); + + code_ptr[0] = (sljit_u16)(0xc408 | R4A(tmp1) /* lgrl */); + code_ptr[1] = (sljit_u16)(offset >> 16); + code_ptr[2] = (sljit_u16)offset; + code_ptr += 3; + pool_ptr++; + + /* branch to tmp1 */ + arg = (ins >> 36) & 0xf; + if (((ins >> 32) & 0xf) == 4) { + /* brcl -> bcr */ + ins = bcr(arg, tmp1); + } else { + SLJIT_ASSERT(((ins >> 32) & 0xf) == 5); + /* brasl -> basr */ + ins = basr(arg, tmp1); + } + + /* Adjust half_count. */ + half_count += 2; + } else + jump->addr = (sljit_uw)code_ptr; + + jump = jump->next; + next_jump_addr = SLJIT_GET_NEXT_ADDRESS(jump); + } else if (next_min_addr == next_const_addr) { + /* update instruction with relative address of constant */ + source = (sljit_sw)code_ptr; + offset = (sljit_sw)pool_ptr - source; + + SLJIT_ASSERT(!(offset & 0x1)); + offset >>= 1; /* halfword (not byte) offset */ + SLJIT_ASSERT(is_s32(offset)); - SLJIT_ASSERT(!(offset & 1)); - offset >>= 1; /* halfword (not byte) offset */ - SLJIT_ASSERT(is_s32(offset)); + ins |= (sljit_ins)offset & 0xffffffff; - ins |= (sljit_ins)offset & 0xffffffff; + /* update address */ + const_->addr = (sljit_uw)pool_ptr; - /* update address */ - const_->const_.addr = (sljit_uw)pool_ptr; + /* store initial value into pool and update pool address */ + *(pool_ptr++) = (sljit_uw)(((struct sljit_s390x_const*)const_)->init_value); - /* store initial value into pool and update pool address */ - *(pool_ptr++) = (sljit_uw)const_->init_value; + /* move to next constant */ + const_ = const_->next; + next_const_addr = SLJIT_GET_NEXT_ADDRESS(const_); + } - /* move to next constant */ - const_ = (struct sljit_s390x_const *)const_->const_.next; + SLJIT_GET_NEXT_MIN(); } - if (jump && jump->addr == j) { - sljit_sw target = (sljit_sw)((jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target); - if ((jump->flags & SLJIT_REWRITABLE_JUMP) || (jump->flags & JUMP_ADDR)) { - sljit_ins op, arg; - jump->addr = (sljit_uw)pool_ptr; + if (ins & 0xffff00000000L) { + *code_ptr++ = (sljit_u16)(ins >> 32); + half_count++; + } - /* load address into tmp1 */ - source = (sljit_sw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset); - offset = (sljit_sw)SLJIT_ADD_EXEC_OFFSET(pool_ptr, executable_offset) - source; + if (ins & 0xffffffff0000L) { + *code_ptr++ = (sljit_u16)(ins >> 16); + half_count++; + } - SLJIT_ASSERT(!(offset & 1)); - offset >>= 1; - SLJIT_ASSERT(is_s32(offset)); + *code_ptr++ = (sljit_u16)ins; + half_count++; + } while (buf_ptr < buf_end); - encode_inst(&code_ptr, lgrl(tmp1, offset & 0xffffffff)); - - /* store jump target into pool and update pool address */ - *(pool_ptr++) = (sljit_uw)target; - - /* branch to tmp1 */ - op = (ins >> 32) & 0xf; - arg = (ins >> 36) & 0xf; - switch (op) { - case 4: /* brcl -> bcr */ - ins = bcr(arg, tmp1); - break; - case 5: /* brasl -> basr */ - ins = basr(arg, tmp1); - break; - default: - abort(); - } - } - else { - jump->addr = (sljit_uw)code_ptr + 2; - source = (sljit_sw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset); - offset = target - source; + buf = buf->next; + } while (buf); - /* offset must be halfword aligned */ - SLJIT_ASSERT(!(offset & 1)); - offset >>= 1; - SLJIT_ASSERT(is_s32(offset)); /* TODO(mundaym): handle arbitrary offsets */ + if (next_label_size == half_count) { + label->u.addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset); + label = label->next; + } - /* patch jump target */ - ins |= (sljit_ins)offset & 0xffffffff; - } - jump = jump->next; - } - if (put_label && put_label->addr == j) { - source = (sljit_sw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset); + SLJIT_ASSERT(!label); + SLJIT_ASSERT(!jump); + SLJIT_ASSERT(!const_); + SLJIT_ASSERT(code + (ins_size >> 1) == code_ptr); + SLJIT_ASSERT((sljit_u8 *)pool + pool_size == (sljit_u8 *)pool_ptr); - SLJIT_ASSERT(put_label->label); - put_label->addr = (sljit_uw)code_ptr; + jump = compiler->jumps; + while (jump != NULL) { + offset = (sljit_sw)((jump->flags & JUMP_ADDR) ? jump->u.target : jump->u.label->u.addr); - /* store target into pool */ - *pool_ptr = put_label->label->addr; - offset = (sljit_sw)SLJIT_ADD_EXEC_OFFSET(pool_ptr, executable_offset) - source; - pool_ptr++; + if (jump->flags & (SLJIT_REWRITABLE_JUMP | JUMP_ADDR | JUMP_MOV_ADDR)) { + /* Store jump target into pool. */ + *(sljit_uw*)(jump->addr) = (sljit_uw)offset; + } else { + code_ptr = (sljit_u16*)jump->addr; + offset -= (sljit_sw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset); - SLJIT_ASSERT(!(offset & 1)); - offset >>= 1; - SLJIT_ASSERT(is_s32(offset)); - ins |= (sljit_ins)offset & 0xffffffff; + /* offset must be halfword aligned */ + SLJIT_ASSERT(!(offset & 1)); + offset >>= 1; + SLJIT_ASSERT(is_s32(offset)); /* TODO(mundaym): handle arbitrary offsets */ - put_label = put_label->next; - } - encode_inst(&code_ptr, ins); + code_ptr[1] = (sljit_u16)(offset >> 16); + code_ptr[2] = (sljit_u16)offset; } + jump = jump->next; } - SLJIT_ASSERT((sljit_u8 *)code + ins_size == code_ptr); - SLJIT_ASSERT((sljit_u8 *)pool + pool_size == (sljit_u8 *)pool_ptr); compiler->error = SLJIT_ERR_COMPILED; compiler->executable_offset = executable_offset; compiler->executable_size = ins_size; if (pool_size) compiler->executable_size += (pad_size + pool_size); - code = SLJIT_ADD_EXEC_OFFSET(code, executable_offset); - code_ptr = SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset); + + code = (sljit_u16 *)SLJIT_ADD_EXEC_OFFSET(code, executable_offset); + code_ptr = (sljit_u16 *)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset); SLJIT_CACHE_FLUSH(code, code_ptr); SLJIT_UPDATE_WX_FLAGS(code, code_ptr, 1); return code; @@ -2497,7 +2464,7 @@ static sljit_s32 sljit_emit_sub(struct sljit_compiler *compiler, sljit_s32 op, const struct ins_forms *forms; sljit_ins ins; - if (dst == (sljit_s32)tmp0 && flag_type <= SLJIT_SIG_LESS_EQUAL) { + if (dst == TMP_REG2 && flag_type <= SLJIT_SIG_LESS_EQUAL) { int compare_signed = flag_type >= SLJIT_SIG_LESS; compiler->status_flags_state |= SLJIT_CURRENT_FLAGS_COMPARE; @@ -2597,7 +2564,7 @@ done: - the first operand is less if the sign bit of the result is not set The -result operation sets the corrent sign, because the result cannot be zero. The overflow is considered greater, since the result must be equal to INT_MIN so its sign bit is set. */ - FAIL_IF(push_inst(compiler, brc(0xe, 2 + 2))); + FAIL_IF(push_inst(compiler, brc(0xe, (op & SLJIT_32) ? (2 + 1) : (2 + 2)))); FAIL_IF(push_inst(compiler, (op & SLJIT_32) ? lcr(tmp1, dst_r) : lcgr(tmp1, dst_r))); } else if (op & SLJIT_SET_Z) @@ -2759,7 +2726,7 @@ static sljit_s32 sljit_emit_bitwise(struct sljit_compiler *compiler, sljit_s32 o sljit_s32 type = GET_OPCODE(op); const struct ins_forms *forms; - if (src2 == SLJIT_IMM && (!(op & SLJIT_SET_Z) || (type == SLJIT_AND && dst == (sljit_s32)tmp0))) { + if (src2 == SLJIT_IMM && (!(op & SLJIT_SET_Z) || (type == SLJIT_AND && dst == TMP_REG2))) { sljit_s32 count16 = 0; sljit_uw imm = (sljit_uw)src2w; @@ -2775,13 +2742,13 @@ static sljit_s32 sljit_emit_bitwise(struct sljit_compiler *compiler, sljit_s32 o if ((imm & 0xffff000000000000ull) != 0) count16++; - if (type == SLJIT_AND && dst == (sljit_s32)tmp0 && count16 == 1) { - sljit_gpr src_r = tmp0; + if (type == SLJIT_AND && dst == TMP_REG2 && count16 == 1) { + sljit_gpr src_r = tmp1; if (FAST_IS_REG(src1)) src_r = gpr(src1 & REG_MASK); else - FAIL_IF(emit_move(compiler, tmp0, src1, src1w)); + FAIL_IF(emit_move(compiler, tmp1, src1, src1w)); if ((imm & 0x000000000000ffffull) != 0 || imm == 0) return push_inst(compiler, 0xa7010000 /* tmll */ | R20A(src_r) | imm); @@ -3002,11 +2969,31 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compil sljit_s32 src1, sljit_sw src1w, sljit_s32 src2, sljit_sw src2w) { + sljit_s32 dst_reg = (GET_OPCODE(op) == SLJIT_SUB || GET_OPCODE(op) == SLJIT_AND) ? TMP_REG2 : TMP_REG1; + CHECK_ERROR(); CHECK(check_sljit_emit_op2(compiler, op, 1, 0, 0, src1, src1w, src2, src2w)); SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_op2(compiler, op, (sljit_s32)tmp0, 0, src1, src1w, src2, src2w); + return sljit_emit_op2(compiler, op, dst_reg, 0, src1, src1w, src2, src2w); +} + +SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2r(struct sljit_compiler *compiler, sljit_s32 op, + sljit_s32 dst_reg, + sljit_s32 src1, sljit_sw src1w, + sljit_s32 src2, sljit_sw src2w) +{ + CHECK_ERROR(); + CHECK(check_sljit_emit_op2r(compiler, op, dst_reg, src1, src1w, src2, src2w)); + + switch (GET_OPCODE(op)) { + case SLJIT_MULADD: + SLJIT_SKIP_CHECKS(compiler); + FAIL_IF(sljit_emit_op2(compiler, SLJIT_MUL | (op & SLJIT_32), 0 /* tmp0 */, 0, src1, src1w, src2, src2w)); + return push_inst(compiler, ((op & SLJIT_32) ? 0x1a00 /* ar */ : 0xb9080000 /* agr */) | R4A(gpr(dst_reg)) | R0A(tmp0)); + } + + return SLJIT_SUCCESS; } SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *compiler, sljit_s32 op, @@ -3415,12 +3402,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compil FAIL_IF(push_inst(compiler, ins | F4(dst_r) | F0(src))); } - if (!(dst & SLJIT_MEM)) - return SLJIT_SUCCESS; - - SLJIT_ASSERT(dst_r == TMP_FREG1); + if (dst & SLJIT_MEM) + return float_mem(compiler, FLOAT_STORE | (op & SLJIT_32), TMP_FREG1, dst, dstw); - return float_mem(compiler, FLOAT_STORE | (op & SLJIT_32), TMP_FREG1, dst, dstw); + return SLJIT_SUCCESS; } #define FLOAT_MOV(op, dst_r, src_r) \ @@ -3491,7 +3476,6 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compil if (dst & SLJIT_MEM) return float_mem(compiler, FLOAT_STORE | (op & SLJIT_32), TMP_FREG1, dst, dstw); - SLJIT_ASSERT(dst_r != TMP_FREG1); return SLJIT_SUCCESS; } @@ -3738,8 +3722,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co FAIL_IF(push_inst(compiler, WHEN2(op & SLJIT_32, lochi, locghi))); } else { - /* TODO(mundaym): no load/store-on-condition 2 facility (ipm? branch-and-set?) */ - abort(); + FAIL_IF(push_load_imm_inst(compiler, loc_r, 1)); + FAIL_IF(push_inst(compiler, brc(mask, 2 + 2))); + FAIL_IF(push_load_imm_inst(compiler, loc_r, 0)); } #undef LEVAL @@ -3837,8 +3822,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *comp return push_inst(compiler, ins | R36A(dst_r) | (mask << 32) | (sljit_ins)(src1w & 0xffff) << 16); } - FAIL_IF(push_load_imm_inst(compiler, tmp0, src1w)); - src_r = tmp0; + FAIL_IF(push_load_imm_inst(compiler, tmp1, src1w)); + src_r = tmp1; } else src_r = gpr(src1); @@ -4474,9 +4459,9 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi dst_r = FAST_IS_REG(dst) ? gpr(dst & REG_MASK) : tmp0; if (have_genext()) - PTR_FAIL_IF(push_inst(compiler, sljit_ins_const | lgrl(dst_r, 0))); + PTR_FAIL_IF(push_inst(compiler, lgrl(dst_r, 0))); else { - PTR_FAIL_IF(push_inst(compiler, sljit_ins_const | larl(tmp1, 0))); + PTR_FAIL_IF(push_inst(compiler, larl(tmp1, 0))); PTR_FAIL_IF(push_inst(compiler, lg(dst_r, 0, r0, tmp1))); } @@ -4503,20 +4488,18 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_consta sljit_set_jump_addr(addr, (sljit_uw)new_constant, executable_offset); } -SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label *sljit_emit_put_label( - struct sljit_compiler *compiler, - sljit_s32 dst, sljit_sw dstw) +SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_mov_addr(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw) { - struct sljit_put_label *put_label; + struct sljit_jump *jump; sljit_gpr dst_r; CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_put_label(compiler, dst, dstw)); + CHECK_PTR(check_sljit_emit_mov_addr(compiler, dst, dstw)); ADJUST_LOCAL_OFFSET(dst, dstw); - put_label = (struct sljit_put_label*)ensure_abuf(compiler, sizeof(struct sljit_put_label)); - PTR_FAIL_IF(!put_label); - set_put_label(put_label, compiler, 0); + jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump)); + PTR_FAIL_IF(!jump); + set_mov_addr(jump, compiler, 0); dst_r = FAST_IS_REG(dst) ? gpr(dst & REG_MASK) : tmp0; @@ -4530,7 +4513,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label *sljit_emit_put_label( if (dst & SLJIT_MEM) PTR_FAIL_IF(store_word(compiler, dst_r, dst, dstw, 0)); - return put_label; + return jump; } /* TODO(carenas): EVAL probably should move up or be refactored */ diff --git a/src/sljit/sljitNativeX86_32.c b/src/sljit/sljitNativeX86_32.c index ba4a1eb..59ea04a 100644 --- a/src/sljit/sljitNativeX86_32.c +++ b/src/sljit/sljitNativeX86_32.c @@ -283,28 +283,25 @@ static sljit_s32 emit_vex_instruction(struct sljit_compiler *compiler, sljit_uw /* Enter / return */ /* --------------------------------------------------------------------- */ -static sljit_u8* generate_far_jump_code(struct sljit_jump *jump, sljit_u8 *code_ptr, sljit_sw executable_offset) +static sljit_u8* detect_far_jump_type(struct sljit_jump *jump, sljit_u8 *code_ptr, sljit_sw executable_offset) { sljit_uw type = jump->flags >> TYPE_SHIFT; if (type == SLJIT_JUMP) { *code_ptr++ = JMP_i32; - jump->addr++; - } - else if (type >= SLJIT_FAST_CALL) { + } else if (type >= SLJIT_FAST_CALL) { *code_ptr++ = CALL_i32; - jump->addr++; - } - else { + } else { *code_ptr++ = GROUP_0F; *code_ptr++ = get_jump_code(type); - jump->addr += 2; } - if (jump->flags & JUMP_LABEL) - jump->flags |= PATCH_MW; - else + jump->addr = (sljit_uw)code_ptr; + + if (jump->flags & JUMP_ADDR) sljit_unaligned_store_sw(code_ptr, (sljit_sw)(jump->u.target - (jump->addr + 4) - (sljit_uw)executable_offset)); + else + jump->flags |= PATCH_MW; code_ptr += 4; return code_ptr; @@ -1249,6 +1246,68 @@ static sljit_s32 sljit_emit_get_return_address(struct sljit_compiler *compiler, /* Other operations */ /* --------------------------------------------------------------------- */ +SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *compiler, sljit_s32 type, + sljit_s32 dst_reg, + sljit_s32 src1, sljit_sw src1w, + sljit_s32 src2_reg) +{ + sljit_s32 dst = dst_reg; + sljit_sw dstw = 0; + sljit_sw src2w = 0; + + CHECK_ERROR(); + CHECK(check_sljit_emit_select(compiler, type, dst_reg, src1, src1w, src2_reg)); + + ADJUST_LOCAL_OFFSET(src1, src1w); + + CHECK_EXTRA_REGS(dst, dstw, (void)0); + CHECK_EXTRA_REGS(src1, src1w, (void)0); + CHECK_EXTRA_REGS(src2_reg, src2w, (void)0); + + type &= ~SLJIT_32; + + if (dst & SLJIT_MEM) { + if (src1 == SLJIT_IMM || (!(src1 & SLJIT_MEM) && (src2_reg & SLJIT_MEM))) { + EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w); + src1 = src2_reg; + src1w = src2w; + type ^= 0x1; + } else + EMIT_MOV(compiler, TMP_REG1, 0, src2_reg, src2w); + + dst_reg = TMP_REG1; + } else { + if (dst_reg != src2_reg) { + if (dst_reg == src1) { + src1 = src2_reg; + src1w = src2w; + type ^= 0x1; + } else if (ADDRESSING_DEPENDS_ON(src1, dst_reg)) { + EMIT_MOV(compiler, dst_reg, 0, src1, src1w); + src1 = src2_reg; + src1w = src2w; + type ^= 0x1; + } else + EMIT_MOV(compiler, dst_reg, 0, src2_reg, src2w); + } + } + + if (sljit_has_cpu_feature(SLJIT_HAS_CMOV) && (src1 != SLJIT_IMM || dst_reg != TMP_REG1)) { + if (SLJIT_UNLIKELY(src1 == SLJIT_IMM)) { + EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w); + src1 = TMP_REG1; + src1w = 0; + } + + FAIL_IF(emit_groupf(compiler, U8(get_jump_code((sljit_uw)type) - 0x40), dst_reg, src1, src1w)); + } else + FAIL_IF(emit_cmov_generic(compiler, type, dst_reg, src1, src1w)); + + if (dst & SLJIT_MEM) + return emit_mov(compiler, dst, dstw, TMP_REG1, 0); + return SLJIT_SUCCESS; +} + SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 reg, sljit_s32 mem, sljit_sw memw) @@ -1449,10 +1508,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset32(struct sljit_compiler *comp if (u.imm == 0) { inst[2] = PXOR_x_xm; - inst[3] = U8(freg | (freg << 3) | MOD_REG); + inst[3] = U8(freg_map[freg] | (freg_map[freg] << 3) | MOD_REG); } else { inst[2] = MOVD_x_rm; - inst[3] = U8(reg_map[TMP_REG1] | (freg << 3) | MOD_REG); + inst[3] = U8(reg_map[TMP_REG1] | (freg_map[freg] << 3) | MOD_REG); } return SLJIT_SUCCESS; @@ -1462,7 +1521,6 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset64(struct sljit_compiler *comp sljit_s32 freg, sljit_f64 value) { sljit_u8 *inst; - sljit_s32 tmp_freg = freg; union { sljit_s32 imm[2]; sljit_f64 value; @@ -1478,8 +1536,18 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset64(struct sljit_compiler *comp return emit_groupf(compiler, PXOR_x_xm | EX86_PREF_66 | EX86_SSE2, freg, freg, 0); EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_IMM, u.imm[1]); - } else + } else { + SLJIT_ASSERT(cpu_feature_list != 0); + + if (!(cpu_feature_list & CPU_FEATURE_SSE41) && u.imm[1] != 0 && u.imm[0] != u.imm[1]) { + EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_SP), 0, SLJIT_IMM, u.imm[0]); + EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_SP), sizeof(sljit_sw), SLJIT_IMM, u.imm[1]); + + return emit_groupf(compiler, MOVLPD_x_m | EX86_SSE2, freg, SLJIT_MEM1(SLJIT_SP), 0); + } + EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_IMM, u.imm[0]); + } FAIL_IF(emit_groupf(compiler, MOVD_x_rm | EX86_PREF_66 | EX86_SSE2_OP1, freg, TMP_REG1, 0)); @@ -1493,23 +1561,17 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset64(struct sljit_compiler *comp inst[0] = GROUP_0F; inst[1] = SHUFPS_x_xm; - inst[2] = U8(MOD_REG | (freg << 3) | freg); + inst[2] = U8(MOD_REG | (freg_map[freg] << 3) | freg_map[freg]); inst[3] = 0x51; return SLJIT_SUCCESS; } if (u.imm[0] != u.imm[1]) { - SLJIT_ASSERT(u.imm[1] != 0 && cpu_feature_list != 0); - + SLJIT_ASSERT(cpu_feature_list & CPU_FEATURE_SSE41); EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_IMM, u.imm[1]); - if (cpu_feature_list & CPU_FEATURE_SSE41) { - FAIL_IF(emit_groupf_ext(compiler, PINSRD_x_rm_i8 | EX86_PREF_66 | VEX_OP_0F3A | EX86_SSE2_OP1, freg, TMP_REG1, 0)); - return emit_byte(compiler, 1); - } - - FAIL_IF(emit_groupf(compiler, MOVD_x_rm | EX86_PREF_66 | EX86_SSE2_OP1, TMP_FREG, TMP_REG1, 0)); - tmp_freg = TMP_FREG; + FAIL_IF(emit_groupf_ext(compiler, PINSRD_x_rm_i8 | EX86_PREF_66 | VEX_OP_0F3A | EX86_SSE2_OP1, freg, TMP_REG1, 0)); + return emit_byte(compiler, 1); } inst = (sljit_u8*)ensure_buf(compiler, 1 + 3); @@ -1518,7 +1580,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset64(struct sljit_compiler *comp inst[0] = GROUP_0F; inst[1] = UNPCKLPS_x_xm; - inst[2] = U8(MOD_REG | (freg << 3) | tmp_freg); + inst[2] = U8(MOD_REG | (freg_map[freg] << 3) | freg_map[freg]); return SLJIT_SUCCESS; } @@ -1581,7 +1643,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fcopy(struct sljit_compiler *compi inst[0] = GROUP_66; inst[1] = GROUP_0F; inst[2] = PSHUFD_x_xm; - inst[3] = U8(MOD_REG | (TMP_FREG << 3) | freg); + inst[3] = U8(MOD_REG | (TMP_FREG << 3) | freg_map[freg]); inst[4] = 1; } else if (reg != 0) FAIL_IF(emit_groupf(compiler, MOVD_x_rm | EX86_PREF_66 | EX86_SSE2_OP1, TMP_FREG, reg, regw)); @@ -1597,7 +1659,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fcopy(struct sljit_compiler *compi inst[0] = GROUP_0F; inst[1] = UNPCKLPS_x_xm; - inst[2] = U8(MOD_REG | (freg << 3) | (reg == 0 ? freg : TMP_FREG)); + inst[2] = U8(MOD_REG | (freg_map[freg] << 3) | freg_map[reg == 0 ? freg : TMP_FREG]); } else FAIL_IF(emit_groupf(compiler, MOVD_rm_x | EX86_PREF_66 | EX86_SSE2_OP1, TMP_FREG, reg, regw)); diff --git a/src/sljit/sljitNativeX86_64.c b/src/sljit/sljitNativeX86_64.c index f313f3f..1ab7929 100644 --- a/src/sljit/sljitNativeX86_64.c +++ b/src/sljit/sljitNativeX86_64.c @@ -358,26 +358,28 @@ static sljit_s32 emit_vex_instruction(struct sljit_compiler *compiler, sljit_uw /* Enter / return */ /* --------------------------------------------------------------------- */ -static sljit_u8* generate_far_jump_code(struct sljit_jump *jump, sljit_u8 *code_ptr) +static sljit_u8* detect_far_jump_type(struct sljit_jump *jump, sljit_u8 *code_ptr) { sljit_uw type = jump->flags >> TYPE_SHIFT; - int short_addr = !(jump->flags & SLJIT_REWRITABLE_JUMP) && !(jump->flags & JUMP_LABEL) && (jump->u.target <= 0xffffffff); + int short_addr = !(jump->flags & SLJIT_REWRITABLE_JUMP) && (jump->flags & JUMP_ADDR) && (jump->u.target <= 0xffffffff); /* The relative jump below specialized for this case. */ - SLJIT_ASSERT(reg_map[TMP_REG2] >= 8); + SLJIT_ASSERT(reg_map[TMP_REG2] >= 8 && TMP_REG2 != SLJIT_TMP_DEST_REG); if (type < SLJIT_JUMP) { /* Invert type. */ - *code_ptr++ = U8(get_jump_code(type ^ 0x1) - 0x10); - *code_ptr++ = short_addr ? (6 + 3) : (10 + 3); + code_ptr[0] = U8(get_jump_code(type ^ 0x1) - 0x10); + code_ptr[1] = short_addr ? (6 + 3) : (10 + 3); + code_ptr += 2; } - *code_ptr++ = short_addr ? REX_B : (REX_W | REX_B); - *code_ptr++ = MOV_r_i32 | reg_lmap[TMP_REG2]; + code_ptr[0] = short_addr ? REX_B : (REX_W | REX_B); + code_ptr[1] = MOV_r_i32 | reg_lmap[TMP_REG2]; + code_ptr += 2; jump->addr = (sljit_uw)code_ptr; - if (jump->flags & JUMP_LABEL) + if (!(jump->flags & JUMP_ADDR)) jump->flags |= PATCH_MD; else if (short_addr) sljit_unaligned_store_s32(code_ptr, (sljit_s32)jump->u.target); @@ -386,60 +388,62 @@ static sljit_u8* generate_far_jump_code(struct sljit_jump *jump, sljit_u8 *code_ code_ptr += short_addr ? sizeof(sljit_s32) : sizeof(sljit_sw); - *code_ptr++ = REX_B; - *code_ptr++ = GROUP_FF; - *code_ptr++ = U8(MOD_REG | (type >= SLJIT_FAST_CALL ? CALL_rm : JMP_rm) | reg_lmap[TMP_REG2]); + code_ptr[0] = REX_B; + code_ptr[1] = GROUP_FF; + code_ptr[2] = U8(MOD_REG | (type >= SLJIT_FAST_CALL ? CALL_rm : JMP_rm) | reg_lmap[TMP_REG2]); - return code_ptr; + return code_ptr + 3; } -static sljit_u8* generate_put_label_code(struct sljit_put_label *put_label, sljit_u8 *code_ptr, sljit_uw max_label) +static sljit_u8* generate_mov_addr_code(struct sljit_jump *jump, sljit_u8 *code_ptr, sljit_u8 *code, sljit_sw executable_offset) { - if (max_label > HALFWORD_MAX) { - put_label->addr -= put_label->flags; - put_label->flags = PATCH_MD; - return code_ptr; - } + sljit_uw addr; + sljit_sw diff; + SLJIT_UNUSED_ARG(executable_offset); - if (put_label->flags == 0) { - /* Destination is register. */ - code_ptr = (sljit_u8*)put_label->addr - 2 - sizeof(sljit_uw); + SLJIT_ASSERT(((jump->flags >> JUMP_SIZE_SHIFT) & 0x1f) <= 10); + if (jump->flags & JUMP_ADDR) + addr = jump->u.target; + else + addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code, executable_offset) + jump->u.label->size; - SLJIT_ASSERT((code_ptr[0] & 0xf8) == REX_W); - SLJIT_ASSERT((code_ptr[1] & 0xf8) == MOV_r_i32); + if (addr > 0xffffffffl) { + diff = (sljit_sw)addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset); - if ((code_ptr[0] & 0x07) != 0) { - code_ptr[0] = U8(code_ptr[0] & ~0x08); - code_ptr += 2 + sizeof(sljit_s32); - } - else { - code_ptr[0] = code_ptr[1]; - code_ptr += 1 + sizeof(sljit_s32); + if (diff <= HALFWORD_MAX && diff >= HALFWORD_MIN) { + SLJIT_ASSERT(((jump->flags >> JUMP_SIZE_SHIFT) & 0x1f) >= 7); + code_ptr -= SSIZE_OF(s32) - 1; + + SLJIT_ASSERT((code_ptr[-3 - SSIZE_OF(s32)] & 0xf8) == REX_W); + SLJIT_ASSERT((code_ptr[-2 - SSIZE_OF(s32)] & 0xf8) == MOV_r_i32); + + code_ptr[-3 - SSIZE_OF(s32)] = U8(REX_W | ((code_ptr[-3 - SSIZE_OF(s32)] & 0x1) << 2)); + code_ptr[-1 - SSIZE_OF(s32)] = U8(((code_ptr[-2 - SSIZE_OF(s32)] & 0x7) << 3) | 0x5); + code_ptr[-2 - SSIZE_OF(s32)] = LEA_r_m; + + jump->flags |= PATCH_MW; + return code_ptr; } - put_label->addr = (sljit_uw)code_ptr; + jump->flags |= PATCH_MD; return code_ptr; } - code_ptr -= put_label->flags + (2 + sizeof(sljit_uw)); - SLJIT_MEMMOVE(code_ptr, code_ptr + (2 + sizeof(sljit_uw)), put_label->flags); + code_ptr -= 2 + sizeof(sljit_uw); SLJIT_ASSERT((code_ptr[0] & 0xf8) == REX_W); + SLJIT_ASSERT((code_ptr[1] & 0xf8) == MOV_r_i32); - if ((code_ptr[1] & 0xf8) == MOV_r_i32) { - code_ptr += 2 + sizeof(sljit_uw); - SLJIT_ASSERT((code_ptr[0] & 0xf8) == REX_W); + if ((code_ptr[0] & 0x07) != 0) { + SLJIT_ASSERT(((jump->flags >> JUMP_SIZE_SHIFT) & 0x1f) >= 6); + code_ptr[0] = U8(code_ptr[0] & ~0x08); + code_ptr += 2 + sizeof(sljit_s32); + } else { + SLJIT_ASSERT(((jump->flags >> JUMP_SIZE_SHIFT) & 0x1f) >= 5); + code_ptr[0] = code_ptr[1]; + code_ptr += 1 + sizeof(sljit_s32); } - SLJIT_ASSERT(code_ptr[1] == MOV_rm_r); - - code_ptr[0] = U8(code_ptr[0] & ~0x4); - code_ptr[1] = MOV_rm_i32; - code_ptr[2] = U8(code_ptr[2] & ~(0x7 << 3)); - - code_ptr = (sljit_u8*)(put_label->addr - (2 + sizeof(sljit_uw)) + sizeof(sljit_s32)); - put_label->addr = (sljit_uw)code_ptr; - put_label->flags = 0; return code_ptr; } @@ -1003,6 +1007,46 @@ static sljit_s32 sljit_emit_get_return_address(struct sljit_compiler *compiler, /* Other operations */ /* --------------------------------------------------------------------- */ +SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *compiler, sljit_s32 type, + sljit_s32 dst_reg, + sljit_s32 src1, sljit_sw src1w, + sljit_s32 src2_reg) +{ + CHECK_ERROR(); + CHECK(check_sljit_emit_select(compiler, type, dst_reg, src1, src1w, src2_reg)); + + ADJUST_LOCAL_OFFSET(src1, src1w); + + compiler->mode32 = type & SLJIT_32; + type &= ~SLJIT_32; + + if (dst_reg != src2_reg) { + if (dst_reg == src1) { + src1 = src2_reg; + src1w = 0; + type ^= 0x1; + } else if (ADDRESSING_DEPENDS_ON(src1, dst_reg)) { + EMIT_MOV(compiler, dst_reg, 0, src1, src1w); + src1 = src2_reg; + src1w = 0; + type ^= 0x1; + } else + EMIT_MOV(compiler, dst_reg, 0, src2_reg, 0); + } + + if (sljit_has_cpu_feature(SLJIT_HAS_CMOV)) { + if (SLJIT_UNLIKELY(src1 == SLJIT_IMM)) { + EMIT_MOV(compiler, TMP_REG2, 0, src1, src1w); + src1 = TMP_REG2; + src1w = 0; + } + + return emit_groupf(compiler, U8(get_jump_code((sljit_uw)type) - 0x40), dst_reg, src1, src1w); + } + + return emit_cmov_generic(compiler, type, dst_reg, src1, src1w); +} + SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 reg, sljit_s32 mem, sljit_sw memw) diff --git a/src/sljit/sljitNativeX86_common.c b/src/sljit/sljitNativeX86_common.c index c2c0421..ecb7e9b 100644 --- a/src/sljit/sljitNativeX86_common.c +++ b/src/sljit/sljitNativeX86_common.c @@ -24,12 +24,6 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#if defined(__has_feature) -#if __has_feature(memory_sanitizer) -#include -#endif /* __has_feature(memory_sanitizer) */ -#endif /* defined(__has_feature) */ - SLJIT_API_FUNC_ATTRIBUTE const char* sljit_get_platform_name(void) { return "x86" SLJIT_CPUINFO; @@ -72,7 +66,6 @@ SLJIT_API_FUNC_ATTRIBUTE const char* sljit_get_platform_name(void) #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 3] = { 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 5, 7, 6, 4, 3 }; @@ -379,6 +372,11 @@ static const sljit_u8 freg_lmap[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 2] = { #define RET() (*inst++ = RET_near) #define RET_I16(n) (*inst++ = RET_i16, *inst++ = U8(n), *inst++ = 0) +#define SLJIT_INST_LABEL 255 +#define SLJIT_INST_JUMP 254 +#define SLJIT_INST_MOV_ADDR 253 +#define SLJIT_INST_CONST 252 + /* 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. */ @@ -392,6 +390,7 @@ static const sljit_u8 freg_lmap[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 2] = { #define CPU_FEATURE_CMOV 0x020 #define CPU_FEATURE_AVX 0x040 #define CPU_FEATURE_AVX2 0x080 +#define CPU_FEATURE_OSXSAVE 0x100 static sljit_u32 cpu_feature_list = 0; @@ -490,22 +489,50 @@ static void execute_cpu_id(sljit_u32 info[4]) } #endif /* _MSC_VER && _MSC_VER >= 1400 */ +} -#if defined(__has_feature) -#if __has_feature(memory_sanitizer) -__msan_unpoison(info, 4 * sizeof(sljit_u32)); -#endif /* __has_feature(memory_sanitizer) */ -#endif /* defined(__has_feature) */ +static sljit_u32 execute_get_xcr0_low(void) +{ + sljit_u32 xcr0; + +#if defined(_MSC_VER) && _MSC_VER >= 1400 + xcr0 = (sljit_u32)_xgetbv(0); + +#elif defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_C) || defined(__TINYC__) + + /* AT&T syntax. */ + __asm__ ( + "xorl %%ecx, %%ecx\n" + "xgetbv\n" + : "=a" (xcr0) + : +#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) + : "ecx", "edx" +#else /* !SLJIT_CONFIG_X86_32 */ + : "rcx", "rdx" +#endif /* SLJIT_CONFIG_X86_32 */ + ); + +#else /* _MSC_VER < 1400 */ + + /* Intel syntax. */ + __asm { + mov ecx, 0 + xgetbv + mov xcr0, eax + } + +#endif /* _MSC_VER && _MSC_VER >= 1400 */ + return xcr0; } static void get_cpu_features(void) { sljit_u32 feature_list = CPU_FEATURE_DETECTED; - sljit_u32 info[4]; + sljit_u32 info[4] = {0}; sljit_u32 max_id; - info[0] = 0; execute_cpu_id(info); max_id = info[0]; @@ -526,6 +553,8 @@ static void get_cpu_features(void) if (info[2] & 0x80000) feature_list |= CPU_FEATURE_SSE41; + if (info[2] & 0x8000000) + feature_list |= CPU_FEATURE_OSXSAVE; if (info[2] & 0x10000000) feature_list |= CPU_FEATURE_AVX; #if (defined SLJIT_DETECT_SSE2 && SLJIT_DETECT_SSE2) @@ -537,12 +566,14 @@ static void get_cpu_features(void) } info[0] = 0x80000001; - info[2] = 0; /* Silences an incorrect compiler warning. */ execute_cpu_id(info); if (info[2] & 0x20) feature_list |= CPU_FEATURE_LZCNT; + if ((feature_list & CPU_FEATURE_OSXSAVE) && (execute_get_xcr0_low() & 0x4) == 0) + feature_list &= ~(sljit_u32)(CPU_FEATURE_AVX | CPU_FEATURE_AVX2); + cpu_feature_list = feature_list; } @@ -617,52 +648,47 @@ static sljit_u8 get_jump_code(sljit_uw type) } #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) -static sljit_u8* generate_far_jump_code(struct sljit_jump *jump, sljit_u8 *code_ptr, sljit_sw executable_offset); -#else -static sljit_u8* generate_far_jump_code(struct sljit_jump *jump, sljit_u8 *code_ptr); -static sljit_u8* generate_put_label_code(struct sljit_put_label *put_label, sljit_u8 *code_ptr, sljit_uw max_label); -#endif +static sljit_u8* detect_far_jump_type(struct sljit_jump *jump, sljit_u8 *code_ptr, sljit_sw executable_offset); +#else /* !SLJIT_CONFIG_X86_32 */ +static sljit_u8* detect_far_jump_type(struct sljit_jump *jump, sljit_u8 *code_ptr); +static sljit_u8* generate_mov_addr_code(struct sljit_jump *jump, sljit_u8 *code_ptr, sljit_u8 *code, sljit_sw executable_offset); +#endif /* SLJIT_CONFIG_X86_32 */ -static sljit_u8* generate_near_jump_code(struct sljit_jump *jump, sljit_u8 *code_ptr, sljit_u8 *code, sljit_sw executable_offset) +static sljit_u8* detect_near_jump_type(struct sljit_jump *jump, sljit_u8 *code_ptr, sljit_u8 *code, sljit_sw executable_offset) { sljit_uw type = jump->flags >> TYPE_SHIFT; sljit_s32 short_jump; sljit_uw label_addr; - if (jump->flags & JUMP_LABEL) - label_addr = (sljit_uw)(code + jump->u.label->size); - else + if (jump->flags & JUMP_ADDR) label_addr = jump->u.target - (sljit_uw)executable_offset; + else + label_addr = (sljit_uw)(code + jump->u.label->size); #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - if ((sljit_sw)(label_addr - (jump->addr + 2)) > HALFWORD_MAX || (sljit_sw)(label_addr - (jump->addr + 6)) < HALFWORD_MIN) - return generate_far_jump_code(jump, code_ptr); -#endif + if ((sljit_sw)(label_addr - (sljit_uw)(code_ptr + 6)) > HALFWORD_MAX || (sljit_sw)(label_addr - (sljit_uw)(code_ptr + 5)) < HALFWORD_MIN) + return detect_far_jump_type(jump, code_ptr); +#endif /* SLJIT_CONFIG_X86_64 */ - short_jump = (sljit_sw)(label_addr - (jump->addr + 2)) >= -128 && (sljit_sw)(label_addr - (jump->addr + 2)) <= 127; + short_jump = (sljit_sw)(label_addr - (sljit_uw)(code_ptr + 2)) >= -0x80 && (sljit_sw)(label_addr - (sljit_uw)(code_ptr + 2)) <= 0x7f; if (type == SLJIT_JUMP) { if (short_jump) *code_ptr++ = JMP_i8; else *code_ptr++ = JMP_i32; - jump->addr++; - } - else if (type >= SLJIT_FAST_CALL) { + } else if (type > SLJIT_JUMP) { short_jump = 0; *code_ptr++ = CALL_i32; - jump->addr++; - } - else if (short_jump) { + } else if (short_jump) { *code_ptr++ = U8(get_jump_code(type) - 0x10); - jump->addr++; - } - else { + } else { *code_ptr++ = GROUP_0F; *code_ptr++ = get_jump_code(type); - jump->addr += 2; } + jump->addr = (sljit_uw)code_ptr; + if (short_jump) { jump->flags |= PATCH_MB; code_ptr += sizeof(sljit_s8); @@ -674,7 +700,172 @@ static sljit_u8* generate_near_jump_code(struct sljit_jump *jump, sljit_u8 *code return code_ptr; } -SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler) +static void generate_jump_or_mov_addr(struct sljit_jump *jump, sljit_sw executable_offset) +{ + sljit_uw flags = jump->flags; + sljit_uw addr = (flags & JUMP_ADDR) ? jump->u.target : jump->u.label->u.addr; + sljit_uw jump_addr = jump->addr; + SLJIT_UNUSED_ARG(executable_offset); + + if (SLJIT_UNLIKELY(flags & JUMP_MOV_ADDR)) { +#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) + sljit_unaligned_store_sw((void*)(jump_addr - sizeof(sljit_sw)), (sljit_sw)addr); +#else /* SLJIT_CONFIG_X86_32 */ + if (flags & PATCH_MD) { + SLJIT_ASSERT(addr > HALFWORD_MAX); + sljit_unaligned_store_sw((void*)(jump_addr - sizeof(sljit_sw)), (sljit_sw)addr); + return; + } + + if (flags & PATCH_MW) { + addr -= (sljit_uw)SLJIT_ADD_EXEC_OFFSET((sljit_u8*)jump_addr, executable_offset); + SLJIT_ASSERT((sljit_sw)addr <= HALFWORD_MAX && (sljit_sw)addr >= HALFWORD_MIN); + } else { + SLJIT_ASSERT(addr <= HALFWORD_MAX); + } + sljit_unaligned_store_s32((void*)(jump_addr - sizeof(sljit_s32)), (sljit_s32)addr); +#endif /* !SLJIT_CONFIG_X86_32 */ + return; + } + +#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) + if (SLJIT_UNLIKELY(flags & PATCH_MD)) { + SLJIT_ASSERT(!(flags & JUMP_ADDR)); + sljit_unaligned_store_sw((void*)jump_addr, (sljit_sw)addr); + return; + } +#endif /* SLJIT_CONFIG_X86_64 */ + + addr -= (sljit_uw)SLJIT_ADD_EXEC_OFFSET((sljit_u8*)jump_addr, executable_offset); + + if (flags & PATCH_MB) { + addr -= sizeof(sljit_s8); + SLJIT_ASSERT((sljit_sw)addr <= 0x7f && (sljit_sw)addr >= -0x80); + *(sljit_u8*)jump_addr = U8(addr); + return; + } else if (flags & PATCH_MW) { + addr -= sizeof(sljit_s32); +#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) + sljit_unaligned_store_sw((void*)jump_addr, (sljit_sw)addr); +#else /* !SLJIT_CONFIG_X86_32 */ + SLJIT_ASSERT((sljit_sw)addr <= HALFWORD_MAX && (sljit_sw)addr >= HALFWORD_MIN); + sljit_unaligned_store_s32((void*)jump_addr, (sljit_s32)addr); +#endif /* SLJIT_CONFIG_X86_32 */ + } +} + +static void reduce_code_size(struct sljit_compiler *compiler) +{ + struct sljit_label *label; + struct sljit_jump *jump; + sljit_uw next_label_size; + sljit_uw next_jump_addr; + sljit_uw next_min_addr; + sljit_uw size_reduce = 0; + sljit_sw diff; + sljit_uw type; +#if (defined SLJIT_DEBUG && SLJIT_DEBUG) + sljit_uw size_reduce_max; +#endif /* SLJIT_DEBUG */ + + label = compiler->labels; + jump = compiler->jumps; + + next_label_size = SLJIT_GET_NEXT_SIZE(label); + next_jump_addr = SLJIT_GET_NEXT_ADDRESS(jump); + + while (1) { + next_min_addr = next_label_size; + if (next_jump_addr < next_min_addr) + next_min_addr = next_jump_addr; + + if (next_min_addr == SLJIT_MAX_ADDRESS) + break; + + if (next_min_addr == next_label_size) { + label->size -= size_reduce; + + label = label->next; + next_label_size = SLJIT_GET_NEXT_SIZE(label); + } + + if (next_min_addr != next_jump_addr) + continue; + + if (!(jump->flags & JUMP_MOV_ADDR)) { +#if (defined SLJIT_DEBUG && SLJIT_DEBUG) + size_reduce_max = size_reduce + (((jump->flags >> TYPE_SHIFT) < SLJIT_JUMP) ? CJUMP_MAX_SIZE : JUMP_MAX_SIZE); +#endif /* SLJIT_DEBUG */ + + if (!(jump->flags & SLJIT_REWRITABLE_JUMP)) { + if (jump->flags & JUMP_ADDR) { +#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) + if (jump->u.target <= 0xffffffffl) + size_reduce += sizeof(sljit_s32); +#endif /* SLJIT_CONFIG_X86_64 */ + } else { + /* Unit size: instruction. */ + diff = (sljit_sw)jump->u.label->size - (sljit_sw)(jump->addr - size_reduce); + type = jump->flags >> TYPE_SHIFT; + +#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) + if (type == SLJIT_JUMP) { + if (diff <= 0x7f + 2 && diff >= -0x80 + 2) + size_reduce += JUMP_MAX_SIZE - 2; + else if (diff <= HALFWORD_MAX + 5 && diff >= HALFWORD_MIN + 5) + size_reduce += JUMP_MAX_SIZE - 5; + } else if (type < SLJIT_JUMP) { + if (diff <= 0x7f + 2 && diff >= -0x80 + 2) + size_reduce += CJUMP_MAX_SIZE - 2; + else if (diff <= HALFWORD_MAX + 6 && diff >= HALFWORD_MIN + 6) + size_reduce += CJUMP_MAX_SIZE - 6; + } else { + if (diff <= HALFWORD_MAX + 5 && diff >= HALFWORD_MIN + 5) + size_reduce += JUMP_MAX_SIZE - 5; + } +#else /* !SLJIT_CONFIG_X86_64 */ + if (type == SLJIT_JUMP) { + if (diff <= 0x7f + 2 && diff >= -0x80 + 2) + size_reduce += JUMP_MAX_SIZE - 2; + } else if (type < SLJIT_JUMP) { + if (diff <= 0x7f + 2 && diff >= -0x80 + 2) + size_reduce += CJUMP_MAX_SIZE - 2; + } +#endif /* SLJIT_CONFIG_X86_64 */ + } + } + +#if (defined SLJIT_DEBUG && SLJIT_DEBUG) + jump->flags |= (size_reduce_max - size_reduce) << JUMP_SIZE_SHIFT; +#endif /* SLJIT_DEBUG */ +#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) + } else { +#if (defined SLJIT_DEBUG && SLJIT_DEBUG) + size_reduce_max = size_reduce + 10; +#endif /* SLJIT_DEBUG */ + + if (!(jump->flags & JUMP_ADDR)) { + diff = (sljit_sw)jump->u.label->size - (sljit_sw)(jump->addr - size_reduce - 3); + + if (diff <= HALFWORD_MAX && diff >= HALFWORD_MIN) + size_reduce += 3; + } else if (jump->u.target <= 0xffffffffl) + size_reduce += (jump->flags & MOV_ADDR_HI) ? 4 : 5; + +#if (defined SLJIT_DEBUG && SLJIT_DEBUG) + jump->flags |= (size_reduce_max - size_reduce) << JUMP_SIZE_SHIFT; +#endif /* SLJIT_DEBUG */ +#endif /* SLJIT_CONFIG_X86_64 */ + } + + jump = jump->next; + next_jump_addr = SLJIT_GET_NEXT_ADDRESS(jump); + } + + compiler->size -= size_reduce; +} + +SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler, sljit_s32 options, void *exec_allocator_data) { struct sljit_memory_fragment *buf; sljit_u8 *code; @@ -683,77 +874,82 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil sljit_u8 *buf_end; sljit_u8 len; sljit_sw executable_offset; - sljit_uw jump_addr; +#if (defined SLJIT_DEBUG && SLJIT_DEBUG) + sljit_uw addr; +#endif /* SLJIT_DEBUG */ struct sljit_label *label; struct sljit_jump *jump; struct sljit_const *const_; - struct sljit_put_label *put_label; CHECK_ERROR_PTR(); CHECK_PTR(check_sljit_generate_code(compiler)); - reverse_buf(compiler); + + reduce_code_size(compiler); /* Second code generation pass. */ - code = (sljit_u8*)SLJIT_MALLOC_EXEC(compiler->size, compiler->exec_allocator_data); + code = (sljit_u8*)allocate_executable_memory(compiler->size, options, exec_allocator_data, &executable_offset); PTR_FAIL_WITH_EXEC_IF(code); + + reverse_buf(compiler); buf = compiler->buf; code_ptr = code; label = compiler->labels; jump = compiler->jumps; const_ = compiler->consts; - put_label = compiler->put_labels; - executable_offset = SLJIT_EXEC_OFFSET(code); do { buf_ptr = buf->memory; buf_end = buf_ptr + buf->used_size; do { len = *buf_ptr++; - if (len > 0) { + SLJIT_ASSERT(len > 0); + if (len < SLJIT_INST_CONST) { /* The code is already generated. */ SLJIT_MEMCPY(code_ptr, buf_ptr, len); code_ptr += len; buf_ptr += len; - } - else { - switch (*buf_ptr) { - case 0: - label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset); + } else { + switch (len) { + case SLJIT_INST_LABEL: + label->u.addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset); label->size = (sljit_uw)(code_ptr - code); label = label->next; break; - case 1: - jump->addr = (sljit_uw)code_ptr; + case SLJIT_INST_JUMP: +#if (defined SLJIT_DEBUG && SLJIT_DEBUG) + addr = (sljit_uw)code_ptr; +#endif /* SLJIT_DEBUG */ if (!(jump->flags & SLJIT_REWRITABLE_JUMP)) - code_ptr = generate_near_jump_code(jump, code_ptr, code, executable_offset); + code_ptr = detect_near_jump_type(jump, code_ptr, code, executable_offset); else { #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - code_ptr = generate_far_jump_code(jump, code_ptr, executable_offset); -#else - code_ptr = generate_far_jump_code(jump, code_ptr); -#endif + code_ptr = detect_far_jump_type(jump, code_ptr, executable_offset); +#else /* !SLJIT_CONFIG_X86_32 */ + code_ptr = detect_far_jump_type(jump, code_ptr); +#endif /* SLJIT_CONFIG_X86_32 */ } + + SLJIT_ASSERT((sljit_uw)code_ptr - addr <= ((jump->flags >> JUMP_SIZE_SHIFT) & 0x1f)); jump = jump->next; break; - case 2: - const_->addr = ((sljit_uw)code_ptr) - sizeof(sljit_sw); - const_ = const_->next; + case SLJIT_INST_MOV_ADDR: +#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) + code_ptr = generate_mov_addr_code(jump, code_ptr, code, executable_offset); +#endif /* SLJIT_CONFIG_X86_64 */ + jump->addr = (sljit_uw)code_ptr; + jump = jump->next; break; default: - SLJIT_ASSERT(*buf_ptr == 3); - SLJIT_ASSERT(put_label->label); - put_label->addr = (sljit_uw)code_ptr; -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - code_ptr = generate_put_label_code(put_label, code_ptr, (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code, executable_offset) + put_label->label->size); -#endif - put_label = put_label->next; + SLJIT_ASSERT(len == SLJIT_INST_CONST); + const_->addr = ((sljit_uw)code_ptr) - sizeof(sljit_sw); + const_ = const_->next; break; } - buf_ptr++; } } while (buf_ptr < buf_end); + SLJIT_ASSERT(buf_ptr == buf_end); buf = buf->next; } while (buf); @@ -761,61 +957,14 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil SLJIT_ASSERT(!label); SLJIT_ASSERT(!jump); SLJIT_ASSERT(!const_); - SLJIT_ASSERT(!put_label); SLJIT_ASSERT(code_ptr <= code + compiler->size); jump = compiler->jumps; while (jump) { - if (jump->flags & (PATCH_MB | PATCH_MW)) { - if (jump->flags & JUMP_LABEL) - jump_addr = jump->u.label->addr; - else - jump_addr = jump->u.target; - - jump_addr -= jump->addr + (sljit_uw)executable_offset; - - if (jump->flags & PATCH_MB) { - jump_addr -= sizeof(sljit_s8); - SLJIT_ASSERT((sljit_sw)jump_addr >= -128 && (sljit_sw)jump_addr <= 127); - *(sljit_u8*)jump->addr = U8(jump_addr); - } else { - jump_addr -= sizeof(sljit_s32); -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - sljit_unaligned_store_sw((void*)jump->addr, (sljit_sw)jump_addr); -#else - SLJIT_ASSERT((sljit_sw)jump_addr >= HALFWORD_MIN && (sljit_sw)jump_addr <= HALFWORD_MAX); - sljit_unaligned_store_s32((void*)jump->addr, (sljit_s32)jump_addr); -#endif - } - } -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - else if (jump->flags & PATCH_MD) { - SLJIT_ASSERT(jump->flags & JUMP_LABEL); - sljit_unaligned_store_sw((void*)jump->addr, (sljit_sw)jump->u.label->addr); - } -#endif - + generate_jump_or_mov_addr(jump, executable_offset); jump = jump->next; } - put_label = compiler->put_labels; - while (put_label) { -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - sljit_unaligned_store_sw((void*)(put_label->addr - sizeof(sljit_sw)), (sljit_sw)put_label->label->addr); -#else - if (put_label->flags & PATCH_MD) { - SLJIT_ASSERT(put_label->label->addr > HALFWORD_MAX); - sljit_unaligned_store_sw((void*)(put_label->addr - sizeof(sljit_sw)), (sljit_sw)put_label->label->addr); - } - else { - SLJIT_ASSERT(put_label->label->addr <= HALFWORD_MAX); - sljit_unaligned_store_s32((void*)(put_label->addr - sizeof(sljit_s32)), (sljit_s32)put_label->label->addr); - } -#endif - - put_label = put_label->next; - } - compiler->error = SLJIT_ERR_COMPILED; compiler->executable_offset = executable_offset; compiler->executable_size = (sljit_uw)(code_ptr - code); @@ -921,8 +1070,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_cmp_info(sljit_s32 type) BINARY_IMM32(op_imm, immw, arg, argw); \ } \ else { \ - FAIL_IF(emit_load_imm64(compiler, (arg == TMP_REG1) ? TMP_REG2 : TMP_REG1, immw)); \ - inst = emit_x86_instruction(compiler, 1, (arg == TMP_REG1) ? TMP_REG2 : TMP_REG1, 0, arg, argw); \ + FAIL_IF(emit_load_imm64(compiler, FAST_IS_REG(arg) ? TMP_REG2 : TMP_REG1, immw)); \ + inst = emit_x86_instruction(compiler, 1, FAST_IS_REG(arg) ? TMP_REG2 : TMP_REG1, 0, arg, argw); \ FAIL_IF(!inst); \ *inst = (op_mr); \ } \ @@ -2248,10 +2397,9 @@ static sljit_s32 emit_test_binary(struct sljit_compiler *compiler, inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, src2w, src1, src1w); FAIL_IF(!inst); *inst = GROUP_F7; - } - else { - FAIL_IF(emit_load_imm64(compiler, TMP_REG1, src2w)); - inst = emit_x86_instruction(compiler, 1, TMP_REG1, 0, src1, src1w); + } else { + FAIL_IF(emit_load_imm64(compiler, FAST_IS_REG(src1) ? TMP_REG2 : TMP_REG1, src2w)); + inst = emit_x86_instruction(compiler, 1, FAST_IS_REG(src1) ? TMP_REG2 : TMP_REG1, 0, src1, src1w); FAIL_IF(!inst); *inst = TEST_rm_r; } @@ -2488,8 +2636,6 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile compiler->mode32 = op & SLJIT_32; #endif - SLJIT_ASSERT(dst != TMP_REG1 || HAS_FLAGS(op)); - switch (GET_OPCODE(op)) { case SLJIT_ADD: if (!HAS_FLAGS(op)) { @@ -2583,12 +2729,44 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compil compiler->mode32 = op & SLJIT_32; #endif - if (opcode == SLJIT_SUB) { + if (opcode == SLJIT_SUB) return emit_cmp_binary(compiler, src1, src1w, src2, src2w); - } + return emit_test_binary(compiler, src1, src1w, src2, src2w); } +SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2r(struct sljit_compiler *compiler, sljit_s32 op, + sljit_s32 dst_reg, + sljit_s32 src1, sljit_sw src1w, + sljit_s32 src2, sljit_sw src2w) +{ + sljit_u8* inst; + sljit_sw dstw = 0; + + CHECK_ERROR(); + CHECK(check_sljit_emit_op2r(compiler, op, dst_reg, src1, src1w, src2, src2w)); + ADJUST_LOCAL_OFFSET(src1, src1w); + ADJUST_LOCAL_OFFSET(src2, src2w); + + CHECK_EXTRA_REGS(dst_reg, dstw, (void)0); + CHECK_EXTRA_REGS(src1, src1w, (void)0); + CHECK_EXTRA_REGS(src2, src2w, (void)0); +#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) + compiler->mode32 = op & SLJIT_32; +#endif + + switch (GET_OPCODE(op)) { + case SLJIT_MULADD: + FAIL_IF(emit_mul(compiler, TMP_REG1, 0, src1, src1w, src2, src2w)); + inst = emit_x86_instruction(compiler, 1, TMP_REG1, 0, dst_reg, dstw); + FAIL_IF(!inst); + *inst = ADD_rm_r; + return SLJIT_SUCCESS; + } + + return SLJIT_SUCCESS; +} + SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 dst_reg, sljit_s32 src1_reg, @@ -3117,19 +3295,17 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compil dst_r = dst; if (dst == src1) ; /* Do nothing here. */ - else if (dst == src2 && (op == SLJIT_ADD_F64 || op == SLJIT_MUL_F64)) { + else if (dst == src2 && (GET_OPCODE(op) == SLJIT_ADD_F64 || GET_OPCODE(op) == SLJIT_MUL_F64)) { /* Swap arguments. */ src2 = src1; src2w = src1w; - } - else if (dst != src2) + } else if (dst != src2) FAIL_IF(emit_sse2_load(compiler, op & SLJIT_32, dst_r, src1, src1w)); else { dst_r = TMP_FREG; FAIL_IF(emit_sse2_load(compiler, op & SLJIT_32, TMP_FREG, src1, src1w)); } - } - else { + } else { dst_r = TMP_FREG; FAIL_IF(emit_sse2_load(compiler, op & SLJIT_32, TMP_FREG, src1, src1w)); } @@ -3152,7 +3328,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compil break; } - if (dst_r == TMP_FREG) + if (dst_r != dst) return emit_sse2_store(compiler, op & SLJIT_32, dst, dstw, TMP_FREG); return SLJIT_SUCCESS; } @@ -3215,10 +3391,9 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compi PTR_FAIL_IF(!label); set_label(label, compiler); - inst = (sljit_u8*)ensure_buf(compiler, 2); + inst = (sljit_u8*)ensure_buf(compiler, 1); PTR_FAIL_IF(!inst); - inst[0] = 0; - inst[1] = 0; + inst[0] = SLJIT_INST_LABEL; return label; } @@ -3236,18 +3411,13 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile set_jump(jump, compiler, (sljit_u32)((type & SLJIT_REWRITABLE_JUMP) | ((type & 0xff) << TYPE_SHIFT))); type &= 0xff; + jump->addr = compiler->size; /* Worst case size. */ -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - compiler->size += (type >= SLJIT_JUMP) ? 5 : 6; -#else - compiler->size += (type >= SLJIT_JUMP) ? (10 + 3) : (2 + 10 + 3); -#endif - - inst = (sljit_u8*)ensure_buf(compiler, 2); + compiler->size += (type >= SLJIT_JUMP) ? JUMP_MAX_SIZE : CJUMP_MAX_SIZE; + inst = (sljit_u8*)ensure_buf(compiler, 1); PTR_FAIL_IF_NULL(inst); - inst[0] = 0; - inst[1] = 1; + inst[0] = SLJIT_INST_JUMP; return jump; } @@ -3268,20 +3438,14 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compi set_jump(jump, compiler, (sljit_u32)(JUMP_ADDR | (type << TYPE_SHIFT))); jump->u.target = (sljit_uw)srcw; + jump->addr = compiler->size; /* Worst case size. */ -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - compiler->size += 5; -#else - compiler->size += 10 + 3; -#endif - - inst = (sljit_u8*)ensure_buf(compiler, 2); + compiler->size += JUMP_MAX_SIZE; + inst = (sljit_u8*)ensure_buf(compiler, 1); FAIL_IF_NULL(inst); - inst[0] = 0; - inst[1] = 1; - } - else { + inst[0] = SLJIT_INST_JUMP; + } else { #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) /* REX_W is not necessary (src is not immediate). */ compiler->mode32 = 1; @@ -3414,82 +3578,6 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co #endif /* SLJIT_CONFIG_X86_64 */ } -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 dst_reg, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2_reg) -{ -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - sljit_s32 dst = dst_reg; - sljit_sw dstw = 0; -#endif /* SLJIT_CONFIG_X86_32 */ - sljit_sw src2w = 0; - - CHECK_ERROR(); - CHECK(check_sljit_emit_select(compiler, type, dst_reg, src1, src1w, src2_reg)); - - ADJUST_LOCAL_OFFSET(src1, src1w); - - CHECK_EXTRA_REGS(dst, dstw, (void)0); - CHECK_EXTRA_REGS(src1, src1w, (void)0); - CHECK_EXTRA_REGS(src2_reg, src2w, (void)0); - -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - compiler->mode32 = type & SLJIT_32; -#endif /* SLJIT_CONFIG_X86_64 */ - type &= ~SLJIT_32; - -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - if (dst & SLJIT_MEM) { - if (src1 == SLJIT_IMM || (!(src1 & SLJIT_MEM) && (src2_reg & SLJIT_MEM))) { - EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w); - src1 = src2_reg; - src1w = src2w; - type ^= 0x1; - } else - EMIT_MOV(compiler, TMP_REG1, 0, src2_reg, src2w); - - dst_reg = TMP_REG1; - } else { -#endif /* SLJIT_CONFIG_X86_32 */ - if (dst_reg != src2_reg) { - if (dst_reg == src1) { - src1 = src2_reg; - src1w = src2w; - type ^= 0x1; - } else { - if (ADDRESSING_DEPENDS_ON(src1, dst_reg)) { - EMIT_MOV(compiler, dst_reg, 0, src1, src1w); - src1 = src2_reg; - src1w = src2w; - type ^= 0x1; - } else - EMIT_MOV(compiler, dst_reg, 0, src2_reg, src2w); - } - } - - if (SLJIT_UNLIKELY(src1 == SLJIT_IMM)) { - SLJIT_ASSERT(dst_reg != TMP_REG1); - EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w); - src1 = TMP_REG1; - src1w = 0; - } -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - } -#endif /* SLJIT_CONFIG_X86_32 */ - - if (sljit_has_cpu_feature(SLJIT_HAS_CMOV)) - FAIL_IF(emit_groupf(compiler, U8(get_jump_code((sljit_uw)type) - 0x40), dst_reg, src1, src1w)); - else - FAIL_IF(emit_cmov_generic(compiler, type, dst_reg, src1, src1w)); - -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - if (dst_reg == TMP_REG1) - return emit_mov(compiler, dst, dstw, TMP_REG1, 0); -#endif /* SLJIT_CONFIG_X86_32 */ - return SLJIT_SUCCESS; -} - SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fselect(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 dst_freg, sljit_s32 src1, sljit_sw src1w, @@ -3581,7 +3669,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_mov(struct sljit_compiler *co if (type & SLJIT_SIMD_TEST) return SLJIT_SUCCESS; - if (op & VEX_256) + if ((op & VEX_256) || ((cpu_feature_list & CPU_FEATURE_AVX) && (compiler->options & SLJIT_ENTER_USE_VEX))) return emit_vex_instruction(compiler, op, freg, 0, srcdst, srcdstw); return emit_groupf(compiler, op, freg, srcdst, srcdstw); @@ -3593,9 +3681,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_replicate(struct sljit_compil { sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type); sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type); + sljit_s32 use_vex = (cpu_feature_list & CPU_FEATURE_AVX) && (compiler->options & SLJIT_ENTER_USE_VEX); sljit_u8 *inst; sljit_u8 opcode = 0; - sljit_uw size; + sljit_uw op; CHECK_ERROR(); CHECK(check_sljit_emit_simd_replicate(compiler, type, freg, src, srcw)); @@ -3616,20 +3705,55 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_replicate(struct sljit_compil return SLJIT_ERR_UNSUPPORTED; #endif /* SLJIT_CONFIG_X86_32 */ - if (cpu_feature_list & CPU_FEATURE_AVX2) { - if (reg_size < 4 || reg_size > 5) - return SLJIT_ERR_UNSUPPORTED; + if (reg_size != 4 && (reg_size != 5 || !(cpu_feature_list & CPU_FEATURE_AVX2))) + return SLJIT_ERR_UNSUPPORTED; - if (src != SLJIT_IMM && (reg_size == 5 || elem_size < 3 || !(type & SLJIT_SIMD_FLOAT))) { - if (type & SLJIT_SIMD_TEST) - return SLJIT_SUCCESS; + if (type & SLJIT_SIMD_TEST) + return SLJIT_SUCCESS; + + if (reg_size == 5) + use_vex = 1; + if (use_vex && src != SLJIT_IMM) { + op = 0; + + switch (elem_size) { + case 0: + if (cpu_feature_list & CPU_FEATURE_AVX2) + op = VPBROADCASTB_x_xm | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2; + break; + case 1: + if (cpu_feature_list & CPU_FEATURE_AVX2) + op = VPBROADCASTW_x_xm | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2; + break; + case 2: + if (type & SLJIT_SIMD_FLOAT) { + if ((cpu_feature_list & CPU_FEATURE_AVX2) || ((cpu_feature_list & CPU_FEATURE_AVX) && (src & SLJIT_MEM))) + op = VBROADCASTSS_x_xm | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2; + } else if (cpu_feature_list & CPU_FEATURE_AVX2) + op = VPBROADCASTD_x_xm | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2; + break; + default: +#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) + if (!(type & SLJIT_SIMD_FLOAT)) { + if (cpu_feature_list & CPU_FEATURE_AVX2) + op = VPBROADCASTQ_x_xm | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2; + break; + } +#endif /* SLJIT_CONFIG_X86_64 */ + + if (reg_size == 5) + op = VBROADCASTSD_x_xm | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2; + break; + } + + if (op != 0) { if (!(src & SLJIT_MEM) && !(type & SLJIT_SIMD_FLOAT)) { #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) if (elem_size >= 3) compiler->mode32 = 0; #endif /* SLJIT_CONFIG_X86_64 */ - FAIL_IF(emit_groupf(compiler, MOVD_x_rm | EX86_PREF_66 | EX86_SSE2_OP1, freg, src, srcw)); + FAIL_IF(emit_vex_instruction(compiler, MOVD_x_rm | VEX_AUTO_W | EX86_PREF_66 | EX86_SSE2_OP1, freg, 0, src, srcw)); #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) compiler->mode32 = 1; #endif /* SLJIT_CONFIG_X86_64 */ @@ -3637,51 +3761,40 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_replicate(struct sljit_compil srcw = 0; } - switch (elem_size) { - case 0: - size = VPBROADCASTB_x_xm | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2; - break; - case 1: - size = VPBROADCASTW_x_xm | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2; - break; - case 2: - size = ((type & SLJIT_SIMD_FLOAT) ? VBROADCASTSS_x_xm : VPBROADCASTD_x_xm) | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2; - break; - default: -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - size = VBROADCASTSD_x_xm | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2; -#else /* !SLJIT_CONFIG_X86_32 */ - size = ((type & SLJIT_SIMD_FLOAT) ? VBROADCASTSD_x_xm : VPBROADCASTQ_x_xm) | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2; -#endif /* SLJIT_CONFIG_X86_32 */ - break; - } - if (reg_size == 5) - size |= VEX_256; + op |= VEX_256; - return emit_vex_instruction(compiler, size, freg, 0, src, srcw); + return emit_vex_instruction(compiler, op, freg, 0, src, srcw); } - } else if (reg_size != 4) - return SLJIT_ERR_UNSUPPORTED; - - if (type & SLJIT_SIMD_TEST) - return SLJIT_SUCCESS; + } if (type & SLJIT_SIMD_FLOAT) { if (src == SLJIT_IMM) { - if (reg_size == 5) - return emit_vex_instruction(compiler, XORPD_x_xm | VEX_256 | (elem_size == 3 ? EX86_PREF_66 : 0) | EX86_SSE2 | VEX_SSE2_OPV, freg, freg, freg, 0); + if (use_vex) + return emit_vex_instruction(compiler, XORPD_x_xm | (reg_size == 5 ? VEX_256 : 0) | (elem_size == 3 ? EX86_PREF_66 : 0) | EX86_SSE2 | VEX_SSE2_OPV, freg, freg, freg, 0); return emit_groupf(compiler, XORPD_x_xm | (elem_size == 3 ? EX86_PREF_66 : 0) | EX86_SSE2, freg, freg, 0); } + SLJIT_ASSERT(reg_size == 4); + + if (use_vex) { + if (elem_size == 3) + return emit_vex_instruction(compiler, MOVDDUP_x_xm | EX86_PREF_F2 | EX86_SSE2, freg, 0, src, srcw); + + SLJIT_ASSERT(!(src & SLJIT_MEM)); + FAIL_IF(emit_vex_instruction(compiler, SHUFPS_x_xm | EX86_SSE2 | VEX_SSE2_OPV, freg, src, src, 0)); + return emit_byte(compiler, 0); + } + if (elem_size == 2 && freg != src) { FAIL_IF(emit_sse2_load(compiler, 1, freg, src, srcw)); src = freg; srcw = 0; } - FAIL_IF(emit_groupf(compiler, (elem_size == 2 ? SHUFPS_x_xm : MOVDDUP_x_xm) | (elem_size == 2 ? 0 : EX86_PREF_F2) | EX86_SSE2, freg, src, srcw)); + op = (elem_size == 2 ? SHUFPS_x_xm : MOVDDUP_x_xm) | (elem_size == 2 ? 0 : EX86_PREF_F2) | EX86_SSE2; + FAIL_IF(emit_groupf(compiler, op, freg, src, srcw)); if (elem_size == 2) return emit_byte(compiler, 0); @@ -3706,8 +3819,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_replicate(struct sljit_compil #endif /* SLJIT_CONFIG_X86_64 */ if (srcw == 0 || srcw == -1) { - if (reg_size == 5) - return emit_vex_instruction(compiler, (srcw == 0 ? PXOR_x_xm : PCMPEQD_x_xm) | VEX_256 | EX86_PREF_66 | EX86_SSE2 | VEX_SSE2_OPV, freg, freg, freg, 0); + if (use_vex) + return emit_vex_instruction(compiler, (srcw == 0 ? PXOR_x_xm : PCMPEQD_x_xm) | (reg_size == 5 ? VEX_256 : 0) | EX86_PREF_66 | EX86_SSE2 | VEX_SSE2_OPV, freg, freg, freg, 0); return emit_groupf(compiler, (srcw == 0 ? PXOR_x_xm : PCMPEQD_x_xm) | EX86_PREF_66 | EX86_SSE2, freg, freg, 0); } @@ -3721,16 +3834,17 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_replicate(struct sljit_compil src = TMP_REG1; srcw = 0; + } - size = 2; + op = 2; opcode = MOVD_x_rm; switch (elem_size) { case 0: if (!FAST_IS_REG(src)) { opcode = 0x3a /* Prefix of PINSRB_x_rm_i8. */; - size = 3; + op = 3; } break; case 1: @@ -3747,44 +3861,66 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_replicate(struct sljit_compil #endif /* SLJIT_CONFIG_X86_64 */ } - inst = emit_x86_instruction(compiler, size | EX86_PREF_66 | EX86_SSE2_OP1, freg, 0, src, srcw); - FAIL_IF(!inst); - inst[0] = GROUP_0F; - inst[1] = opcode; + if (use_vex) { + if (opcode != MOVD_x_rm) { + op = (opcode == 0x3a) ? (PINSRB_x_rm_i8 | VEX_OP_0F3A) : opcode; + FAIL_IF(emit_vex_instruction(compiler, op | EX86_PREF_66 | EX86_SSE2_OP1 | VEX_SSE2_OPV, freg, freg, src, srcw)); + } else + FAIL_IF(emit_vex_instruction(compiler, MOVD_x_rm | VEX_AUTO_W | EX86_PREF_66 | EX86_SSE2_OP1, freg, 0, src, srcw)); + } else { + inst = emit_x86_instruction(compiler, op | EX86_PREF_66 | EX86_SSE2_OP1, freg, 0, src, srcw); + FAIL_IF(!inst); + inst[0] = GROUP_0F; + inst[1] = opcode; - if (reg_size == 5) { - SLJIT_ASSERT(opcode == MOVD_x_rm); + if (op == 3) { + SLJIT_ASSERT(opcode == 0x3a); + inst[2] = PINSRB_x_rm_i8; + } + } + + if (use_vex && elem_size >= 2) { #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - size = VPBROADCASTD_x_xm; + op = VPBROADCASTD_x_xm; #else /* !SLJIT_CONFIG_X86_32 */ - size = (elem_size == 3) ? VPBROADCASTQ_x_xm : VPBROADCASTD_x_xm; + op = (elem_size == 3) ? VPBROADCASTQ_x_xm : VPBROADCASTD_x_xm; #endif /* SLJIT_CONFIG_X86_32 */ - return emit_vex_instruction(compiler, size | VEX_256 | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2, freg, 0, freg, 0); + return emit_vex_instruction(compiler, op | ((reg_size == 5) ? VEX_256 : 0) | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2, freg, 0, freg, 0); } - if (size == 3) { - SLJIT_ASSERT(opcode == 0x3a); - inst[2] = PINSRB_x_rm_i8; - } + SLJIT_ASSERT(reg_size == 4); if (opcode != MOVD_x_rm) FAIL_IF(emit_byte(compiler, 0)); switch (elem_size) { case 0: + if (use_vex) { + FAIL_IF(emit_vex_instruction(compiler, PXOR_x_xm | EX86_PREF_66 | EX86_SSE2 | VEX_SSE2_OPV, TMP_FREG, TMP_FREG, TMP_FREG, 0)); + return emit_vex_instruction(compiler, PSHUFB_x_xm | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2 | VEX_SSE2_OPV, freg, freg, TMP_FREG, 0); + } FAIL_IF(emit_groupf(compiler, PXOR_x_xm | EX86_PREF_66 | EX86_SSE2, TMP_FREG, TMP_FREG, 0)); return emit_groupf_ext(compiler, PSHUFB_x_xm | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2, freg, TMP_FREG, 0); case 1: - FAIL_IF(emit_groupf(compiler, PSHUFLW_x_xm | EX86_PREF_F2 | EX86_SSE2, freg, freg, 0)); + if (use_vex) + FAIL_IF(emit_vex_instruction(compiler, PSHUFLW_x_xm | EX86_PREF_F2 | EX86_SSE2, freg, 0, freg, 0)); + else + FAIL_IF(emit_groupf(compiler, PSHUFLW_x_xm | EX86_PREF_F2 | EX86_SSE2, freg, freg, 0)); FAIL_IF(emit_byte(compiler, 0)); /* fallthrough */ default: - FAIL_IF(emit_groupf(compiler, PSHUFD_x_xm | EX86_PREF_66 | EX86_SSE2, freg, freg, 0)); + if (use_vex) + FAIL_IF(emit_vex_instruction(compiler, PSHUFD_x_xm | EX86_PREF_66 | EX86_SSE2, freg, 0, freg, 0)); + else + FAIL_IF(emit_groupf(compiler, PSHUFD_x_xm | EX86_PREF_66 | EX86_SSE2, freg, freg, 0)); return emit_byte(compiler, 0); #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) case 3: compiler->mode32 = 1; - FAIL_IF(emit_groupf(compiler, PSHUFD_x_xm | EX86_PREF_66 | EX86_SSE2, freg, freg, 0)); + if (use_vex) + FAIL_IF(emit_vex_instruction(compiler, PSHUFD_x_xm | EX86_PREF_66 | EX86_SSE2, freg, 0, freg, 0)); + else + FAIL_IF(emit_groupf(compiler, PSHUFD_x_xm | EX86_PREF_66 | EX86_SSE2, freg, freg, 0)); return emit_byte(compiler, 0x44); #endif /* SLJIT_CONFIG_X86_64 */ } @@ -3796,9 +3932,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_mov(struct sljit_compile { sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type); sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type); + sljit_s32 use_vex = (cpu_feature_list & CPU_FEATURE_AVX) && (compiler->options & SLJIT_ENTER_USE_VEX); sljit_u8 *inst; sljit_u8 opcode = 0; - sljit_uw size; + sljit_uw op; sljit_s32 freg_orig = freg; #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) sljit_s32 srcdst_is_ereg = 0; @@ -3814,6 +3951,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_mov(struct sljit_compile if (reg_size == 5) { if (!(cpu_feature_list & CPU_FEATURE_AVX2)) return SLJIT_ERR_UNSUPPORTED; + use_vex = 1; } else if (reg_size != 4) return SLJIT_ERR_UNSUPPORTED; @@ -3865,20 +4003,23 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_mov(struct sljit_compile } if (elem_size == 2) { - if (reg_size == 4) - return emit_groupf(compiler, MOVD_x_rm | EX86_PREF_66 | EX86_SSE2_OP1, freg, srcdst, srcdstw); - return emit_vex_instruction(compiler, MOVD_x_rm | VEX_AUTO_W | EX86_PREF_66 | EX86_SSE2_OP1, freg, 0, srcdst, srcdstw); + if (use_vex) + return emit_vex_instruction(compiler, MOVD_x_rm | VEX_AUTO_W | EX86_PREF_66 | EX86_SSE2_OP1, freg, 0, srcdst, srcdstw); + return emit_groupf(compiler, MOVD_x_rm | EX86_PREF_66 | EX86_SSE2_OP1, freg, srcdst, srcdstw); } } else if (srcdst & SLJIT_MEM) { SLJIT_ASSERT(elem_size == 2 || elem_size == 3); - if (reg_size == 4) - return emit_groupf(compiler, MOVSD_x_xm | (elem_size == 2 ? EX86_PREF_F3 : EX86_PREF_F2) | EX86_SSE2, freg, srcdst, srcdstw); - return emit_vex_instruction(compiler, MOVSD_x_xm | (elem_size == 2 ? EX86_PREF_F3 : EX86_PREF_F2) | EX86_SSE2, freg, 0, srcdst, srcdstw); + if (use_vex) + return emit_vex_instruction(compiler, MOVSD_x_xm | (elem_size == 2 ? EX86_PREF_F3 : EX86_PREF_F2) | EX86_SSE2, freg, 0, srcdst, srcdstw); + return emit_groupf(compiler, MOVSD_x_xm | (elem_size == 2 ? EX86_PREF_F3 : EX86_PREF_F2) | EX86_SSE2, freg, srcdst, srcdstw); } else if (elem_size == 3) { - if (reg_size == 4) - return emit_groupf(compiler, MOVQ_x_xm | EX86_PREF_F3 | EX86_SSE2, freg, srcdst, 0); - return emit_vex_instruction(compiler, MOVQ_x_xm | EX86_PREF_F3 | EX86_SSE2, freg, 0, srcdst, 0); + if (use_vex) + return emit_vex_instruction(compiler, MOVQ_x_xm | EX86_PREF_F3 | EX86_SSE2, freg, 0, srcdst, 0); + return emit_groupf(compiler, MOVQ_x_xm | EX86_PREF_F3 | EX86_SSE2, freg, srcdst, 0); + } else if (use_vex) { + FAIL_IF(emit_vex_instruction(compiler, XORPD_x_xm | EX86_SSE2 | VEX_SSE2_OPV, TMP_FREG, TMP_FREG, TMP_FREG, 0)); + return emit_vex_instruction(compiler, MOVSD_x_xm | EX86_PREF_F3 | EX86_SSE2 | VEX_SSE2_OPV, freg, TMP_FREG, srcdst, 0); } } @@ -3886,18 +4027,21 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_mov(struct sljit_compile freg = TMP_FREG; lane_index -= (1 << (4 - elem_size)); } else if ((type & SLJIT_SIMD_FLOAT) && freg == srcdst) { - FAIL_IF(emit_sse2_load(compiler, elem_size == 2, TMP_FREG, srcdst, srcdstw)); + if (use_vex) + FAIL_IF(emit_vex_instruction(compiler, MOVSD_x_xm | (elem_size == 2 ? EX86_PREF_F3 : EX86_PREF_F2) | EX86_SSE2 | VEX_SSE2_OPV, TMP_FREG, TMP_FREG, srcdst, srcdstw)); + else + FAIL_IF(emit_sse2_load(compiler, elem_size == 2, TMP_FREG, srcdst, srcdstw)); srcdst = TMP_FREG; srcdstw = 0; } - size = ((!(type & SLJIT_SIMD_FLOAT) || elem_size != 2) ? EX86_PREF_66 : 0) + op = ((!(type & SLJIT_SIMD_FLOAT) || elem_size != 2) ? EX86_PREF_66 : 0) | ((type & SLJIT_SIMD_FLOAT) ? XORPD_x_xm : PXOR_x_xm) | EX86_SSE2; - if (reg_size == 5) - FAIL_IF(emit_vex_instruction(compiler, size | VEX_256 | VEX_SSE2_OPV, freg, freg, freg, 0)); + if (use_vex) + FAIL_IF(emit_vex_instruction(compiler, op | (reg_size == 5 ? VEX_256 : 0) | VEX_SSE2_OPV, freg, freg, freg, 0)); else - FAIL_IF(emit_groupf(compiler, size, freg, freg, 0)); + FAIL_IF(emit_groupf(compiler, op, freg, freg, 0)); } else if (reg_size == 5 && lane_index >= (1 << (4 - elem_size))) { FAIL_IF(emit_vex_instruction(compiler, ((type & SLJIT_SIMD_FLOAT) ? VEXTRACTF128_x_ym : VEXTRACTI128_x_ym) | VEX_256 | EX86_PREF_66 | VEX_OP_0F3A | EX86_SSE2, freg, 0, TMP_FREG, 0)); FAIL_IF(emit_byte(compiler, 1)); @@ -3910,58 +4054,80 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_mov(struct sljit_compile if (elem_size == 3) { if (srcdst & SLJIT_MEM) { if (type & SLJIT_SIMD_STORE) - size = lane_index == 0 ? MOVLPD_m_x : MOVHPD_m_x; + op = lane_index == 0 ? MOVLPD_m_x : MOVHPD_m_x; else - size = lane_index == 0 ? MOVLPD_x_m : MOVHPD_x_m; + op = lane_index == 0 ? MOVLPD_x_m : MOVHPD_x_m; - FAIL_IF(emit_groupf(compiler, size | EX86_PREF_66 | EX86_SSE2, freg, srcdst, srcdstw)); + /* VEX prefix clears upper bits of the target register. */ + if (use_vex && ((type & SLJIT_SIMD_STORE) || reg_size == 4 || freg == TMP_FREG)) + FAIL_IF(emit_vex_instruction(compiler, op | EX86_PREF_66 | EX86_SSE2 + | ((type & SLJIT_SIMD_STORE) ? 0 : VEX_SSE2_OPV), freg, (type & SLJIT_SIMD_STORE) ? 0 : freg, srcdst, srcdstw)); + else + FAIL_IF(emit_groupf(compiler, op | EX86_PREF_66 | EX86_SSE2, freg, srcdst, srcdstw)); /* In case of store, freg is not TMP_FREG. */ } else if (type & SLJIT_SIMD_STORE) { - if (lane_index == 1) + if (lane_index == 1) { + if (use_vex) + return emit_vex_instruction(compiler, MOVHLPS_x_x | EX86_SSE2 | VEX_SSE2_OPV, srcdst, srcdst, freg, 0); return emit_groupf(compiler, MOVHLPS_x_x | EX86_SSE2, srcdst, freg, 0); + } + if (use_vex) + return emit_vex_instruction(compiler, MOVSD_x_xm | EX86_PREF_F2 | EX86_SSE2 | VEX_SSE2_OPV, srcdst, srcdst, freg, 0); return emit_sse2_load(compiler, 0, srcdst, freg, 0); + } else if (use_vex && (reg_size == 4 || freg == TMP_FREG)) { + if (lane_index == 1) + FAIL_IF(emit_vex_instruction(compiler, MOVLHPS_x_x | EX86_SSE2 | VEX_SSE2_OPV, freg, freg, srcdst, 0)); + else + FAIL_IF(emit_vex_instruction(compiler, MOVSD_x_xm | EX86_PREF_F2 | EX86_SSE2 | VEX_SSE2_OPV, freg, freg, srcdst, 0)); } else { if (lane_index == 1) FAIL_IF(emit_groupf(compiler, MOVLHPS_x_x | EX86_SSE2, freg, srcdst, 0)); else - FAIL_IF(emit_sse2_store(compiler, 0, freg, 0, srcdst)); + FAIL_IF(emit_sse2_load(compiler, 0, freg, srcdst, 0)); } } else if (type & SLJIT_SIMD_STORE) { - if (lane_index == 0) + if (lane_index == 0) { + if (use_vex) + return emit_vex_instruction(compiler, ((srcdst & SLJIT_MEM) ? MOVSD_xm_x : MOVSD_x_xm) | EX86_PREF_F3 | EX86_SSE2 + | ((srcdst & SLJIT_MEM) ? 0 : VEX_SSE2_OPV), freg, ((srcdst & SLJIT_MEM) ? 0 : freg), srcdst, srcdstw); return emit_sse2_store(compiler, 1, srcdst, srcdstw, freg); + } if (srcdst & SLJIT_MEM) { - FAIL_IF(emit_groupf_ext(compiler, EXTRACTPS_x_xm | EX86_PREF_66 | VEX_OP_0F3A | EX86_SSE2, freg, srcdst, srcdstw)); + if (use_vex) + FAIL_IF(emit_vex_instruction(compiler, EXTRACTPS_x_xm | EX86_PREF_66 | VEX_OP_0F3A | EX86_SSE2, freg, 0, srcdst, srcdstw)); + else + FAIL_IF(emit_groupf_ext(compiler, EXTRACTPS_x_xm | EX86_PREF_66 | VEX_OP_0F3A | EX86_SSE2, freg, srcdst, srcdstw)); + return emit_byte(compiler, U8(lane_index)); + } + + if (use_vex) { + FAIL_IF(emit_vex_instruction(compiler, SHUFPS_x_xm | EX86_SSE2 | VEX_SSE2_OPV, srcdst, freg, freg, 0)); return emit_byte(compiler, U8(lane_index)); } if (srcdst == freg) - size = SHUFPS_x_xm | EX86_SSE2; + op = SHUFPS_x_xm | EX86_SSE2; else { - if (cpu_feature_list & CPU_FEATURE_AVX) { - FAIL_IF(emit_vex_instruction(compiler, SHUFPS_x_xm | EX86_SSE2 | VEX_SSE2_OPV, srcdst, freg, freg, 0)); - return emit_byte(compiler, U8(lane_index)); - } - switch (lane_index) { case 1: - size = MOVSHDUP_x_xm | EX86_PREF_F3 | EX86_SSE2; + op = MOVSHDUP_x_xm | EX86_PREF_F3 | EX86_SSE2; break; case 2: - size = MOVHLPS_x_x | EX86_SSE2; + op = MOVHLPS_x_x | EX86_SSE2; break; default: SLJIT_ASSERT(lane_index == 3); - size = PSHUFD_x_xm | EX86_PREF_66 | EX86_SSE2; + op = PSHUFD_x_xm | EX86_PREF_66 | EX86_SSE2; break; } } - FAIL_IF(emit_groupf(compiler, size, srcdst, freg, 0)); + FAIL_IF(emit_groupf(compiler, op, srcdst, freg, 0)); - size &= 0xff; - if (size == SHUFPS_x_xm || size == PSHUFD_x_xm) + op &= 0xff; + if (op == SHUFPS_x_xm || op == PSHUFD_x_xm) return emit_byte(compiler, U8(lane_index)); return SLJIT_SUCCESS; @@ -3993,7 +4159,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_mov(struct sljit_compile srcdstw = 0; } - size = 3; + op = 3; switch (elem_size) { case 0: @@ -4001,7 +4167,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_mov(struct sljit_compile break; case 1: if (!(type & SLJIT_SIMD_STORE)) { - size = 2; + op = 2; opcode = PINSRW_x_rm_i8; } else opcode = PEXTRW_rm_x_i8; @@ -4018,15 +4184,20 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_mov(struct sljit_compile #endif /* SLJIT_CONFIG_X86_64 */ } - inst = emit_x86_instruction(compiler, size | EX86_PREF_66 | EX86_SSE2_OP1, freg, 0, srcdst, srcdstw); - FAIL_IF(!inst); - inst[0] = GROUP_0F; + if (use_vex && (type & SLJIT_SIMD_STORE)) { + op = opcode | ((op == 3) ? VEX_OP_0F3A : 0); + FAIL_IF(emit_vex_instruction(compiler, op | EX86_PREF_66 | VEX_AUTO_W | EX86_SSE2_OP1 | VEX_SSE2_OPV, freg, 0, srcdst, srcdstw)); + } else { + inst = emit_x86_instruction(compiler, op | EX86_PREF_66 | EX86_SSE2_OP1, freg, 0, srcdst, srcdstw); + FAIL_IF(!inst); + inst[0] = GROUP_0F; - if (size == 3) { - inst[1] = 0x3a; - inst[2] = opcode; - } else - inst[1] = opcode; + if (op == 3) { + inst[1] = 0x3a; + inst[2] = opcode; + } else + inst[1] = opcode; + } FAIL_IF(emit_byte(compiler, U8(lane_index))); @@ -4056,23 +4227,23 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_mov(struct sljit_compile compiler->mode32 = (type & SLJIT_32); - size = 2; + op = 2; if (elem_size == 0) - size |= EX86_REX; + op |= EX86_REX; if (elem_size == 2) { if (type & SLJIT_32) return SLJIT_SUCCESS; SLJIT_ASSERT(!(compiler->mode32)); - size = 1; + op = 1; } - inst = emit_x86_instruction(compiler, size, srcdst, 0, srcdst, 0); + inst = emit_x86_instruction(compiler, op, srcdst, 0, srcdst, 0); FAIL_IF(!inst); - if (size != 1) { + if (op != 1) { inst[0] = GROUP_0F; inst[1] = U8((elem_size == 0) ? MOVSX_r_rm8 : MOVSX_r_rm16); } else @@ -4096,6 +4267,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_replicate(struct sljit_c { sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type); sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type); + sljit_s32 use_vex = (cpu_feature_list & CPU_FEATURE_AVX) && (compiler->options & SLJIT_ENTER_USE_VEX); sljit_uw pref; sljit_u8 byte; #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) @@ -4115,6 +4287,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_replicate(struct sljit_c if (reg_size == 5) { if (!(cpu_feature_list & CPU_FEATURE_AVX2)) return SLJIT_ERR_UNSUPPORTED; + use_vex = 1; } else if (reg_size != 4) return SLJIT_ERR_UNSUPPORTED; @@ -4136,8 +4309,11 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_replicate(struct sljit_c return emit_byte(compiler, U8(byte | (byte << 4))); } - if (src_lane_index == 0) + if (src_lane_index == 0) { + if (use_vex) + return emit_vex_instruction(compiler, MOVDDUP_x_xm | EX86_PREF_F2 | EX86_SSE2, freg, 0, src, 0); return emit_groupf(compiler, MOVDDUP_x_xm | EX86_PREF_F2 | EX86_SSE2, freg, src, 0); + } /* Changes it to SHUFPD_x_xm. */ pref = EX86_PREF_66; @@ -4163,7 +4339,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_replicate(struct sljit_c FAIL_IF(emit_byte(compiler, byte)); FAIL_IF(emit_vex_instruction(compiler, SHUFPS_x_xm | VEX_256 | pref | EX86_SSE2 | VEX_SSE2_OPV, freg, freg, freg, 0)); byte = U8(src_lane_index); - } else if (freg != src && (cpu_feature_list & CPU_FEATURE_AVX)) { + } else if (use_vex) { FAIL_IF(emit_vex_instruction(compiler, SHUFPS_x_xm | pref | EX86_SSE2 | VEX_SSE2_OPV, freg, src, src, 0)); } else { if (freg != src) @@ -4192,7 +4368,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_replicate(struct sljit_c src = freg; } - if ((freg != src && !(cpu_feature_list & CPU_FEATURE_AVX2)) || src_lane_index != 0) { + if (src_lane_index != 0 || (freg != src && (!(cpu_feature_list & CPU_FEATURE_AVX2) || !use_vex))) { pref = 0; if ((src_lane_index & 0x3) == 0) { @@ -4202,7 +4378,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_replicate(struct sljit_c pref = EX86_PREF_F2; byte = U8(src_lane_index >> 1); } else { - if (freg == src || !(cpu_feature_list & CPU_FEATURE_AVX2)) { + if (!use_vex) { if (freg != src) FAIL_IF(emit_groupf(compiler, MOVDQA_x_xm | EX86_PREF_66 | EX86_SSE2, freg, src, 0)); @@ -4214,14 +4390,17 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_replicate(struct sljit_c } if (pref != 0) { - FAIL_IF(emit_groupf(compiler, PSHUFLW_x_xm | pref | EX86_SSE2, freg, src, 0)); + if (use_vex) + FAIL_IF(emit_vex_instruction(compiler, PSHUFLW_x_xm | pref | EX86_SSE2, freg, 0, src, 0)); + else + FAIL_IF(emit_groupf(compiler, PSHUFLW_x_xm | pref | EX86_SSE2, freg, src, 0)); FAIL_IF(emit_byte(compiler, byte)); } src = freg; } - if (cpu_feature_list & CPU_FEATURE_AVX2) + if (use_vex && (cpu_feature_list & CPU_FEATURE_AVX2)) return emit_vex_instruction(compiler, VPBROADCASTB_x_xm | (reg_size == 5 ? VEX_256 : 0) | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2, freg, 0, src, 0); SLJIT_ASSERT(reg_size == 4); @@ -4229,7 +4408,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_replicate(struct sljit_c return emit_groupf_ext(compiler, PSHUFB_x_xm | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2, freg, TMP_FREG, 0); } - if ((cpu_feature_list & CPU_FEATURE_AVX2) && src_lane_index == 0 && elem_size <= 3) { + if ((cpu_feature_list & CPU_FEATURE_AVX2) && use_vex && src_lane_index == 0 && elem_size <= 3) { switch (elem_size) { case 1: pref = VPBROADCASTW_x_xm | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2; @@ -4291,11 +4470,14 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_replicate(struct sljit_c src_lane_index >>= 1; pref = (src_lane_index & 2) == 0 ? EX86_PREF_F2 : EX86_PREF_F3; - FAIL_IF(emit_groupf(compiler, PSHUFLW_x_xm | pref | EX86_SSE2, freg, src, 0)); + if (use_vex) + FAIL_IF(emit_vex_instruction(compiler, PSHUFLW_x_xm | pref | EX86_SSE2, freg, 0, src, 0)); + else + FAIL_IF(emit_groupf(compiler, PSHUFLW_x_xm | pref | EX86_SSE2, freg, src, 0)); byte = U8(byte | (byte << 2)); FAIL_IF(emit_byte(compiler, U8(byte | (byte << 4)))); - if ((cpu_feature_list & CPU_FEATURE_AVX2) && pref == EX86_PREF_F2) + if ((cpu_feature_list & CPU_FEATURE_AVX2) && use_vex && pref == EX86_PREF_F2) return emit_vex_instruction(compiler, VPBROADCASTD_x_xm | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2, freg, 0, freg, 0); src = freg; @@ -4310,7 +4492,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_replicate(struct sljit_c break; } - FAIL_IF(emit_groupf(compiler, PSHUFD_x_xm | EX86_PREF_66 | EX86_SSE2, freg, src, 0)); + if (use_vex) + FAIL_IF(emit_vex_instruction(compiler, PSHUFD_x_xm | EX86_PREF_66 | EX86_SSE2, freg, 0, src, 0)); + else + FAIL_IF(emit_groupf(compiler, PSHUFD_x_xm | EX86_PREF_66 | EX86_SSE2, freg, src, 0)); return emit_byte(compiler, U8(byte | (byte << 4))); } @@ -4321,6 +4506,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_extend(struct sljit_compiler sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type); sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type); sljit_s32 elem2_size = SLJIT_SIMD_GET_ELEM2_SIZE(type); + sljit_s32 use_vex = (cpu_feature_list & CPU_FEATURE_AVX) && (compiler->options & SLJIT_ENTER_USE_VEX); sljit_u8 opcode; CHECK_ERROR(); @@ -4335,6 +4521,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_extend(struct sljit_compiler if (reg_size == 5) { if (!(cpu_feature_list & CPU_FEATURE_AVX2)) return SLJIT_ERR_UNSUPPORTED; + use_vex = 1; } else if (reg_size != 4) return SLJIT_ERR_UNSUPPORTED; @@ -4345,9 +4532,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_extend(struct sljit_compiler if (type & SLJIT_SIMD_TEST) return SLJIT_SUCCESS; - if (reg_size == 4) - return emit_groupf(compiler, CVTPS2PD_x_xm | EX86_SSE2, freg, src, srcw); - return emit_vex_instruction(compiler, CVTPS2PD_x_xm | VEX_256 | EX86_SSE2, freg, 0, src, srcw); + if (use_vex) + return emit_vex_instruction(compiler, CVTPS2PD_x_xm | ((reg_size == 5) ? VEX_256 : 0) | EX86_SSE2, freg, 0, src, srcw); + return emit_groupf(compiler, CVTPS2PD_x_xm | EX86_SSE2, freg, src, srcw); } switch (elem_size) { @@ -4382,9 +4569,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_extend(struct sljit_compiler if (type & SLJIT_SIMD_TEST) return SLJIT_SUCCESS; - if (reg_size == 4) - return emit_groupf_ext(compiler, opcode | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2, freg, src, srcw); - return emit_vex_instruction(compiler, opcode | VEX_256 | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2, freg, 0, src, srcw); + if (use_vex) + return emit_vex_instruction(compiler, opcode | ((reg_size == 5) ? VEX_256 : 0) | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2, freg, 0, src, srcw); + return emit_groupf_ext(compiler, opcode | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2, freg, src, srcw); } SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_sign(struct sljit_compiler *compiler, sljit_s32 type, @@ -4393,8 +4580,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_sign(struct sljit_compiler *c { sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type); sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type); + sljit_s32 use_vex = (cpu_feature_list & CPU_FEATURE_AVX) && (compiler->options & SLJIT_ENTER_USE_VEX); sljit_s32 dst_r; - sljit_uw pref; + sljit_uw op; sljit_u8 *inst; CHECK_ERROR(); @@ -4414,20 +4602,28 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_sign(struct sljit_compiler *c if (type & SLJIT_SIMD_TEST) return SLJIT_SUCCESS; - pref = EX86_PREF_66 | EX86_SSE2_OP2; + op = EX86_PREF_66 | EX86_SSE2_OP2; switch (elem_size) { case 1: - FAIL_IF(emit_groupf(compiler, PACKSSWB_x_xm | EX86_PREF_66 | EX86_SSE2, TMP_FREG, freg, 0)); + if (use_vex) + FAIL_IF(emit_vex_instruction(compiler, PACKSSWB_x_xm | EX86_PREF_66 | EX86_SSE2 | VEX_SSE2_OPV, TMP_FREG, freg, freg, 0)); + else + FAIL_IF(emit_groupf(compiler, PACKSSWB_x_xm | EX86_PREF_66 | EX86_SSE2, TMP_FREG, freg, 0)); freg = TMP_FREG; break; case 2: - pref = EX86_SSE2_OP2; + op = EX86_SSE2_OP2; break; } dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1; - FAIL_IF(emit_groupf(compiler, (elem_size < 2 ? PMOVMSKB_r_x : MOVMSKPS_r_x) | pref, dst_r, freg, 0)); + op |= (elem_size < 2) ? PMOVMSKB_r_x : MOVMSKPS_r_x; + + if (use_vex) + FAIL_IF(emit_vex_instruction(compiler, op, dst_r, 0, freg, 0)); + else + FAIL_IF(emit_groupf(compiler, op, dst_r, freg, 0)); #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) compiler->mode32 = type & SLJIT_32; @@ -4459,14 +4655,14 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_sign(struct sljit_compiler *c FAIL_IF(emit_vex_instruction(compiler, PACKSSWB_x_xm | VEX_256 | EX86_PREF_66 | EX86_SSE2 | VEX_SSE2_OPV, TMP_FREG, freg, TMP_FREG, 0)); FAIL_IF(emit_groupf(compiler, PMOVMSKB_r_x | EX86_PREF_66 | EX86_SSE2_OP2, dst_r, TMP_FREG, 0)); } else { - pref = MOVMSKPS_r_x | VEX_256 | EX86_SSE2_OP2; + op = MOVMSKPS_r_x | VEX_256 | EX86_SSE2_OP2; if (elem_size == 0) - pref = PMOVMSKB_r_x | VEX_256 | EX86_PREF_66 | EX86_SSE2_OP2; + op = PMOVMSKB_r_x | VEX_256 | EX86_PREF_66 | EX86_SSE2_OP2; else if (elem_size == 3) - pref |= EX86_PREF_66; + op |= EX86_PREF_66; - FAIL_IF(emit_vex_instruction(compiler, pref, dst_r, 0, freg, 0)); + FAIL_IF(emit_vex_instruction(compiler, op, dst_r, 0, freg, 0)); } if (dst_r == TMP_REG1) { @@ -4497,7 +4693,6 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_op2(struct sljit_compiler *co { sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type); sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type); - sljit_s32 needs_move = 0; sljit_uw op = 0; CHECK_ERROR(); @@ -4540,20 +4735,18 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_op2(struct sljit_compiler *co if (type & SLJIT_SIMD_TEST) return SLJIT_SUCCESS; - needs_move = dst_freg != src1_freg && dst_freg != src2_freg; - - if (reg_size == 5 || (needs_move && (cpu_feature_list & CPU_FEATURE_AVX2))) { + if (reg_size == 5 || ((cpu_feature_list & CPU_FEATURE_AVX) && (compiler->options & SLJIT_ENTER_USE_VEX))) { if (reg_size == 5) op |= VEX_256; return emit_vex_instruction(compiler, op | EX86_SSE2 | VEX_SSE2_OPV, dst_freg, src1_freg, src2_freg, 0); } - if (needs_move) { - FAIL_IF(emit_simd_mov(compiler, type, dst_freg, src1_freg)); - } else if (dst_freg != src1_freg) { - SLJIT_ASSERT(dst_freg == src2_freg); - src2_freg = src1_freg; + if (dst_freg != src1_freg) { + if (dst_freg == src2_freg) + src2_freg = src1_freg; + else + FAIL_IF(emit_simd_mov(compiler, type, dst_freg, src1_freg)); } FAIL_IF(emit_groupf(compiler, op | EX86_SSE2, dst_freg, src2_freg, 0)); @@ -4727,11 +4920,10 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi return NULL; #endif - inst = (sljit_u8*)ensure_buf(compiler, 2); + inst = (sljit_u8*)ensure_buf(compiler, 1); PTR_FAIL_IF(!inst); - inst[0] = 0; - inst[1] = 2; + inst[0] = SLJIT_INST_CONST; #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) if (dst & SLJIT_MEM) @@ -4742,52 +4934,48 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi return const_; } -SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label* sljit_emit_put_label(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw) +SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_mov_addr(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw) { - struct sljit_put_label *put_label; + struct sljit_jump *jump; sljit_u8 *inst; #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) sljit_s32 reg; - sljit_uw start_size; -#endif +#endif /* SLJIT_CONFIG_X86_64 */ CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_put_label(compiler, dst, dstw)); + CHECK_PTR(check_sljit_emit_mov_addr(compiler, dst, dstw)); ADJUST_LOCAL_OFFSET(dst, dstw); CHECK_EXTRA_REGS(dst, dstw, (void)0); - put_label = (struct sljit_put_label*)ensure_abuf(compiler, sizeof(struct sljit_put_label)); - PTR_FAIL_IF(!put_label); - set_put_label(put_label, compiler, 0); + jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump)); + PTR_FAIL_IF(!jump); + set_mov_addr(jump, compiler, 0); #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) compiler->mode32 = 0; reg = FAST_IS_REG(dst) ? dst : TMP_REG1; - if (emit_load_imm64(compiler, reg, 0)) - return NULL; -#else - if (emit_mov(compiler, dst, dstw, SLJIT_IMM, 0)) - return NULL; -#endif + PTR_FAIL_IF(emit_load_imm64(compiler, reg, 0)); + jump->addr = compiler->size; -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - if (dst & SLJIT_MEM) { - start_size = compiler->size; - if (emit_mov(compiler, dst, dstw, TMP_REG1, 0)) - return NULL; - put_label->flags = compiler->size - start_size; - } -#endif + if (reg_map[reg] >= 8) + jump->flags |= MOV_ADDR_HI; +#else /* !SLJIT_CONFIG_X86_64 */ + PTR_FAIL_IF(emit_mov(compiler, dst, dstw, SLJIT_IMM, 0)); +#endif /* SLJIT_CONFIG_X86_64 */ - inst = (sljit_u8*)ensure_buf(compiler, 2); + inst = (sljit_u8*)ensure_buf(compiler, 1); PTR_FAIL_IF(!inst); - inst[0] = 0; - inst[1] = 3; + inst[0] = SLJIT_INST_MOV_ADDR; + +#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) + if (dst & SLJIT_MEM) + PTR_FAIL_IF(emit_mov(compiler, dst, dstw, TMP_REG1, 0)); +#endif /* SLJIT_CONFIG_X86_64 */ - return put_label; + return jump; } SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset) diff --git a/src/sljit/sljitSerialize.c b/src/sljit/sljitSerialize.c new file mode 100644 index 0000000..6ef161f --- /dev/null +++ b/src/sljit/sljitSerialize.c @@ -0,0 +1,516 @@ +/* + * Stack-less Just-In-Time compiler + * + * Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_jump_has_label(struct sljit_jump *jump) +{ + return !(jump->flags & JUMP_ADDR) && (jump->u.label != NULL); +} + +SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_jump_has_target(struct sljit_jump *jump) +{ + return (jump->flags & JUMP_ADDR) != 0; +} + +SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_jump_is_mov_addr(struct sljit_jump *jump) +{ + return (jump->flags & JUMP_MOV_ADDR) != 0; +} + +#define SLJIT_SERIALIZE_DEBUG ((sljit_u16)0x1) + +struct sljit_serialized_compiler { + sljit_u32 signature; + sljit_u16 version; + sljit_u16 cpu_type; + + sljit_uw buf_segment_count; + sljit_uw label_count; + sljit_uw jump_count; + sljit_uw const_count; + + sljit_s32 options; + sljit_s32 scratches; + sljit_s32 saveds; + sljit_s32 fscratches; + sljit_s32 fsaveds; + sljit_s32 local_size; + sljit_uw size; + +#if (defined SLJIT_HAS_STATUS_FLAGS_STATE && SLJIT_HAS_STATUS_FLAGS_STATE) + sljit_s32 status_flags_state; +#endif /* SLJIT_HAS_STATUS_FLAGS_STATE */ + +#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) + sljit_s32 args_size; +#endif /* SLJIT_CONFIG_X86_32 */ + +#if ((defined SLJIT_CONFIG_ARM_32 && SLJIT_CONFIG_ARM_32) && (defined __SOFTFP__)) \ + || (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) + sljit_uw args_size; +#endif /* (SLJIT_CONFIG_ARM_32 && __SOFTFP__) || SLJIT_CONFIG_MIPS_32 */ + +#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) + sljit_uw cpool_diff; + sljit_uw cpool_fill; + sljit_uw patches; +#endif /* SLJIT_CONFIG_ARM_V6 */ + +#if (defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS) + sljit_s32 delay_slot; +#endif /* SLJIT_CONFIG_MIPS */ + +}; + +struct sljit_serialized_debug_info { + sljit_sw last_flags; + sljit_s32 last_return; + sljit_s32 logical_local_size; +}; + +struct sljit_serialized_label { + sljit_uw size; +}; + +struct sljit_serialized_jump { + sljit_uw addr; + sljit_uw flags; + sljit_uw value; +}; + +struct sljit_serialized_const { + sljit_uw addr; +}; + +#define SLJIT_SERIALIZE_ALIGN(v) (((v) + sizeof(sljit_uw) - 1) & ~(sljit_uw)(sizeof(sljit_uw) - 1)) +#if (defined SLJIT_LITTLE_ENDIAN && SLJIT_LITTLE_ENDIAN) +#define SLJIT_SERIALIZE_SIGNATURE 0x534c4a54 +#else /* !SLJIT_LITTLE_ENDIAN */ +#define SLJIT_SERIALIZE_SIGNATURE 0x544a4c53 +#endif /* SLJIT_LITTLE_ENDIAN */ +#define SLJIT_SERIALIZE_VERSION 1 + +SLJIT_API_FUNC_ATTRIBUTE sljit_uw* sljit_serialize_compiler(struct sljit_compiler *compiler, + sljit_s32 options, sljit_uw *size) +{ + sljit_uw serialized_size = sizeof(struct sljit_serialized_compiler); + struct sljit_memory_fragment *buf; + struct sljit_label *label; + struct sljit_jump *jump; + struct sljit_const *const_; + struct sljit_serialized_compiler *serialized_compiler; + struct sljit_serialized_label *serialized_label; + struct sljit_serialized_jump *serialized_jump; + struct sljit_serialized_const *serialized_const; +#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) \ + || (defined SLJIT_DEBUG && SLJIT_DEBUG) + struct sljit_serialized_debug_info *serialized_debug_info; +#endif /* SLJIT_ARGUMENT_CHECKS || SLJIT_DEBUG */ + sljit_uw counter, used_size; + sljit_u8 *result; + sljit_u8 *ptr; + SLJIT_UNUSED_ARG(options); + + if (size != NULL) + *size = 0; + + PTR_FAIL_IF(compiler->error); + +#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) \ + || (defined SLJIT_DEBUG && SLJIT_DEBUG) + if (!(options & SLJIT_SERIALIZE_IGNORE_DEBUG)) + serialized_size += sizeof(struct sljit_serialized_debug_info); +#endif /* SLJIT_ARGUMENT_CHECKS || SLJIT_DEBUG */ + +#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) + serialized_size += SLJIT_SERIALIZE_ALIGN(compiler->cpool_fill * (sizeof(sljit_uw) + 1)); +#endif /* SLJIT_CONFIG_ARM_V6 */ + + /* Compute the size of the data. */ + buf = compiler->buf; + while (buf != NULL) { + serialized_size += sizeof(sljit_uw) + SLJIT_SERIALIZE_ALIGN(buf->used_size); + buf = buf->next; + } + + serialized_size += compiler->label_count * sizeof(struct sljit_serialized_label); + + jump = compiler->jumps; + while (jump != NULL) { + serialized_size += sizeof(struct sljit_serialized_jump); + jump = jump->next; + } + + const_ = compiler->consts; + while (const_ != NULL) { + serialized_size += sizeof(struct sljit_serialized_const); + const_ = const_->next; + } + + result = (sljit_u8*)SLJIT_MALLOC(serialized_size, compiler->allocator_data); + PTR_FAIL_IF_NULL(result); + + if (size != NULL) + *size = serialized_size; + + ptr = result; + serialized_compiler = (struct sljit_serialized_compiler*)ptr; + ptr += sizeof(struct sljit_serialized_compiler); + + serialized_compiler->signature = SLJIT_SERIALIZE_SIGNATURE; + serialized_compiler->version = SLJIT_SERIALIZE_VERSION; + serialized_compiler->cpu_type = 0; + serialized_compiler->label_count = compiler->label_count; + serialized_compiler->options = compiler->options; + serialized_compiler->scratches = compiler->scratches; + serialized_compiler->saveds = compiler->saveds; + serialized_compiler->fscratches = compiler->fscratches; + serialized_compiler->fsaveds = compiler->fsaveds; + serialized_compiler->local_size = compiler->local_size; + serialized_compiler->size = compiler->size; + +#if (defined SLJIT_HAS_STATUS_FLAGS_STATE && SLJIT_HAS_STATUS_FLAGS_STATE) + serialized_compiler->status_flags_state = compiler->status_flags_state; +#endif /* SLJIT_HAS_STATUS_FLAGS_STATE */ + +#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) \ + || ((defined SLJIT_CONFIG_ARM_32 && SLJIT_CONFIG_ARM_32) && (defined __SOFTFP__)) \ + || (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) + serialized_compiler->args_size = compiler->args_size; +#endif /* SLJIT_CONFIG_X86_32 || (SLJIT_CONFIG_ARM_32 && __SOFTFP__) || SLJIT_CONFIG_MIPS_32 */ + +#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) + serialized_compiler->cpool_diff = compiler->cpool_diff; + serialized_compiler->cpool_fill = compiler->cpool_fill; + serialized_compiler->patches = compiler->patches; + + SLJIT_MEMCPY(ptr, compiler->cpool, compiler->cpool_fill * sizeof(sljit_uw)); + SLJIT_MEMCPY(ptr + compiler->cpool_fill * sizeof(sljit_uw), compiler->cpool_unique, compiler->cpool_fill); + ptr += SLJIT_SERIALIZE_ALIGN(compiler->cpool_fill * (sizeof(sljit_uw) + 1)); +#endif /* SLJIT_CONFIG_ARM_V6 */ + +#if (defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS) + serialized_compiler->delay_slot = compiler->delay_slot; +#endif /* SLJIT_CONFIG_MIPS */ + + buf = compiler->buf; + counter = 0; + while (buf != NULL) { + used_size = buf->used_size; + *(sljit_uw*)ptr = used_size; + ptr += sizeof(sljit_uw); + SLJIT_MEMCPY(ptr, buf->memory, used_size); + ptr += SLJIT_SERIALIZE_ALIGN(used_size); + buf = buf->next; + counter++; + } + serialized_compiler->buf_segment_count = counter; + + label = compiler->labels; + while (label != NULL) { + serialized_label = (struct sljit_serialized_label*)ptr; + serialized_label->size = label->size; + ptr += sizeof(struct sljit_serialized_label); + label = label->next; + } + + jump = compiler->jumps; + counter = 0; + while (jump != NULL) { + serialized_jump = (struct sljit_serialized_jump*)ptr; + serialized_jump->addr = jump->addr; + serialized_jump->flags = jump->flags; + + if (jump->flags & JUMP_ADDR) + serialized_jump->value = jump->u.target; + else if (jump->u.label != NULL) + serialized_jump->value = jump->u.label->u.index; + else + serialized_jump->value = SLJIT_MAX_ADDRESS; + + ptr += sizeof(struct sljit_serialized_jump); + jump = jump->next; + counter++; + } + serialized_compiler->jump_count = counter; + + const_ = compiler->consts; + counter = 0; + while (const_ != NULL) { + serialized_const = (struct sljit_serialized_const*)ptr; + serialized_const->addr = const_->addr; + ptr += sizeof(struct sljit_serialized_const); + const_ = const_->next; + counter++; + } + serialized_compiler->const_count = counter; + +#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) \ + || (defined SLJIT_DEBUG && SLJIT_DEBUG) + if (!(options & SLJIT_SERIALIZE_IGNORE_DEBUG)) { + serialized_debug_info = (struct sljit_serialized_debug_info*)ptr; + serialized_debug_info->last_flags = compiler->last_flags; + serialized_debug_info->last_return = compiler->last_return; + serialized_debug_info->logical_local_size = compiler->logical_local_size; + serialized_compiler->cpu_type |= SLJIT_SERIALIZE_DEBUG; +#if (defined SLJIT_DEBUG && SLJIT_DEBUG) + ptr += sizeof(struct sljit_serialized_debug_info); +#endif /* SLJIT_DEBUG */ + } +#endif /* SLJIT_ARGUMENT_CHECKS || SLJIT_DEBUG */ + + SLJIT_ASSERT((sljit_uw)(ptr - result) == serialized_size); + return (sljit_uw*)result; +} + +SLJIT_API_FUNC_ATTRIBUTE struct sljit_compiler *sljit_deserialize_compiler(sljit_uw* buffer, sljit_uw size, + sljit_s32 options, void *allocator_data) +{ + struct sljit_compiler *compiler; + struct sljit_serialized_compiler *serialized_compiler; + struct sljit_serialized_label *serialized_label; + struct sljit_serialized_jump *serialized_jump; + struct sljit_serialized_const *serialized_const; +#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) \ + || (defined SLJIT_DEBUG && SLJIT_DEBUG) + struct sljit_serialized_debug_info *serialized_debug_info; +#endif /* SLJIT_ARGUMENT_CHECKS || SLJIT_DEBUG */ + struct sljit_memory_fragment *buf; + struct sljit_memory_fragment *last_buf; + struct sljit_label *label; + struct sljit_label *last_label; + struct sljit_label **label_list = NULL; + struct sljit_jump *jump; + struct sljit_jump *last_jump; + struct sljit_const *const_; + struct sljit_const *last_const; + sljit_u8 *ptr = (sljit_u8*)buffer; + sljit_u8 *end = ptr + size; + sljit_uw i, used_size, aligned_size, label_count; + SLJIT_UNUSED_ARG(options); + + if (size < sizeof(struct sljit_serialized_compiler) || (size & (sizeof(sljit_uw) - 1)) != 0) + return NULL; + + serialized_compiler = (struct sljit_serialized_compiler*)ptr; + + if (serialized_compiler->signature != SLJIT_SERIALIZE_SIGNATURE || serialized_compiler->version != SLJIT_SERIALIZE_VERSION) + return NULL; + + compiler = sljit_create_compiler(allocator_data); + PTR_FAIL_IF(compiler == NULL); + + compiler->label_count = serialized_compiler->label_count; + compiler->options = serialized_compiler->options; + compiler->scratches = serialized_compiler->scratches; + compiler->saveds = serialized_compiler->saveds; + compiler->fscratches = serialized_compiler->fscratches; + compiler->fsaveds = serialized_compiler->fsaveds; + compiler->local_size = serialized_compiler->local_size; + compiler->size = serialized_compiler->size; + +#if (defined SLJIT_HAS_STATUS_FLAGS_STATE && SLJIT_HAS_STATUS_FLAGS_STATE) + compiler->status_flags_state = serialized_compiler->status_flags_state; +#endif /* SLJIT_HAS_STATUS_FLAGS_STATE */ + +#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) \ + || ((defined SLJIT_CONFIG_ARM_32 && SLJIT_CONFIG_ARM_32) && (defined __SOFTFP__)) \ + || (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) + compiler->args_size = serialized_compiler->args_size; +#endif /* SLJIT_CONFIG_X86_32 || (SLJIT_CONFIG_ARM_32 && __SOFTFP__) || SLJIT_CONFIG_MIPS_32 */ + +#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) + used_size = serialized_compiler->cpool_fill; + aligned_size = SLJIT_SERIALIZE_ALIGN(used_size * (sizeof(sljit_uw) + 1)); + compiler->cpool_diff = serialized_compiler->cpool_diff; + compiler->cpool_fill = used_size; + compiler->patches = serialized_compiler->patches; + + if ((sljit_uw)(end - ptr) < aligned_size) + goto error; + + SLJIT_MEMCPY(compiler->cpool, ptr, used_size * sizeof(sljit_uw)); + SLJIT_MEMCPY(compiler->cpool_unique, ptr + used_size * sizeof(sljit_uw), used_size); + ptr += aligned_size; +#endif /* SLJIT_CONFIG_ARM_V6 */ + +#if (defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS) + compiler->delay_slot = serialized_compiler->delay_slot; +#endif /* SLJIT_CONFIG_MIPS */ + +#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) \ + || (defined SLJIT_DEBUG && SLJIT_DEBUG) + if (!(serialized_compiler->cpu_type & SLJIT_SERIALIZE_DEBUG)) + goto error; +#endif /* SLJIT_ARGUMENT_CHECKS || SLJIT_DEBUG */ + + ptr += sizeof(struct sljit_serialized_compiler); + i = serialized_compiler->buf_segment_count; + last_buf = NULL; + while (i > 0) { + if ((sljit_uw)(end - ptr) < sizeof(sljit_uw)) + goto error; + + used_size = *(sljit_uw*)ptr; + aligned_size = SLJIT_SERIALIZE_ALIGN(used_size); + ptr += sizeof(sljit_uw); + + if ((sljit_uw)(end - ptr) < aligned_size) + goto error; + + if (last_buf == NULL) { + SLJIT_ASSERT(compiler->buf != NULL && compiler->buf->next == NULL); + buf = compiler->buf; + } else { + buf = (struct sljit_memory_fragment*)SLJIT_MALLOC(BUF_SIZE, allocator_data); + if (!buf) + goto error; + buf->next = NULL; + } + + buf->used_size = used_size; + SLJIT_MEMCPY(buf->memory, ptr, used_size); + + if (last_buf != NULL) + last_buf->next = buf; + last_buf = buf; + + ptr += aligned_size; + i--; + } + + last_label = NULL; + label_count = serialized_compiler->label_count; + if ((sljit_uw)(end - ptr) < label_count * sizeof(struct sljit_serialized_label)) + goto error; + + label_list = (struct sljit_label **)SLJIT_MALLOC(label_count * sizeof(struct sljit_label*), allocator_data); + if (label_list == NULL) + goto error; + + for (i = 0; i < label_count; i++) { + label = (struct sljit_label*)ensure_abuf(compiler, sizeof(struct sljit_label)); + if (label == NULL) + goto error; + + serialized_label = (struct sljit_serialized_label*)ptr; + label->next = NULL; + label->u.index = i; + label->size = serialized_label->size; + + if (last_label != NULL) + last_label->next = label; + else + compiler->labels = label; + last_label = label; + + label_list[i] = label; + ptr += sizeof(struct sljit_serialized_label); + } + compiler->last_label = last_label; + + last_jump = NULL; + i = serialized_compiler->jump_count; + if ((sljit_uw)(end - ptr) < i * sizeof(struct sljit_serialized_jump)) + goto error; + + while (i > 0) { + jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump)); + if (jump == NULL) + goto error; + + serialized_jump = (struct sljit_serialized_jump*)ptr; + jump->next = NULL; + jump->addr = serialized_jump->addr; + jump->flags = serialized_jump->flags; + + if (!(serialized_jump->flags & JUMP_ADDR)) { + if (serialized_jump->value != SLJIT_MAX_ADDRESS) { + if (serialized_jump->value >= label_count) + goto error; + jump->u.label = label_list[serialized_jump->value]; + } else + jump->u.label = NULL; + } else + jump->u.target = serialized_jump->value; + + if (last_jump != NULL) + last_jump->next = jump; + else + compiler->jumps = jump; + last_jump = jump; + + ptr += sizeof(struct sljit_serialized_jump); + i--; + } + compiler->last_jump = last_jump; + + SLJIT_FREE(label_list, allocator_data); + label_list = NULL; + + last_const = NULL; + i = serialized_compiler->const_count; + if ((sljit_uw)(end - ptr) < i * sizeof(struct sljit_serialized_const)) + goto error; + + while (i > 0) { + const_ = (struct sljit_const*)ensure_abuf(compiler, sizeof(struct sljit_const)); + if (const_ == NULL) + goto error; + + serialized_const = (struct sljit_serialized_const*)ptr; + const_->next = NULL; + const_->addr = serialized_const->addr; + + if (last_const != NULL) + last_const->next = const_; + else + compiler->consts = const_; + last_const = const_; + + ptr += sizeof(struct sljit_serialized_const); + i--; + } + compiler->last_const = last_const; + +#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) \ + || (defined SLJIT_DEBUG && SLJIT_DEBUG) + if ((sljit_uw)(end - ptr) < sizeof(struct sljit_serialized_debug_info)) + goto error; + + serialized_debug_info = (struct sljit_serialized_debug_info*)ptr; + compiler->last_flags = (sljit_s32)serialized_debug_info->last_flags; + compiler->last_return = serialized_debug_info->last_return; + compiler->logical_local_size = serialized_debug_info->logical_local_size; +#endif /* SLJIT_ARGUMENT_CHECKS || SLJIT_DEBUG */ + + return compiler; + +error: + sljit_free_compiler(compiler); + if (label_list != NULL) + SLJIT_FREE(label_list, allocator_data); + return NULL; +} diff --git a/testdata/testinput10 b/testdata/testinput10 index e901d51..3190ebc 100644 --- a/testdata/testinput10 +++ b/testdata/testinput10 @@ -487,11 +487,11 @@ # Check name length with non-ASCII characters -/(?'ABáC678901234567890123456789012'...)/utf +/(?'ABáC678901234567890123456789012012345678901234567890123456789AB012345678901234567890123456789AB012345678901234567890123456789AB'...)/utf -/(?'ABáC6789012345678901234567890123'...)/utf +/(?'ABáC6789012345678901234567890123012345678901234567890123456789AB012345678901234567890123456789AB012345678901234567890123456789AB'...)/utf -/(?'ABZC6789012345678901234567890123'...)/utf +/(?'ABZC6789012345678901234567890123012345678901234567890123456789AB012345678901234567890123456789AB012345678901234567890123456789AB'...)/utf /(?(n/utf diff --git a/testdata/testinput2 b/testdata/testinput2 index 9760854..b90489a 100644 --- a/testdata/testinput2 +++ b/testdata/testinput2 @@ -4680,9 +4680,9 @@ B)x/alt_verbnames,mark /(?<=\K.)/g,replace=-,allow_lookaround_bsk ab -/(?'abcdefghijklmnopqrstuvwxyzABCDEFG'toolong)/ +/(?'abcdefghijklmnopqrstuvwxyzABCDEFGabcdefghijklmnopqrstuvwxyzABCDEabcdefghijklmnopqrstuvwxyzABCDEabcdefghijklmnopqrstuvwxyzABCDEFGH'toolong)/ -/(?'abcdefghijklmnopqrstuvwxyzABCDEF'justright)/ +/(?'abcdefghijklmnopqrstuvwxyzABCDEFGabcdefghijklmnopqrstuvwxyzABCDEabcdefghijklmnopqrstuvwxyzABCDEabcdefghijklmnopqrstuvwxyzABCDEFG'justright)/ # These two use zero-termination /abcd/max_pattern_length=3 @@ -4694,6 +4694,9 @@ B)x/alt_verbnames,mark /abcdef/hex,max_pattern_length=3 +# Test compiled length limit +/(abcdefg){10}/max_pattern_compiled_length=100 + # These patterns used to take a long time to compile "(.*) @@ -4949,7 +4952,7 @@ a)"xI /{„Í„Í̈́Í{'{22{2{{2{'{22{{22{2{'{22{2{{2{{222{{2{'{22{2{22{2{'{22{2{{2{'{22{2{22{2{'{'{22{2{22{2{'{22{2{{2{'{22{2{22{2{'{222{2Ą̈́Í̈́Í{'{22{2{{2{'{22{{11{2{'{22{2{{2{{'{22{2{{2{'{22{{22{1{'{22{2{{2{{222{{2{'{22{2{22{2{'{/auto_callout // -\=get=i00000000000000000000000000000000 +\=get=i00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \=get=i2345678901234567890123456789012,get=i1245678901234567890123456789012 "(?(?C))" @@ -6099,4 +6102,13 @@ a)"xI /(a(?1)z||(?1)++)$/ abcd\=disable_recurseloop_check +/(((?<=123?456456|ABC)))(?<=\2)../ + ABCDEFG + 12345645678910 + +# This test is crashing Perl 5.38.2. + +/[^\S\W]{6}/ + .abc def.. + # End of testinput2 diff --git a/testdata/testinput4 b/testdata/testinput4 index 34f187a..2205caf 100644 --- a/testdata/testinput4 +++ b/testdata/testinput4 @@ -1604,6 +1604,15 @@ \x0a\x{1b04}LF, spacingmark \x0b\x{0711}Control, extend \x09\x{1b04}Control, spacingmark + *Test Extended Pictographic after bug fix + \x{261d}\x{261d}B Extended_Pictographic Extended_Pictographic + \x{261D}\x{1F3FB}\x{261d}B Extended_Pictographic Extend E-P + \x{261D}\x{1F3FB}\x{200d}\x{261d}B Extended_Pictographic Extend ZWJ E-P + \x{1f3f3}\x{fe0f}\x{200d}\x{1f308}\x{1f3f4}\x{200d}\x{2620}\x{fe0f}\x{1f3f3}\x{fe0f}\x{200d}\x{1f308}\x{1f3f4}\x{200d}\x{2620}\x{fe0f} + A\x{200d}\x{1f308}B + A\x{200d}B A ZWJ + \x{261D}\x{1F3FB}B Extended_Pictographic Extend + \x{1F1E6}\x{1F1E7}B RegionalIndicator RegionalIndicator *There are no Prepend characters, so we can't test Prepend, CR /^(?>\X{2})X/utf,aftertext diff --git a/testdata/testinput5 b/testdata/testinput5 index 855ecc4..7e04873 100644 --- a/testdata/testinput5 +++ b/testdata/testinput5 @@ -2060,16 +2060,6 @@ (\p{Medefaidrin}+)(\p{Old_Sogdian}+)(\p{Sogdian}+)/x,utf \x{11800}\x{11da9}\x{10d27}\x{11ee0}\x{16e48}\x{10f27}\x{10f30} -# These two are here because of differences from Perl. - -/^\X/utf - A\x{200d}B A ZWJ - \x{261d}\x{261d}B Extended_Pictographic Extended_Pictographic - \x{261D}\x{1F3FB}B Extended_Pictographic Extend - \x{1F1E6}\x{1F1E7}B RegionalIndicator RegionalIndicator - \x{261D}\x{1F3FB}\x{261d}B Extended_Pictographic Extend E-P - \x{261D}\x{1F3FB}\x{200d}\x{261d}B Extended_Pictographic Extend ZWJ E-P - # Regional indicators /^(\X)(\X)/utf,aftertext diff --git a/testdata/testoutput10 b/testdata/testoutput10 index 8145891..1cf7584 100644 --- a/testdata/testoutput10 +++ b/testdata/testoutput10 @@ -1615,12 +1615,12 @@ No match # Check name length with non-ASCII characters -/(?'ABáC678901234567890123456789012'...)/utf +/(?'ABáC678901234567890123456789012012345678901234567890123456789AB012345678901234567890123456789AB012345678901234567890123456789AB'...)/utf -/(?'ABáC6789012345678901234567890123'...)/utf -Failed: error 148 at offset 36: subpattern name is too long (maximum 32 code units) +/(?'ABáC6789012345678901234567890123012345678901234567890123456789AB012345678901234567890123456789AB012345678901234567890123456789AB'...)/utf +Failed: error 148 at offset 132: subpattern name is too long (maximum 128 code units) -/(?'ABZC6789012345678901234567890123'...)/utf +/(?'ABZC6789012345678901234567890123012345678901234567890123456789AB012345678901234567890123456789AB012345678901234567890123456789AB'...)/utf /(?(n/utf Failed: error 142 at offset 4: syntax error in subpattern name (missing terminator?) diff --git a/testdata/testoutput16 b/testdata/testoutput16 index 78d43bd..54c9f18 100644 --- a/testdata/testoutput16 +++ b/testdata/testoutput16 @@ -3,6 +3,7 @@ # are different without JIT. /abc/I,jit,jitverify +JIT compilation was not successful (bad JIT option) Capture group count = 0 First code unit = 'a' Last code unit = 'c' diff --git a/testdata/testoutput17 b/testdata/testoutput17 index ff17d06..00c4bd4 100644 --- a/testdata/testoutput17 +++ b/testdata/testoutput17 @@ -6,6 +6,7 @@ # JIT does not support this pattern (callout at start of condition). /(?(?C1)(?=a)a)/I +JIT compilation was not successful (no more memory) Capture group count = 0 May match empty string Subject length lower bound = 0 @@ -14,6 +15,7 @@ JIT compilation was not successful (no more memory) # The following pattern cannot be compiled by JIT. /b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*/I +JIT compilation was not successful (no more memory) Capture group count = 0 May match empty string Subject length lower bound = 0 diff --git a/testdata/testoutput2 b/testdata/testoutput2 index ee1f70b..8375668 100644 --- a/testdata/testoutput2 +++ b/testdata/testoutput2 @@ -14935,10 +14935,10 @@ Failed: error -60: match with end before start or start moved backwards is not s ab Failed: error -60: match with end before start or start moved backwards is not supported -/(?'abcdefghijklmnopqrstuvwxyzABCDEFG'toolong)/ -Failed: error 148 at offset 36: subpattern name is too long (maximum 32 code units) +/(?'abcdefghijklmnopqrstuvwxyzABCDEFGabcdefghijklmnopqrstuvwxyzABCDEabcdefghijklmnopqrstuvwxyzABCDEabcdefghijklmnopqrstuvwxyzABCDEFGH'toolong)/ +Failed: error 148 at offset 132: subpattern name is too long (maximum 128 code units) -/(?'abcdefghijklmnopqrstuvwxyzABCDEF'justright)/ +/(?'abcdefghijklmnopqrstuvwxyzABCDEFGabcdefghijklmnopqrstuvwxyzABCDEabcdefghijklmnopqrstuvwxyzABCDEabcdefghijklmnopqrstuvwxyzABCDEFG'justright)/ # These two use zero-termination /abcd/max_pattern_length=3 @@ -14952,6 +14952,10 @@ Failed: error 188 at offset 0: pattern string is longer than the limit set by th /abcdef/hex,max_pattern_length=3 +# Test compiled length limit +/(abcdefg){10}/max_pattern_compiled_length=100 +Failed: error 201 at offset 13: compiled pattern would be longer than the limit set by the application + # These patterns used to take a long time to compile "(.*) @@ -15549,7 +15553,7 @@ Failed: error 157 at offset 6: \g is not followed by a braced, angle-bracketed, /{„Í„Í̈́Í{'{22{2{{2{'{22{{22{2{'{22{2{{2{{222{{2{'{22{2{22{2{'{22{2{{2{'{22{2{22{2{'{'{22{2{22{2{'{22{2{{2{'{22{2{22{2{'{222{2Ą̈́Í̈́Í{'{22{2{{2{'{22{{11{2{'{22{2{{2{{'{22{2{{2{'{22{{22{1{'{22{2{{2{{222{{2{'{22{2{22{2{'{/auto_callout // -\=get=i00000000000000000000000000000000 +\=get=i00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ** Group name in 'get' is too long \=get=i2345678901234567890123456789012,get=i1245678901234567890123456789012 ** Too many characters in named 'get' modifiers @@ -18038,6 +18042,22 @@ Failed: error -47: match limit exceeded 0: 1: +/(((?<=123?456456|ABC)))(?<=\2)../ + ABCDEFG + 0: DE + 1: + 2: + 12345645678910 + 0: 78 + 1: + 2: + +# This test is crashing Perl 5.38.2. + +/[^\S\W]{6}/ + .abc def.. +No match + # End of testinput2 Error -70: PCRE2_ERROR_BADDATA (unknown error number) Error -62: bad serialized data diff --git a/testdata/testoutput4 b/testdata/testoutput4 index cb121fa..5917ebb 100644 --- a/testdata/testoutput4 +++ b/testdata/testoutput4 @@ -2668,6 +2668,33 @@ No match \x09\x{1b04}Control, spacingmark 0: \x{09} 0+ \x{1b04}Control, spacingmark + *Test Extended Pictographic after bug fix + 0: * + 0+ Test Extended Pictographic after bug fix + \x{261d}\x{261d}B Extended_Pictographic Extended_Pictographic + 0: \x{261d} + 0+ \x{261d}B Extended_Pictographic Extended_Pictographic + \x{261D}\x{1F3FB}\x{261d}B Extended_Pictographic Extend E-P + 0: \x{261d}\x{1f3fb} + 0+ \x{261d}B Extended_Pictographic Extend E-P + \x{261D}\x{1F3FB}\x{200d}\x{261d}B Extended_Pictographic Extend ZWJ E-P + 0: \x{261d}\x{1f3fb}\x{200d}\x{261d} + 0+ B Extended_Pictographic Extend ZWJ E-P + \x{1f3f3}\x{fe0f}\x{200d}\x{1f308}\x{1f3f4}\x{200d}\x{2620}\x{fe0f}\x{1f3f3}\x{fe0f}\x{200d}\x{1f308}\x{1f3f4}\x{200d}\x{2620}\x{fe0f} + 0: \x{1f3f3}\x{fe0f}\x{200d}\x{1f308} + 0+ \x{1f3f4}\x{200d}\x{2620}\x{fe0f}\x{1f3f3}\x{fe0f}\x{200d}\x{1f308}\x{1f3f4}\x{200d}\x{2620}\x{fe0f} + A\x{200d}\x{1f308}B + 0: A\x{200d} + 0+ \x{1f308}B + A\x{200d}B A ZWJ + 0: A\x{200d} + 0+ B A ZWJ + \x{261D}\x{1F3FB}B Extended_Pictographic Extend + 0: \x{261d}\x{1f3fb} + 0+ B Extended_Pictographic Extend + \x{1F1E6}\x{1F1E7}B RegionalIndicator RegionalIndicator + 0: \x{1f1e6}\x{1f1e7} + 0+ B RegionalIndicator RegionalIndicator *There are no Prepend characters, so we can't test Prepend, CR 0: * 0+ There are no Prepend characters, so we can't test Prepend, CR diff --git a/testdata/testoutput5 b/testdata/testoutput5 index c289c5c..b79959b 100644 --- a/testdata/testoutput5 +++ b/testdata/testoutput5 @@ -4708,22 +4708,6 @@ Callout 0: last capture = 1 6: \x{10f27} 7: \x{10f30} -# These two are here because of differences from Perl. - -/^\X/utf - A\x{200d}B A ZWJ - 0: A\x{200d} - \x{261d}\x{261d}B Extended_Pictographic Extended_Pictographic - 0: \x{261d}\x{261d} - \x{261D}\x{1F3FB}B Extended_Pictographic Extend - 0: \x{261d}\x{1f3fb} - \x{1F1E6}\x{1F1E7}B RegionalIndicator RegionalIndicator - 0: \x{1f1e6}\x{1f1e7} - \x{261D}\x{1F3FB}\x{261d}B Extended_Pictographic Extend E-P - 0: \x{261d}\x{1f3fb}\x{261d} - \x{261D}\x{1F3FB}\x{200d}\x{261d}B Extended_Pictographic Extend ZWJ E-P - 0: \x{261d}\x{1f3fb}\x{200d}\x{261d} - # Regional indicators /^(\X)(\X)/utf,aftertext diff --git a/testdata/testoutput8-16-2 b/testdata/testoutput8-16-2 index 49b1022..bcb9e17 100644 --- a/testdata/testoutput8-16-2 +++ b/testdata/testoutput8-16-2 @@ -10,7 +10,8 @@ #pattern fullbincode,memory /((?i)b)/ -Memory allocation (code space): 24 +Memory allocation - compiled block : 160 +Memory allocation - code portion : 24 ------------------------------------------------------------------ 0 9 Bra 2 5 CBra 1 @@ -21,7 +22,8 @@ Memory allocation (code space): 24 ------------------------------------------------------------------ /(?s)(.*X|^B)/ -Memory allocation (code space): 38 +Memory allocation - compiled block : 174 +Memory allocation - code portion : 38 ------------------------------------------------------------------ 0 16 Bra 2 7 CBra 1 @@ -36,7 +38,8 @@ Memory allocation (code space): 38 ------------------------------------------------------------------ /(?s:.*X|^B)/ -Memory allocation (code space): 36 +Memory allocation - compiled block : 172 +Memory allocation - code portion : 36 ------------------------------------------------------------------ 0 15 Bra 2 6 Bra @@ -51,7 +54,8 @@ Memory allocation (code space): 36 ------------------------------------------------------------------ /^[[:alnum:]]/ -Memory allocation (code space): 46 +Memory allocation - compiled block : 182 +Memory allocation - code portion : 46 ------------------------------------------------------------------ 0 20 Bra 2 ^ @@ -61,7 +65,8 @@ Memory allocation (code space): 46 ------------------------------------------------------------------ /#/Ix -Memory allocation (code space): 10 +Memory allocation - compiled block : 146 +Memory allocation - code portion : 10 ------------------------------------------------------------------ 0 2 Bra 2 2 Ket @@ -73,7 +78,8 @@ Options: extended Subject length lower bound = 0 /a#/Ix -Memory allocation (code space): 14 +Memory allocation - compiled block : 150 +Memory allocation - code portion : 14 ------------------------------------------------------------------ 0 4 Bra 2 a @@ -86,7 +92,8 @@ First code unit = 'a' Subject length lower bound = 1 /x?+/ -Memory allocation (code space): 14 +Memory allocation - compiled block : 150 +Memory allocation - code portion : 14 ------------------------------------------------------------------ 0 4 Bra 2 x?+ @@ -95,7 +102,8 @@ Memory allocation (code space): 14 ------------------------------------------------------------------ /x++/ -Memory allocation (code space): 14 +Memory allocation - compiled block : 150 +Memory allocation - code portion : 14 ------------------------------------------------------------------ 0 4 Bra 2 x++ @@ -104,7 +112,8 @@ Memory allocation (code space): 14 ------------------------------------------------------------------ /x{1,3}+/ -Memory allocation (code space): 20 +Memory allocation - compiled block : 156 +Memory allocation - code portion : 20 ------------------------------------------------------------------ 0 7 Bra 2 x @@ -114,7 +123,8 @@ Memory allocation (code space): 20 ------------------------------------------------------------------ /(x)*+/ -Memory allocation (code space): 26 +Memory allocation - compiled block : 162 +Memory allocation - code portion : 26 ------------------------------------------------------------------ 0 10 Bra 2 Braposzero @@ -126,7 +136,8 @@ Memory allocation (code space): 26 ------------------------------------------------------------------ /^((a+)(?U)([ab]+)(?-U)([bc]+)(\w*))/ -Memory allocation (code space): 142 +Memory allocation - compiled block : 278 +Memory allocation - code portion : 142 ------------------------------------------------------------------ 0 68 Bra 2 ^ @@ -149,7 +160,8 @@ Memory allocation (code space): 142 ------------------------------------------------------------------ "8J\$WE\<\.rX\+ix\[d1b\!H\#\?vV0vrK\:ZH1\=2M\>iV\;\?aPhFB\<\*vW\@QW\@sO9\}cfZA\-i\'w\%hKd6gt1UJP\,15_\#QY\$M\^Mss_U\/\]\&LK9\[5vQub\^w\[KDD\qmj\;2\}YWFdYx\.Ap\]hjCPTP\(n28k\+3\;o\&WXqs\/gOXdr\$\:r\'do0\;b4c\(f_Gr\=\"\\4\)\[01T7ajQJvL\$W\~mL_sS\/4h\:x\*\[ZN\=KLs\&L5zX\/\/\>it\,o\:aU\(\;Z\>pW\&T7oP\'2K\^E\:x9\'c\[\%z\-\,64JQ5AeH_G\#KijUKghQw\^\\vea3a\?kka_G\$8\#\`\*kynsxzBLru\'\]k_\[7FrVx\}\^\=\$blx\>s\-N\%j\;D\*aZDnsw\:YKZ\%Q\.Kne9\#hP\?\+b3\(SOvL\,\^\;\&u5\@\?5C5Bhb\=m\-vEh_L15Jl\]U\)0RP6\{q\%L\^_z5E\'Dw6X\b" -Memory allocation (code space): 1648 +Memory allocation - compiled block : 1784 +Memory allocation - code portion : 1648 ------------------------------------------------------------------ 0 821 Bra 2 8J$WE<.rX+ix[d1b!H#?vV0vrK:ZH1=2M>iV;?aPhFB<*vW@QW@sO9}cfZA-i'w%hKd6gt1UJP,15_#QY$M^Mss_U/]&LK9[5vQub^w[KDDqmj;2}YWFdYx.Ap]hjCPTP(n28k+3;o&WXqs/gOXdr$:r'do0;b4c(f_Gr="\4)[01T7ajQJvL$W~mL_sS/4h:x*[ZN=KLs&L5zX//>it,o:aU(;Z>pW&T7oP'2K^E:x9'c[%z-,64JQ5AeH_G#KijUKghQw^\vea3a?kka_G$8#`*kynsxzBLru']k_[7FrVx}^=$blx>s-N%j;D*aZDnsw:YKZ%Q.Kne9#hP?+b3(SOvL,^;&u5@?5C5Bhb=m-vEh_L15Jl]U)0RP6{q%L^_z5E'Dw6X @@ -159,7 +171,8 @@ Memory allocation (code space): 1648 ------------------------------------------------------------------ "\$\<\.X\+ix\[d1b\!H\#\?vV0vrK\:ZH1\=2M\>iV\;\?aPhFB\<\*vW\@QW\@sO9\}cfZA\-i\'w\%hKd6gt1UJP\,15_\#QY\$M\^Mss_U\/\]\&LK9\[5vQub\^w\[KDD\qmj\;2\}YWFdYx\.Ap\]hjCPTP\(n28k\+3\;o\&WXqs\/gOXdr\$\:r\'do0\;b4c\(f_Gr\=\"\\4\)\[01T7ajQJvL\$W\~mL_sS\/4h\:x\*\[ZN\=KLs\&L5zX\/\/\>it\,o\:aU\(\;Z\>pW\&T7oP\'2K\^E\:x9\'c\[\%z\-\,64JQ5AeH_G\#KijUKghQw\^\\vea3a\?kka_G\$8\#\`\*kynsxzBLru\'\]k_\[7FrVx\}\^\=\$blx\>s\-N\%j\;D\*aZDnsw\:YKZ\%Q\.Kne9\#hP\?\+b3\(SOvL\,\^\;\&u5\@\?5C5Bhb\=m\-vEh_L15Jl\]U\)0RP6\{q\%L\^_z5E\'Dw6X\b" -Memory allocation (code space): 1628 +Memory allocation - compiled block : 1764 +Memory allocation - code portion : 1628 ------------------------------------------------------------------ 0 811 Bra 2 $<.X+ix[d1b!H#?vV0vrK:ZH1=2M>iV;?aPhFB<*vW@QW@sO9}cfZA-i'w%hKd6gt1UJP,15_#QY$M^Mss_U/]&LK9[5vQub^w[KDDqmj;2}YWFdYx.Ap]hjCPTP(n28k+3;o&WXqs/gOXdr$:r'do0;b4c(f_Gr="\4)[01T7ajQJvL$W~mL_sS/4h:x*[ZN=KLs&L5zX//>it,o:aU(;Z>pW&T7oP'2K^E:x9'c[%z-,64JQ5AeH_G#KijUKghQw^\vea3a?kka_G$8#`*kynsxzBLru']k_[7FrVx}^=$blx>s-N%j;D*aZDnsw:YKZ%Q.Kne9#hP?+b3(SOvL,^;&u5@?5C5Bhb=m-vEh_L15Jl]U)0RP6{q%L^_z5E'Dw6X @@ -169,7 +182,8 @@ Memory allocation (code space): 1628 ------------------------------------------------------------------ /(a(?1)b)/ -Memory allocation (code space): 32 +Memory allocation - compiled block : 168 +Memory allocation - code portion : 32 ------------------------------------------------------------------ 0 13 Bra 2 9 CBra 1 @@ -182,7 +196,8 @@ Memory allocation (code space): 32 ------------------------------------------------------------------ /(a(?1)+b)/ -Memory allocation (code space): 40 +Memory allocation - compiled block : 176 +Memory allocation - code portion : 40 ------------------------------------------------------------------ 0 17 Bra 2 13 CBra 1 @@ -197,7 +212,8 @@ Memory allocation (code space): 40 ------------------------------------------------------------------ /a(?Pb|c)d(?Pe)/ -Memory allocation (code space): 54 +Memory allocation - compiled block : 242 +Memory allocation - code portion : 54 ------------------------------------------------------------------ 0 24 Bra 2 a @@ -215,7 +231,8 @@ Memory allocation (code space): 54 ------------------------------------------------------------------ /(?:a(?Pc(?Pd)))(?Pa)/ -Memory allocation (code space): 64 +Memory allocation - compiled block : 218 +Memory allocation - code portion : 64 ------------------------------------------------------------------ 0 29 Bra 2 18 Bra @@ -235,7 +252,8 @@ Memory allocation (code space): 64 ------------------------------------------------------------------ /(?Pa)...(?P=a)bbb(?P>a)d/ -Memory allocation (code space): 54 +Memory allocation - compiled block : 196 +Memory allocation - code portion : 54 ------------------------------------------------------------------ 0 24 Bra 2 5 CBra 1 @@ -253,7 +271,8 @@ Memory allocation (code space): 54 ------------------------------------------------------------------ /abc(?C255)de(?C)f/ -Memory allocation (code space): 50 +Memory allocation - compiled block : 186 +Memory allocation - code portion : 50 ------------------------------------------------------------------ 0 22 Bra 2 abc @@ -266,7 +285,8 @@ Memory allocation (code space): 50 ------------------------------------------------------------------ /abcde/auto_callout -Memory allocation (code space): 78 +Memory allocation - compiled block : 214 +Memory allocation - code portion : 78 ------------------------------------------------------------------ 0 36 Bra 2 Callout 255 0 1 @@ -285,7 +305,8 @@ Memory allocation (code space): 78 ------------------------------------------------------------------ /\x{100}/utf -Memory allocation (code space): 14 +Memory allocation - compiled block : 150 +Memory allocation - code portion : 14 ------------------------------------------------------------------ 0 4 Bra 2 \x{100} @@ -294,7 +315,8 @@ Memory allocation (code space): 14 ------------------------------------------------------------------ /\x{1000}/utf -Memory allocation (code space): 14 +Memory allocation - compiled block : 150 +Memory allocation - code portion : 14 ------------------------------------------------------------------ 0 4 Bra 2 \x{1000} @@ -303,7 +325,8 @@ Memory allocation (code space): 14 ------------------------------------------------------------------ /\x{10000}/utf -Memory allocation (code space): 16 +Memory allocation - compiled block : 152 +Memory allocation - code portion : 16 ------------------------------------------------------------------ 0 5 Bra 2 \x{10000} @@ -312,7 +335,8 @@ Memory allocation (code space): 16 ------------------------------------------------------------------ /\x{100000}/utf -Memory allocation (code space): 16 +Memory allocation - compiled block : 152 +Memory allocation - code portion : 16 ------------------------------------------------------------------ 0 5 Bra 2 \x{100000} @@ -321,7 +345,8 @@ Memory allocation (code space): 16 ------------------------------------------------------------------ /\x{10ffff}/utf -Memory allocation (code space): 16 +Memory allocation - compiled block : 152 +Memory allocation - code portion : 16 ------------------------------------------------------------------ 0 5 Bra 2 \x{10ffff} @@ -333,7 +358,8 @@ Memory allocation (code space): 16 Failed: error 134 at offset 9: character code point value in \x{} or \o{} is too large /[\x{ff}]/utf -Memory allocation (code space): 14 +Memory allocation - compiled block : 150 +Memory allocation - code portion : 14 ------------------------------------------------------------------ 0 4 Bra 2 \x{ff} @@ -342,7 +368,8 @@ Memory allocation (code space): 14 ------------------------------------------------------------------ /[\x{100}]/utf -Memory allocation (code space): 14 +Memory allocation - compiled block : 150 +Memory allocation - code portion : 14 ------------------------------------------------------------------ 0 4 Bra 2 \x{100} @@ -351,7 +378,8 @@ Memory allocation (code space): 14 ------------------------------------------------------------------ /\x80/utf -Memory allocation (code space): 14 +Memory allocation - compiled block : 150 +Memory allocation - code portion : 14 ------------------------------------------------------------------ 0 4 Bra 2 \x{80} @@ -360,7 +388,8 @@ Memory allocation (code space): 14 ------------------------------------------------------------------ /\xff/utf -Memory allocation (code space): 14 +Memory allocation - compiled block : 150 +Memory allocation - code portion : 14 ------------------------------------------------------------------ 0 4 Bra 2 \x{ff} @@ -369,7 +398,8 @@ Memory allocation (code space): 14 ------------------------------------------------------------------ /\x{0041}\x{2262}\x{0391}\x{002e}/I,utf -Memory allocation (code space): 26 +Memory allocation - compiled block : 162 +Memory allocation - code portion : 26 ------------------------------------------------------------------ 0 10 Bra 2 A\x{2262}\x{391}. @@ -383,7 +413,8 @@ Last code unit = '.' Subject length lower bound = 4 /\x{D55c}\x{ad6d}\x{C5B4}/I,utf -Memory allocation (code space): 22 +Memory allocation - compiled block : 158 +Memory allocation - code portion : 22 ------------------------------------------------------------------ 0 8 Bra 2 \x{d55c}\x{ad6d}\x{c5b4} @@ -397,7 +428,8 @@ Last code unit = \x{c5b4} Subject length lower bound = 3 /\x{65e5}\x{672c}\x{8a9e}/I,utf -Memory allocation (code space): 22 +Memory allocation - compiled block : 158 +Memory allocation - code portion : 22 ------------------------------------------------------------------ 0 8 Bra 2 \x{65e5}\x{672c}\x{8a9e} @@ -411,7 +443,8 @@ Last code unit = \x{8a9e} Subject length lower bound = 3 /[\x{100}]/utf -Memory allocation (code space): 14 +Memory allocation - compiled block : 150 +Memory allocation - code portion : 14 ------------------------------------------------------------------ 0 4 Bra 2 \x{100} @@ -420,7 +453,8 @@ Memory allocation (code space): 14 ------------------------------------------------------------------ /[Z\x{100}]/utf -Memory allocation (code space): 54 +Memory allocation - compiled block : 190 +Memory allocation - code portion : 54 ------------------------------------------------------------------ 0 24 Bra 2 [Z\x{100}] @@ -429,7 +463,8 @@ Memory allocation (code space): 54 ------------------------------------------------------------------ /^[\x{100}\E-\Q\E\x{150}]/utf -Memory allocation (code space): 26 +Memory allocation - compiled block : 162 +Memory allocation - code portion : 26 ------------------------------------------------------------------ 0 10 Bra 2 ^ @@ -439,7 +474,8 @@ Memory allocation (code space): 26 ------------------------------------------------------------------ /^[\QĀ\E-\QŐ\E]/utf -Memory allocation (code space): 26 +Memory allocation - compiled block : 162 +Memory allocation - code portion : 26 ------------------------------------------------------------------ 0 10 Bra 2 ^ @@ -452,7 +488,8 @@ Memory allocation (code space): 26 Failed: error 106 at offset 13: missing terminating ] for character class /[\p{L}]/ -Memory allocation (code space): 24 +Memory allocation - compiled block : 160 +Memory allocation - code portion : 24 ------------------------------------------------------------------ 0 9 Bra 2 [\p{L}] @@ -461,7 +498,8 @@ Memory allocation (code space): 24 ------------------------------------------------------------------ /[\p{^L}]/ -Memory allocation (code space): 24 +Memory allocation - compiled block : 160 +Memory allocation - code portion : 24 ------------------------------------------------------------------ 0 9 Bra 2 [\P{L}] @@ -470,7 +508,8 @@ Memory allocation (code space): 24 ------------------------------------------------------------------ /[\P{L}]/ -Memory allocation (code space): 24 +Memory allocation - compiled block : 160 +Memory allocation - code portion : 24 ------------------------------------------------------------------ 0 9 Bra 2 [\P{L}] @@ -479,7 +518,8 @@ Memory allocation (code space): 24 ------------------------------------------------------------------ /[\P{^L}]/ -Memory allocation (code space): 24 +Memory allocation - compiled block : 160 +Memory allocation - code portion : 24 ------------------------------------------------------------------ 0 9 Bra 2 [\p{L}] @@ -488,7 +528,8 @@ Memory allocation (code space): 24 ------------------------------------------------------------------ /[abc\p{L}\x{0660}]/utf -Memory allocation (code space): 60 +Memory allocation - compiled block : 196 +Memory allocation - code portion : 60 ------------------------------------------------------------------ 0 27 Bra 2 [a-c\p{L}\x{660}] @@ -497,7 +538,8 @@ Memory allocation (code space): 60 ------------------------------------------------------------------ /[\p{Nd}]/utf -Memory allocation (code space): 24 +Memory allocation - compiled block : 160 +Memory allocation - code portion : 24 ------------------------------------------------------------------ 0 9 Bra 2 [\p{Nd}] @@ -506,7 +548,8 @@ Memory allocation (code space): 24 ------------------------------------------------------------------ /[\p{Nd}+-]+/utf -Memory allocation (code space): 58 +Memory allocation - compiled block : 194 +Memory allocation - code portion : 58 ------------------------------------------------------------------ 0 26 Bra 2 [+\-\p{Nd}]++ @@ -515,7 +558,8 @@ Memory allocation (code space): 58 ------------------------------------------------------------------ /A\x{391}\x{10427}\x{ff3a}\x{1fb0}/i,utf -Memory allocation (code space): 32 +Memory allocation - compiled block : 168 +Memory allocation - code portion : 32 ------------------------------------------------------------------ 0 13 Bra 2 /i A\x{391}\x{10427}\x{ff3a}\x{1fb0} @@ -524,7 +568,8 @@ Memory allocation (code space): 32 ------------------------------------------------------------------ /A\x{391}\x{10427}\x{ff3a}\x{1fb0}/utf -Memory allocation (code space): 32 +Memory allocation - compiled block : 168 +Memory allocation - code portion : 32 ------------------------------------------------------------------ 0 13 Bra 2 A\x{391}\x{10427}\x{ff3a}\x{1fb0} @@ -533,7 +578,8 @@ Memory allocation (code space): 32 ------------------------------------------------------------------ /[\x{105}-\x{109}]/i,utf -Memory allocation (code space): 24 +Memory allocation - compiled block : 160 +Memory allocation - code portion : 24 ------------------------------------------------------------------ 0 9 Bra 2 [\x{104}-\x{109}] @@ -542,7 +588,8 @@ Memory allocation (code space): 24 ------------------------------------------------------------------ /( ( (?(1)0|) )* )/x -Memory allocation (code space): 52 +Memory allocation - compiled block : 188 +Memory allocation - code portion : 52 ------------------------------------------------------------------ 0 23 Bra 2 19 CBra 1 @@ -560,7 +607,8 @@ Memory allocation (code space): 52 ------------------------------------------------------------------ /( (?(1)0|)* )/x -Memory allocation (code space): 42 +Memory allocation - compiled block : 178 +Memory allocation - code portion : 42 ------------------------------------------------------------------ 0 18 Bra 2 14 CBra 1 @@ -576,7 +624,8 @@ Memory allocation (code space): 42 ------------------------------------------------------------------ /[a]/ -Memory allocation (code space): 14 +Memory allocation - compiled block : 150 +Memory allocation - code portion : 14 ------------------------------------------------------------------ 0 4 Bra 2 a @@ -585,7 +634,8 @@ Memory allocation (code space): 14 ------------------------------------------------------------------ /[a]/utf -Memory allocation (code space): 14 +Memory allocation - compiled block : 150 +Memory allocation - code portion : 14 ------------------------------------------------------------------ 0 4 Bra 2 a @@ -594,7 +644,8 @@ Memory allocation (code space): 14 ------------------------------------------------------------------ /[\xaa]/ -Memory allocation (code space): 14 +Memory allocation - compiled block : 150 +Memory allocation - code portion : 14 ------------------------------------------------------------------ 0 4 Bra 2 \x{aa} @@ -603,7 +654,8 @@ Memory allocation (code space): 14 ------------------------------------------------------------------ /[\xaa]/utf -Memory allocation (code space): 14 +Memory allocation - compiled block : 150 +Memory allocation - code portion : 14 ------------------------------------------------------------------ 0 4 Bra 2 \x{aa} @@ -612,7 +664,8 @@ Memory allocation (code space): 14 ------------------------------------------------------------------ /[^a]/ -Memory allocation (code space): 14 +Memory allocation - compiled block : 150 +Memory allocation - code portion : 14 ------------------------------------------------------------------ 0 4 Bra 2 [^a] @@ -621,7 +674,8 @@ Memory allocation (code space): 14 ------------------------------------------------------------------ /[^a]/utf -Memory allocation (code space): 14 +Memory allocation - compiled block : 150 +Memory allocation - code portion : 14 ------------------------------------------------------------------ 0 4 Bra 2 [^a] @@ -630,7 +684,8 @@ Memory allocation (code space): 14 ------------------------------------------------------------------ /[^\xaa]/ -Memory allocation (code space): 14 +Memory allocation - compiled block : 150 +Memory allocation - code portion : 14 ------------------------------------------------------------------ 0 4 Bra 2 [^\x{aa}] @@ -639,7 +694,8 @@ Memory allocation (code space): 14 ------------------------------------------------------------------ /[^\xaa]/utf -Memory allocation (code space): 14 +Memory allocation - compiled block : 150 +Memory allocation - code portion : 14 ------------------------------------------------------------------ 0 4 Bra 2 [^\x{aa}] diff --git a/testdata/testoutput8-16-3 b/testdata/testoutput8-16-3 index 80ee1c9..4ec13ea 100644 --- a/testdata/testoutput8-16-3 +++ b/testdata/testoutput8-16-3 @@ -10,7 +10,8 @@ #pattern fullbincode,memory /((?i)b)/ -Memory allocation (code space): 32 +Memory allocation - compiled block : 168 +Memory allocation - code portion : 32 ------------------------------------------------------------------ 0 12 Bra 3 6 CBra 1 @@ -21,7 +22,8 @@ Memory allocation (code space): 32 ------------------------------------------------------------------ /(?s)(.*X|^B)/ -Memory allocation (code space): 48 +Memory allocation - compiled block : 184 +Memory allocation - code portion : 48 ------------------------------------------------------------------ 0 20 Bra 3 8 CBra 1 @@ -36,7 +38,8 @@ Memory allocation (code space): 48 ------------------------------------------------------------------ /(?s:.*X|^B)/ -Memory allocation (code space): 46 +Memory allocation - compiled block : 182 +Memory allocation - code portion : 46 ------------------------------------------------------------------ 0 19 Bra 3 7 Bra @@ -51,7 +54,8 @@ Memory allocation (code space): 46 ------------------------------------------------------------------ /^[[:alnum:]]/ -Memory allocation (code space): 50 +Memory allocation - compiled block : 186 +Memory allocation - code portion : 50 ------------------------------------------------------------------ 0 21 Bra 3 ^ @@ -61,7 +65,8 @@ Memory allocation (code space): 50 ------------------------------------------------------------------ /#/Ix -Memory allocation (code space): 14 +Memory allocation - compiled block : 150 +Memory allocation - code portion : 14 ------------------------------------------------------------------ 0 3 Bra 3 3 Ket @@ -73,7 +78,8 @@ Options: extended Subject length lower bound = 0 /a#/Ix -Memory allocation (code space): 18 +Memory allocation - compiled block : 154 +Memory allocation - code portion : 18 ------------------------------------------------------------------ 0 5 Bra 3 a @@ -86,7 +92,8 @@ First code unit = 'a' Subject length lower bound = 1 /x?+/ -Memory allocation (code space): 18 +Memory allocation - compiled block : 154 +Memory allocation - code portion : 18 ------------------------------------------------------------------ 0 5 Bra 3 x?+ @@ -95,7 +102,8 @@ Memory allocation (code space): 18 ------------------------------------------------------------------ /x++/ -Memory allocation (code space): 18 +Memory allocation - compiled block : 154 +Memory allocation - code portion : 18 ------------------------------------------------------------------ 0 5 Bra 3 x++ @@ -104,7 +112,8 @@ Memory allocation (code space): 18 ------------------------------------------------------------------ /x{1,3}+/ -Memory allocation (code space): 24 +Memory allocation - compiled block : 160 +Memory allocation - code portion : 24 ------------------------------------------------------------------ 0 8 Bra 3 x @@ -114,7 +123,8 @@ Memory allocation (code space): 24 ------------------------------------------------------------------ /(x)*+/ -Memory allocation (code space): 34 +Memory allocation - compiled block : 170 +Memory allocation - code portion : 34 ------------------------------------------------------------------ 0 13 Bra 3 Braposzero @@ -126,7 +136,8 @@ Memory allocation (code space): 34 ------------------------------------------------------------------ /^((a+)(?U)([ab]+)(?-U)([bc]+)(\w*))/ -Memory allocation (code space): 166 +Memory allocation - compiled block : 302 +Memory allocation - code portion : 166 ------------------------------------------------------------------ 0 79 Bra 3 ^ @@ -149,7 +160,8 @@ Memory allocation (code space): 166 ------------------------------------------------------------------ "8J\$WE\<\.rX\+ix\[d1b\!H\#\?vV0vrK\:ZH1\=2M\>iV\;\?aPhFB\<\*vW\@QW\@sO9\}cfZA\-i\'w\%hKd6gt1UJP\,15_\#QY\$M\^Mss_U\/\]\&LK9\[5vQub\^w\[KDD\qmj\;2\}YWFdYx\.Ap\]hjCPTP\(n28k\+3\;o\&WXqs\/gOXdr\$\:r\'do0\;b4c\(f_Gr\=\"\\4\)\[01T7ajQJvL\$W\~mL_sS\/4h\:x\*\[ZN\=KLs\&L5zX\/\/\>it\,o\:aU\(\;Z\>pW\&T7oP\'2K\^E\:x9\'c\[\%z\-\,64JQ5AeH_G\#KijUKghQw\^\\vea3a\?kka_G\$8\#\`\*kynsxzBLru\'\]k_\[7FrVx\}\^\=\$blx\>s\-N\%j\;D\*aZDnsw\:YKZ\%Q\.Kne9\#hP\?\+b3\(SOvL\,\^\;\&u5\@\?5C5Bhb\=m\-vEh_L15Jl\]U\)0RP6\{q\%L\^_z5E\'Dw6X\b" -Memory allocation (code space): 1652 +Memory allocation - compiled block : 1788 +Memory allocation - code portion : 1652 ------------------------------------------------------------------ 0 822 Bra 3 8J$WE<.rX+ix[d1b!H#?vV0vrK:ZH1=2M>iV;?aPhFB<*vW@QW@sO9}cfZA-i'w%hKd6gt1UJP,15_#QY$M^Mss_U/]&LK9[5vQub^w[KDDqmj;2}YWFdYx.Ap]hjCPTP(n28k+3;o&WXqs/gOXdr$:r'do0;b4c(f_Gr="\4)[01T7ajQJvL$W~mL_sS/4h:x*[ZN=KLs&L5zX//>it,o:aU(;Z>pW&T7oP'2K^E:x9'c[%z-,64JQ5AeH_G#KijUKghQw^\vea3a?kka_G$8#`*kynsxzBLru']k_[7FrVx}^=$blx>s-N%j;D*aZDnsw:YKZ%Q.Kne9#hP?+b3(SOvL,^;&u5@?5C5Bhb=m-vEh_L15Jl]U)0RP6{q%L^_z5E'Dw6X @@ -159,7 +171,8 @@ Memory allocation (code space): 1652 ------------------------------------------------------------------ "\$\<\.X\+ix\[d1b\!H\#\?vV0vrK\:ZH1\=2M\>iV\;\?aPhFB\<\*vW\@QW\@sO9\}cfZA\-i\'w\%hKd6gt1UJP\,15_\#QY\$M\^Mss_U\/\]\&LK9\[5vQub\^w\[KDD\qmj\;2\}YWFdYx\.Ap\]hjCPTP\(n28k\+3\;o\&WXqs\/gOXdr\$\:r\'do0\;b4c\(f_Gr\=\"\\4\)\[01T7ajQJvL\$W\~mL_sS\/4h\:x\*\[ZN\=KLs\&L5zX\/\/\>it\,o\:aU\(\;Z\>pW\&T7oP\'2K\^E\:x9\'c\[\%z\-\,64JQ5AeH_G\#KijUKghQw\^\\vea3a\?kka_G\$8\#\`\*kynsxzBLru\'\]k_\[7FrVx\}\^\=\$blx\>s\-N\%j\;D\*aZDnsw\:YKZ\%Q\.Kne9\#hP\?\+b3\(SOvL\,\^\;\&u5\@\?5C5Bhb\=m\-vEh_L15Jl\]U\)0RP6\{q\%L\^_z5E\'Dw6X\b" -Memory allocation (code space): 1632 +Memory allocation - compiled block : 1768 +Memory allocation - code portion : 1632 ------------------------------------------------------------------ 0 812 Bra 3 $<.X+ix[d1b!H#?vV0vrK:ZH1=2M>iV;?aPhFB<*vW@QW@sO9}cfZA-i'w%hKd6gt1UJP,15_#QY$M^Mss_U/]&LK9[5vQub^w[KDDqmj;2}YWFdYx.Ap]hjCPTP(n28k+3;o&WXqs/gOXdr$:r'do0;b4c(f_Gr="\4)[01T7ajQJvL$W~mL_sS/4h:x*[ZN=KLs&L5zX//>it,o:aU(;Z>pW&T7oP'2K^E:x9'c[%z-,64JQ5AeH_G#KijUKghQw^\vea3a?kka_G$8#`*kynsxzBLru']k_[7FrVx}^=$blx>s-N%j;D*aZDnsw:YKZ%Q.Kne9#hP?+b3(SOvL,^;&u5@?5C5Bhb=m-vEh_L15Jl]U)0RP6{q%L^_z5E'Dw6X @@ -169,7 +182,8 @@ Memory allocation (code space): 1632 ------------------------------------------------------------------ /(a(?1)b)/ -Memory allocation (code space): 42 +Memory allocation - compiled block : 178 +Memory allocation - code portion : 42 ------------------------------------------------------------------ 0 17 Bra 3 11 CBra 1 @@ -182,7 +196,8 @@ Memory allocation (code space): 42 ------------------------------------------------------------------ /(a(?1)+b)/ -Memory allocation (code space): 54 +Memory allocation - compiled block : 190 +Memory allocation - code portion : 54 ------------------------------------------------------------------ 0 23 Bra 3 17 CBra 1 @@ -197,7 +212,8 @@ Memory allocation (code space): 54 ------------------------------------------------------------------ /a(?Pb|c)d(?Pe)/ -Memory allocation (code space): 68 +Memory allocation - compiled block : 256 +Memory allocation - code portion : 68 ------------------------------------------------------------------ 0 30 Bra 3 a @@ -215,7 +231,8 @@ Memory allocation (code space): 68 ------------------------------------------------------------------ /(?:a(?Pc(?Pd)))(?Pa)/ -Memory allocation (code space): 84 +Memory allocation - compiled block : 238 +Memory allocation - code portion : 84 ------------------------------------------------------------------ 0 38 Bra 3 23 Bra @@ -235,7 +252,8 @@ Memory allocation (code space): 84 ------------------------------------------------------------------ /(?Pa)...(?P=a)bbb(?P>a)d/ -Memory allocation (code space): 64 +Memory allocation - compiled block : 206 +Memory allocation - code portion : 64 ------------------------------------------------------------------ 0 28 Bra 3 6 CBra 1 @@ -253,7 +271,8 @@ Memory allocation (code space): 64 ------------------------------------------------------------------ /abc(?C255)de(?C)f/ -Memory allocation (code space): 62 +Memory allocation - compiled block : 198 +Memory allocation - code portion : 62 ------------------------------------------------------------------ 0 27 Bra 3 abc @@ -266,7 +285,8 @@ Memory allocation (code space): 62 ------------------------------------------------------------------ /abcde/auto_callout -Memory allocation (code space): 106 +Memory allocation - compiled block : 242 +Memory allocation - code portion : 106 ------------------------------------------------------------------ 0 49 Bra 3 Callout 255 0 1 @@ -285,7 +305,8 @@ Memory allocation (code space): 106 ------------------------------------------------------------------ /\x{100}/utf -Memory allocation (code space): 18 +Memory allocation - compiled block : 154 +Memory allocation - code portion : 18 ------------------------------------------------------------------ 0 5 Bra 3 \x{100} @@ -294,7 +315,8 @@ Memory allocation (code space): 18 ------------------------------------------------------------------ /\x{1000}/utf -Memory allocation (code space): 18 +Memory allocation - compiled block : 154 +Memory allocation - code portion : 18 ------------------------------------------------------------------ 0 5 Bra 3 \x{1000} @@ -303,7 +325,8 @@ Memory allocation (code space): 18 ------------------------------------------------------------------ /\x{10000}/utf -Memory allocation (code space): 20 +Memory allocation - compiled block : 156 +Memory allocation - code portion : 20 ------------------------------------------------------------------ 0 6 Bra 3 \x{10000} @@ -312,7 +335,8 @@ Memory allocation (code space): 20 ------------------------------------------------------------------ /\x{100000}/utf -Memory allocation (code space): 20 +Memory allocation - compiled block : 156 +Memory allocation - code portion : 20 ------------------------------------------------------------------ 0 6 Bra 3 \x{100000} @@ -321,7 +345,8 @@ Memory allocation (code space): 20 ------------------------------------------------------------------ /\x{10ffff}/utf -Memory allocation (code space): 20 +Memory allocation - compiled block : 156 +Memory allocation - code portion : 20 ------------------------------------------------------------------ 0 6 Bra 3 \x{10ffff} @@ -333,7 +358,8 @@ Memory allocation (code space): 20 Failed: error 134 at offset 9: character code point value in \x{} or \o{} is too large /[\x{ff}]/utf -Memory allocation (code space): 18 +Memory allocation - compiled block : 154 +Memory allocation - code portion : 18 ------------------------------------------------------------------ 0 5 Bra 3 \x{ff} @@ -342,7 +368,8 @@ Memory allocation (code space): 18 ------------------------------------------------------------------ /[\x{100}]/utf -Memory allocation (code space): 18 +Memory allocation - compiled block : 154 +Memory allocation - code portion : 18 ------------------------------------------------------------------ 0 5 Bra 3 \x{100} @@ -351,7 +378,8 @@ Memory allocation (code space): 18 ------------------------------------------------------------------ /\x80/utf -Memory allocation (code space): 18 +Memory allocation - compiled block : 154 +Memory allocation - code portion : 18 ------------------------------------------------------------------ 0 5 Bra 3 \x{80} @@ -360,7 +388,8 @@ Memory allocation (code space): 18 ------------------------------------------------------------------ /\xff/utf -Memory allocation (code space): 18 +Memory allocation - compiled block : 154 +Memory allocation - code portion : 18 ------------------------------------------------------------------ 0 5 Bra 3 \x{ff} @@ -369,7 +398,8 @@ Memory allocation (code space): 18 ------------------------------------------------------------------ /\x{0041}\x{2262}\x{0391}\x{002e}/I,utf -Memory allocation (code space): 30 +Memory allocation - compiled block : 166 +Memory allocation - code portion : 30 ------------------------------------------------------------------ 0 11 Bra 3 A\x{2262}\x{391}. @@ -383,7 +413,8 @@ Last code unit = '.' Subject length lower bound = 4 /\x{D55c}\x{ad6d}\x{C5B4}/I,utf -Memory allocation (code space): 26 +Memory allocation - compiled block : 162 +Memory allocation - code portion : 26 ------------------------------------------------------------------ 0 9 Bra 3 \x{d55c}\x{ad6d}\x{c5b4} @@ -397,7 +428,8 @@ Last code unit = \x{c5b4} Subject length lower bound = 3 /\x{65e5}\x{672c}\x{8a9e}/I,utf -Memory allocation (code space): 26 +Memory allocation - compiled block : 162 +Memory allocation - code portion : 26 ------------------------------------------------------------------ 0 9 Bra 3 \x{65e5}\x{672c}\x{8a9e} @@ -411,7 +443,8 @@ Last code unit = \x{8a9e} Subject length lower bound = 3 /[\x{100}]/utf -Memory allocation (code space): 18 +Memory allocation - compiled block : 154 +Memory allocation - code portion : 18 ------------------------------------------------------------------ 0 5 Bra 3 \x{100} @@ -420,7 +453,8 @@ Memory allocation (code space): 18 ------------------------------------------------------------------ /[Z\x{100}]/utf -Memory allocation (code space): 60 +Memory allocation - compiled block : 196 +Memory allocation - code portion : 60 ------------------------------------------------------------------ 0 26 Bra 3 [Z\x{100}] @@ -429,7 +463,8 @@ Memory allocation (code space): 60 ------------------------------------------------------------------ /^[\x{100}\E-\Q\E\x{150}]/utf -Memory allocation (code space): 32 +Memory allocation - compiled block : 168 +Memory allocation - code portion : 32 ------------------------------------------------------------------ 0 12 Bra 3 ^ @@ -439,7 +474,8 @@ Memory allocation (code space): 32 ------------------------------------------------------------------ /^[\QĀ\E-\QŐ\E]/utf -Memory allocation (code space): 32 +Memory allocation - compiled block : 168 +Memory allocation - code portion : 32 ------------------------------------------------------------------ 0 12 Bra 3 ^ @@ -452,7 +488,8 @@ Memory allocation (code space): 32 Failed: error 106 at offset 13: missing terminating ] for character class /[\p{L}]/ -Memory allocation (code space): 30 +Memory allocation - compiled block : 166 +Memory allocation - code portion : 30 ------------------------------------------------------------------ 0 11 Bra 3 [\p{L}] @@ -461,7 +498,8 @@ Memory allocation (code space): 30 ------------------------------------------------------------------ /[\p{^L}]/ -Memory allocation (code space): 30 +Memory allocation - compiled block : 166 +Memory allocation - code portion : 30 ------------------------------------------------------------------ 0 11 Bra 3 [\P{L}] @@ -470,7 +508,8 @@ Memory allocation (code space): 30 ------------------------------------------------------------------ /[\P{L}]/ -Memory allocation (code space): 30 +Memory allocation - compiled block : 166 +Memory allocation - code portion : 30 ------------------------------------------------------------------ 0 11 Bra 3 [\P{L}] @@ -479,7 +518,8 @@ Memory allocation (code space): 30 ------------------------------------------------------------------ /[\P{^L}]/ -Memory allocation (code space): 30 +Memory allocation - compiled block : 166 +Memory allocation - code portion : 30 ------------------------------------------------------------------ 0 11 Bra 3 [\p{L}] @@ -488,7 +528,8 @@ Memory allocation (code space): 30 ------------------------------------------------------------------ /[abc\p{L}\x{0660}]/utf -Memory allocation (code space): 66 +Memory allocation - compiled block : 202 +Memory allocation - code portion : 66 ------------------------------------------------------------------ 0 29 Bra 3 [a-c\p{L}\x{660}] @@ -497,7 +538,8 @@ Memory allocation (code space): 66 ------------------------------------------------------------------ /[\p{Nd}]/utf -Memory allocation (code space): 30 +Memory allocation - compiled block : 166 +Memory allocation - code portion : 30 ------------------------------------------------------------------ 0 11 Bra 3 [\p{Nd}] @@ -506,7 +548,8 @@ Memory allocation (code space): 30 ------------------------------------------------------------------ /[\p{Nd}+-]+/utf -Memory allocation (code space): 64 +Memory allocation - compiled block : 200 +Memory allocation - code portion : 64 ------------------------------------------------------------------ 0 28 Bra 3 [+\-\p{Nd}]++ @@ -515,7 +558,8 @@ Memory allocation (code space): 64 ------------------------------------------------------------------ /A\x{391}\x{10427}\x{ff3a}\x{1fb0}/i,utf -Memory allocation (code space): 36 +Memory allocation - compiled block : 172 +Memory allocation - code portion : 36 ------------------------------------------------------------------ 0 14 Bra 3 /i A\x{391}\x{10427}\x{ff3a}\x{1fb0} @@ -524,7 +568,8 @@ Memory allocation (code space): 36 ------------------------------------------------------------------ /A\x{391}\x{10427}\x{ff3a}\x{1fb0}/utf -Memory allocation (code space): 36 +Memory allocation - compiled block : 172 +Memory allocation - code portion : 36 ------------------------------------------------------------------ 0 14 Bra 3 A\x{391}\x{10427}\x{ff3a}\x{1fb0} @@ -533,7 +578,8 @@ Memory allocation (code space): 36 ------------------------------------------------------------------ /[\x{105}-\x{109}]/i,utf -Memory allocation (code space): 30 +Memory allocation - compiled block : 166 +Memory allocation - code portion : 30 ------------------------------------------------------------------ 0 11 Bra 3 [\x{104}-\x{109}] @@ -542,7 +588,8 @@ Memory allocation (code space): 30 ------------------------------------------------------------------ /( ( (?(1)0|) )* )/x -Memory allocation (code space): 70 +Memory allocation - compiled block : 206 +Memory allocation - code portion : 70 ------------------------------------------------------------------ 0 31 Bra 3 25 CBra 1 @@ -560,7 +607,8 @@ Memory allocation (code space): 70 ------------------------------------------------------------------ /( (?(1)0|)* )/x -Memory allocation (code space): 56 +Memory allocation - compiled block : 192 +Memory allocation - code portion : 56 ------------------------------------------------------------------ 0 24 Bra 3 18 CBra 1 @@ -576,7 +624,8 @@ Memory allocation (code space): 56 ------------------------------------------------------------------ /[a]/ -Memory allocation (code space): 18 +Memory allocation - compiled block : 154 +Memory allocation - code portion : 18 ------------------------------------------------------------------ 0 5 Bra 3 a @@ -585,7 +634,8 @@ Memory allocation (code space): 18 ------------------------------------------------------------------ /[a]/utf -Memory allocation (code space): 18 +Memory allocation - compiled block : 154 +Memory allocation - code portion : 18 ------------------------------------------------------------------ 0 5 Bra 3 a @@ -594,7 +644,8 @@ Memory allocation (code space): 18 ------------------------------------------------------------------ /[\xaa]/ -Memory allocation (code space): 18 +Memory allocation - compiled block : 154 +Memory allocation - code portion : 18 ------------------------------------------------------------------ 0 5 Bra 3 \x{aa} @@ -603,7 +654,8 @@ Memory allocation (code space): 18 ------------------------------------------------------------------ /[\xaa]/utf -Memory allocation (code space): 18 +Memory allocation - compiled block : 154 +Memory allocation - code portion : 18 ------------------------------------------------------------------ 0 5 Bra 3 \x{aa} @@ -612,7 +664,8 @@ Memory allocation (code space): 18 ------------------------------------------------------------------ /[^a]/ -Memory allocation (code space): 18 +Memory allocation - compiled block : 154 +Memory allocation - code portion : 18 ------------------------------------------------------------------ 0 5 Bra 3 [^a] @@ -621,7 +674,8 @@ Memory allocation (code space): 18 ------------------------------------------------------------------ /[^a]/utf -Memory allocation (code space): 18 +Memory allocation - compiled block : 154 +Memory allocation - code portion : 18 ------------------------------------------------------------------ 0 5 Bra 3 [^a] @@ -630,7 +684,8 @@ Memory allocation (code space): 18 ------------------------------------------------------------------ /[^\xaa]/ -Memory allocation (code space): 18 +Memory allocation - compiled block : 154 +Memory allocation - code portion : 18 ------------------------------------------------------------------ 0 5 Bra 3 [^\x{aa}] @@ -639,7 +694,8 @@ Memory allocation (code space): 18 ------------------------------------------------------------------ /[^\xaa]/utf -Memory allocation (code space): 18 +Memory allocation - compiled block : 154 +Memory allocation - code portion : 18 ------------------------------------------------------------------ 0 5 Bra 3 [^\x{aa}] diff --git a/testdata/testoutput8-16-4 b/testdata/testoutput8-16-4 index 80ee1c9..4ec13ea 100644 --- a/testdata/testoutput8-16-4 +++ b/testdata/testoutput8-16-4 @@ -10,7 +10,8 @@ #pattern fullbincode,memory /((?i)b)/ -Memory allocation (code space): 32 +Memory allocation - compiled block : 168 +Memory allocation - code portion : 32 ------------------------------------------------------------------ 0 12 Bra 3 6 CBra 1 @@ -21,7 +22,8 @@ Memory allocation (code space): 32 ------------------------------------------------------------------ /(?s)(.*X|^B)/ -Memory allocation (code space): 48 +Memory allocation - compiled block : 184 +Memory allocation - code portion : 48 ------------------------------------------------------------------ 0 20 Bra 3 8 CBra 1 @@ -36,7 +38,8 @@ Memory allocation (code space): 48 ------------------------------------------------------------------ /(?s:.*X|^B)/ -Memory allocation (code space): 46 +Memory allocation - compiled block : 182 +Memory allocation - code portion : 46 ------------------------------------------------------------------ 0 19 Bra 3 7 Bra @@ -51,7 +54,8 @@ Memory allocation (code space): 46 ------------------------------------------------------------------ /^[[:alnum:]]/ -Memory allocation (code space): 50 +Memory allocation - compiled block : 186 +Memory allocation - code portion : 50 ------------------------------------------------------------------ 0 21 Bra 3 ^ @@ -61,7 +65,8 @@ Memory allocation (code space): 50 ------------------------------------------------------------------ /#/Ix -Memory allocation (code space): 14 +Memory allocation - compiled block : 150 +Memory allocation - code portion : 14 ------------------------------------------------------------------ 0 3 Bra 3 3 Ket @@ -73,7 +78,8 @@ Options: extended Subject length lower bound = 0 /a#/Ix -Memory allocation (code space): 18 +Memory allocation - compiled block : 154 +Memory allocation - code portion : 18 ------------------------------------------------------------------ 0 5 Bra 3 a @@ -86,7 +92,8 @@ First code unit = 'a' Subject length lower bound = 1 /x?+/ -Memory allocation (code space): 18 +Memory allocation - compiled block : 154 +Memory allocation - code portion : 18 ------------------------------------------------------------------ 0 5 Bra 3 x?+ @@ -95,7 +102,8 @@ Memory allocation (code space): 18 ------------------------------------------------------------------ /x++/ -Memory allocation (code space): 18 +Memory allocation - compiled block : 154 +Memory allocation - code portion : 18 ------------------------------------------------------------------ 0 5 Bra 3 x++ @@ -104,7 +112,8 @@ Memory allocation (code space): 18 ------------------------------------------------------------------ /x{1,3}+/ -Memory allocation (code space): 24 +Memory allocation - compiled block : 160 +Memory allocation - code portion : 24 ------------------------------------------------------------------ 0 8 Bra 3 x @@ -114,7 +123,8 @@ Memory allocation (code space): 24 ------------------------------------------------------------------ /(x)*+/ -Memory allocation (code space): 34 +Memory allocation - compiled block : 170 +Memory allocation - code portion : 34 ------------------------------------------------------------------ 0 13 Bra 3 Braposzero @@ -126,7 +136,8 @@ Memory allocation (code space): 34 ------------------------------------------------------------------ /^((a+)(?U)([ab]+)(?-U)([bc]+)(\w*))/ -Memory allocation (code space): 166 +Memory allocation - compiled block : 302 +Memory allocation - code portion : 166 ------------------------------------------------------------------ 0 79 Bra 3 ^ @@ -149,7 +160,8 @@ Memory allocation (code space): 166 ------------------------------------------------------------------ "8J\$WE\<\.rX\+ix\[d1b\!H\#\?vV0vrK\:ZH1\=2M\>iV\;\?aPhFB\<\*vW\@QW\@sO9\}cfZA\-i\'w\%hKd6gt1UJP\,15_\#QY\$M\^Mss_U\/\]\&LK9\[5vQub\^w\[KDD\qmj\;2\}YWFdYx\.Ap\]hjCPTP\(n28k\+3\;o\&WXqs\/gOXdr\$\:r\'do0\;b4c\(f_Gr\=\"\\4\)\[01T7ajQJvL\$W\~mL_sS\/4h\:x\*\[ZN\=KLs\&L5zX\/\/\>it\,o\:aU\(\;Z\>pW\&T7oP\'2K\^E\:x9\'c\[\%z\-\,64JQ5AeH_G\#KijUKghQw\^\\vea3a\?kka_G\$8\#\`\*kynsxzBLru\'\]k_\[7FrVx\}\^\=\$blx\>s\-N\%j\;D\*aZDnsw\:YKZ\%Q\.Kne9\#hP\?\+b3\(SOvL\,\^\;\&u5\@\?5C5Bhb\=m\-vEh_L15Jl\]U\)0RP6\{q\%L\^_z5E\'Dw6X\b" -Memory allocation (code space): 1652 +Memory allocation - compiled block : 1788 +Memory allocation - code portion : 1652 ------------------------------------------------------------------ 0 822 Bra 3 8J$WE<.rX+ix[d1b!H#?vV0vrK:ZH1=2M>iV;?aPhFB<*vW@QW@sO9}cfZA-i'w%hKd6gt1UJP,15_#QY$M^Mss_U/]&LK9[5vQub^w[KDDqmj;2}YWFdYx.Ap]hjCPTP(n28k+3;o&WXqs/gOXdr$:r'do0;b4c(f_Gr="\4)[01T7ajQJvL$W~mL_sS/4h:x*[ZN=KLs&L5zX//>it,o:aU(;Z>pW&T7oP'2K^E:x9'c[%z-,64JQ5AeH_G#KijUKghQw^\vea3a?kka_G$8#`*kynsxzBLru']k_[7FrVx}^=$blx>s-N%j;D*aZDnsw:YKZ%Q.Kne9#hP?+b3(SOvL,^;&u5@?5C5Bhb=m-vEh_L15Jl]U)0RP6{q%L^_z5E'Dw6X @@ -159,7 +171,8 @@ Memory allocation (code space): 1652 ------------------------------------------------------------------ "\$\<\.X\+ix\[d1b\!H\#\?vV0vrK\:ZH1\=2M\>iV\;\?aPhFB\<\*vW\@QW\@sO9\}cfZA\-i\'w\%hKd6gt1UJP\,15_\#QY\$M\^Mss_U\/\]\&LK9\[5vQub\^w\[KDD\qmj\;2\}YWFdYx\.Ap\]hjCPTP\(n28k\+3\;o\&WXqs\/gOXdr\$\:r\'do0\;b4c\(f_Gr\=\"\\4\)\[01T7ajQJvL\$W\~mL_sS\/4h\:x\*\[ZN\=KLs\&L5zX\/\/\>it\,o\:aU\(\;Z\>pW\&T7oP\'2K\^E\:x9\'c\[\%z\-\,64JQ5AeH_G\#KijUKghQw\^\\vea3a\?kka_G\$8\#\`\*kynsxzBLru\'\]k_\[7FrVx\}\^\=\$blx\>s\-N\%j\;D\*aZDnsw\:YKZ\%Q\.Kne9\#hP\?\+b3\(SOvL\,\^\;\&u5\@\?5C5Bhb\=m\-vEh_L15Jl\]U\)0RP6\{q\%L\^_z5E\'Dw6X\b" -Memory allocation (code space): 1632 +Memory allocation - compiled block : 1768 +Memory allocation - code portion : 1632 ------------------------------------------------------------------ 0 812 Bra 3 $<.X+ix[d1b!H#?vV0vrK:ZH1=2M>iV;?aPhFB<*vW@QW@sO9}cfZA-i'w%hKd6gt1UJP,15_#QY$M^Mss_U/]&LK9[5vQub^w[KDDqmj;2}YWFdYx.Ap]hjCPTP(n28k+3;o&WXqs/gOXdr$:r'do0;b4c(f_Gr="\4)[01T7ajQJvL$W~mL_sS/4h:x*[ZN=KLs&L5zX//>it,o:aU(;Z>pW&T7oP'2K^E:x9'c[%z-,64JQ5AeH_G#KijUKghQw^\vea3a?kka_G$8#`*kynsxzBLru']k_[7FrVx}^=$blx>s-N%j;D*aZDnsw:YKZ%Q.Kne9#hP?+b3(SOvL,^;&u5@?5C5Bhb=m-vEh_L15Jl]U)0RP6{q%L^_z5E'Dw6X @@ -169,7 +182,8 @@ Memory allocation (code space): 1632 ------------------------------------------------------------------ /(a(?1)b)/ -Memory allocation (code space): 42 +Memory allocation - compiled block : 178 +Memory allocation - code portion : 42 ------------------------------------------------------------------ 0 17 Bra 3 11 CBra 1 @@ -182,7 +196,8 @@ Memory allocation (code space): 42 ------------------------------------------------------------------ /(a(?1)+b)/ -Memory allocation (code space): 54 +Memory allocation - compiled block : 190 +Memory allocation - code portion : 54 ------------------------------------------------------------------ 0 23 Bra 3 17 CBra 1 @@ -197,7 +212,8 @@ Memory allocation (code space): 54 ------------------------------------------------------------------ /a(?Pb|c)d(?Pe)/ -Memory allocation (code space): 68 +Memory allocation - compiled block : 256 +Memory allocation - code portion : 68 ------------------------------------------------------------------ 0 30 Bra 3 a @@ -215,7 +231,8 @@ Memory allocation (code space): 68 ------------------------------------------------------------------ /(?:a(?Pc(?Pd)))(?Pa)/ -Memory allocation (code space): 84 +Memory allocation - compiled block : 238 +Memory allocation - code portion : 84 ------------------------------------------------------------------ 0 38 Bra 3 23 Bra @@ -235,7 +252,8 @@ Memory allocation (code space): 84 ------------------------------------------------------------------ /(?Pa)...(?P=a)bbb(?P>a)d/ -Memory allocation (code space): 64 +Memory allocation - compiled block : 206 +Memory allocation - code portion : 64 ------------------------------------------------------------------ 0 28 Bra 3 6 CBra 1 @@ -253,7 +271,8 @@ Memory allocation (code space): 64 ------------------------------------------------------------------ /abc(?C255)de(?C)f/ -Memory allocation (code space): 62 +Memory allocation - compiled block : 198 +Memory allocation - code portion : 62 ------------------------------------------------------------------ 0 27 Bra 3 abc @@ -266,7 +285,8 @@ Memory allocation (code space): 62 ------------------------------------------------------------------ /abcde/auto_callout -Memory allocation (code space): 106 +Memory allocation - compiled block : 242 +Memory allocation - code portion : 106 ------------------------------------------------------------------ 0 49 Bra 3 Callout 255 0 1 @@ -285,7 +305,8 @@ Memory allocation (code space): 106 ------------------------------------------------------------------ /\x{100}/utf -Memory allocation (code space): 18 +Memory allocation - compiled block : 154 +Memory allocation - code portion : 18 ------------------------------------------------------------------ 0 5 Bra 3 \x{100} @@ -294,7 +315,8 @@ Memory allocation (code space): 18 ------------------------------------------------------------------ /\x{1000}/utf -Memory allocation (code space): 18 +Memory allocation - compiled block : 154 +Memory allocation - code portion : 18 ------------------------------------------------------------------ 0 5 Bra 3 \x{1000} @@ -303,7 +325,8 @@ Memory allocation (code space): 18 ------------------------------------------------------------------ /\x{10000}/utf -Memory allocation (code space): 20 +Memory allocation - compiled block : 156 +Memory allocation - code portion : 20 ------------------------------------------------------------------ 0 6 Bra 3 \x{10000} @@ -312,7 +335,8 @@ Memory allocation (code space): 20 ------------------------------------------------------------------ /\x{100000}/utf -Memory allocation (code space): 20 +Memory allocation - compiled block : 156 +Memory allocation - code portion : 20 ------------------------------------------------------------------ 0 6 Bra 3 \x{100000} @@ -321,7 +345,8 @@ Memory allocation (code space): 20 ------------------------------------------------------------------ /\x{10ffff}/utf -Memory allocation (code space): 20 +Memory allocation - compiled block : 156 +Memory allocation - code portion : 20 ------------------------------------------------------------------ 0 6 Bra 3 \x{10ffff} @@ -333,7 +358,8 @@ Memory allocation (code space): 20 Failed: error 134 at offset 9: character code point value in \x{} or \o{} is too large /[\x{ff}]/utf -Memory allocation (code space): 18 +Memory allocation - compiled block : 154 +Memory allocation - code portion : 18 ------------------------------------------------------------------ 0 5 Bra 3 \x{ff} @@ -342,7 +368,8 @@ Memory allocation (code space): 18 ------------------------------------------------------------------ /[\x{100}]/utf -Memory allocation (code space): 18 +Memory allocation - compiled block : 154 +Memory allocation - code portion : 18 ------------------------------------------------------------------ 0 5 Bra 3 \x{100} @@ -351,7 +378,8 @@ Memory allocation (code space): 18 ------------------------------------------------------------------ /\x80/utf -Memory allocation (code space): 18 +Memory allocation - compiled block : 154 +Memory allocation - code portion : 18 ------------------------------------------------------------------ 0 5 Bra 3 \x{80} @@ -360,7 +388,8 @@ Memory allocation (code space): 18 ------------------------------------------------------------------ /\xff/utf -Memory allocation (code space): 18 +Memory allocation - compiled block : 154 +Memory allocation - code portion : 18 ------------------------------------------------------------------ 0 5 Bra 3 \x{ff} @@ -369,7 +398,8 @@ Memory allocation (code space): 18 ------------------------------------------------------------------ /\x{0041}\x{2262}\x{0391}\x{002e}/I,utf -Memory allocation (code space): 30 +Memory allocation - compiled block : 166 +Memory allocation - code portion : 30 ------------------------------------------------------------------ 0 11 Bra 3 A\x{2262}\x{391}. @@ -383,7 +413,8 @@ Last code unit = '.' Subject length lower bound = 4 /\x{D55c}\x{ad6d}\x{C5B4}/I,utf -Memory allocation (code space): 26 +Memory allocation - compiled block : 162 +Memory allocation - code portion : 26 ------------------------------------------------------------------ 0 9 Bra 3 \x{d55c}\x{ad6d}\x{c5b4} @@ -397,7 +428,8 @@ Last code unit = \x{c5b4} Subject length lower bound = 3 /\x{65e5}\x{672c}\x{8a9e}/I,utf -Memory allocation (code space): 26 +Memory allocation - compiled block : 162 +Memory allocation - code portion : 26 ------------------------------------------------------------------ 0 9 Bra 3 \x{65e5}\x{672c}\x{8a9e} @@ -411,7 +443,8 @@ Last code unit = \x{8a9e} Subject length lower bound = 3 /[\x{100}]/utf -Memory allocation (code space): 18 +Memory allocation - compiled block : 154 +Memory allocation - code portion : 18 ------------------------------------------------------------------ 0 5 Bra 3 \x{100} @@ -420,7 +453,8 @@ Memory allocation (code space): 18 ------------------------------------------------------------------ /[Z\x{100}]/utf -Memory allocation (code space): 60 +Memory allocation - compiled block : 196 +Memory allocation - code portion : 60 ------------------------------------------------------------------ 0 26 Bra 3 [Z\x{100}] @@ -429,7 +463,8 @@ Memory allocation (code space): 60 ------------------------------------------------------------------ /^[\x{100}\E-\Q\E\x{150}]/utf -Memory allocation (code space): 32 +Memory allocation - compiled block : 168 +Memory allocation - code portion : 32 ------------------------------------------------------------------ 0 12 Bra 3 ^ @@ -439,7 +474,8 @@ Memory allocation (code space): 32 ------------------------------------------------------------------ /^[\QĀ\E-\QŐ\E]/utf -Memory allocation (code space): 32 +Memory allocation - compiled block : 168 +Memory allocation - code portion : 32 ------------------------------------------------------------------ 0 12 Bra 3 ^ @@ -452,7 +488,8 @@ Memory allocation (code space): 32 Failed: error 106 at offset 13: missing terminating ] for character class /[\p{L}]/ -Memory allocation (code space): 30 +Memory allocation - compiled block : 166 +Memory allocation - code portion : 30 ------------------------------------------------------------------ 0 11 Bra 3 [\p{L}] @@ -461,7 +498,8 @@ Memory allocation (code space): 30 ------------------------------------------------------------------ /[\p{^L}]/ -Memory allocation (code space): 30 +Memory allocation - compiled block : 166 +Memory allocation - code portion : 30 ------------------------------------------------------------------ 0 11 Bra 3 [\P{L}] @@ -470,7 +508,8 @@ Memory allocation (code space): 30 ------------------------------------------------------------------ /[\P{L}]/ -Memory allocation (code space): 30 +Memory allocation - compiled block : 166 +Memory allocation - code portion : 30 ------------------------------------------------------------------ 0 11 Bra 3 [\P{L}] @@ -479,7 +518,8 @@ Memory allocation (code space): 30 ------------------------------------------------------------------ /[\P{^L}]/ -Memory allocation (code space): 30 +Memory allocation - compiled block : 166 +Memory allocation - code portion : 30 ------------------------------------------------------------------ 0 11 Bra 3 [\p{L}] @@ -488,7 +528,8 @@ Memory allocation (code space): 30 ------------------------------------------------------------------ /[abc\p{L}\x{0660}]/utf -Memory allocation (code space): 66 +Memory allocation - compiled block : 202 +Memory allocation - code portion : 66 ------------------------------------------------------------------ 0 29 Bra 3 [a-c\p{L}\x{660}] @@ -497,7 +538,8 @@ Memory allocation (code space): 66 ------------------------------------------------------------------ /[\p{Nd}]/utf -Memory allocation (code space): 30 +Memory allocation - compiled block : 166 +Memory allocation - code portion : 30 ------------------------------------------------------------------ 0 11 Bra 3 [\p{Nd}] @@ -506,7 +548,8 @@ Memory allocation (code space): 30 ------------------------------------------------------------------ /[\p{Nd}+-]+/utf -Memory allocation (code space): 64 +Memory allocation - compiled block : 200 +Memory allocation - code portion : 64 ------------------------------------------------------------------ 0 28 Bra 3 [+\-\p{Nd}]++ @@ -515,7 +558,8 @@ Memory allocation (code space): 64 ------------------------------------------------------------------ /A\x{391}\x{10427}\x{ff3a}\x{1fb0}/i,utf -Memory allocation (code space): 36 +Memory allocation - compiled block : 172 +Memory allocation - code portion : 36 ------------------------------------------------------------------ 0 14 Bra 3 /i A\x{391}\x{10427}\x{ff3a}\x{1fb0} @@ -524,7 +568,8 @@ Memory allocation (code space): 36 ------------------------------------------------------------------ /A\x{391}\x{10427}\x{ff3a}\x{1fb0}/utf -Memory allocation (code space): 36 +Memory allocation - compiled block : 172 +Memory allocation - code portion : 36 ------------------------------------------------------------------ 0 14 Bra 3 A\x{391}\x{10427}\x{ff3a}\x{1fb0} @@ -533,7 +578,8 @@ Memory allocation (code space): 36 ------------------------------------------------------------------ /[\x{105}-\x{109}]/i,utf -Memory allocation (code space): 30 +Memory allocation - compiled block : 166 +Memory allocation - code portion : 30 ------------------------------------------------------------------ 0 11 Bra 3 [\x{104}-\x{109}] @@ -542,7 +588,8 @@ Memory allocation (code space): 30 ------------------------------------------------------------------ /( ( (?(1)0|) )* )/x -Memory allocation (code space): 70 +Memory allocation - compiled block : 206 +Memory allocation - code portion : 70 ------------------------------------------------------------------ 0 31 Bra 3 25 CBra 1 @@ -560,7 +607,8 @@ Memory allocation (code space): 70 ------------------------------------------------------------------ /( (?(1)0|)* )/x -Memory allocation (code space): 56 +Memory allocation - compiled block : 192 +Memory allocation - code portion : 56 ------------------------------------------------------------------ 0 24 Bra 3 18 CBra 1 @@ -576,7 +624,8 @@ Memory allocation (code space): 56 ------------------------------------------------------------------ /[a]/ -Memory allocation (code space): 18 +Memory allocation - compiled block : 154 +Memory allocation - code portion : 18 ------------------------------------------------------------------ 0 5 Bra 3 a @@ -585,7 +634,8 @@ Memory allocation (code space): 18 ------------------------------------------------------------------ /[a]/utf -Memory allocation (code space): 18 +Memory allocation - compiled block : 154 +Memory allocation - code portion : 18 ------------------------------------------------------------------ 0 5 Bra 3 a @@ -594,7 +644,8 @@ Memory allocation (code space): 18 ------------------------------------------------------------------ /[\xaa]/ -Memory allocation (code space): 18 +Memory allocation - compiled block : 154 +Memory allocation - code portion : 18 ------------------------------------------------------------------ 0 5 Bra 3 \x{aa} @@ -603,7 +654,8 @@ Memory allocation (code space): 18 ------------------------------------------------------------------ /[\xaa]/utf -Memory allocation (code space): 18 +Memory allocation - compiled block : 154 +Memory allocation - code portion : 18 ------------------------------------------------------------------ 0 5 Bra 3 \x{aa} @@ -612,7 +664,8 @@ Memory allocation (code space): 18 ------------------------------------------------------------------ /[^a]/ -Memory allocation (code space): 18 +Memory allocation - compiled block : 154 +Memory allocation - code portion : 18 ------------------------------------------------------------------ 0 5 Bra 3 [^a] @@ -621,7 +674,8 @@ Memory allocation (code space): 18 ------------------------------------------------------------------ /[^a]/utf -Memory allocation (code space): 18 +Memory allocation - compiled block : 154 +Memory allocation - code portion : 18 ------------------------------------------------------------------ 0 5 Bra 3 [^a] @@ -630,7 +684,8 @@ Memory allocation (code space): 18 ------------------------------------------------------------------ /[^\xaa]/ -Memory allocation (code space): 18 +Memory allocation - compiled block : 154 +Memory allocation - code portion : 18 ------------------------------------------------------------------ 0 5 Bra 3 [^\x{aa}] @@ -639,7 +694,8 @@ Memory allocation (code space): 18 ------------------------------------------------------------------ /[^\xaa]/utf -Memory allocation (code space): 18 +Memory allocation - compiled block : 154 +Memory allocation - code portion : 18 ------------------------------------------------------------------ 0 5 Bra 3 [^\x{aa}] diff --git a/testdata/testoutput8-32-2 b/testdata/testoutput8-32-2 index 91d96c9..d76f3aa 100644 --- a/testdata/testoutput8-32-2 +++ b/testdata/testoutput8-32-2 @@ -10,7 +10,8 @@ #pattern fullbincode,memory /((?i)b)/ -Memory allocation (code space): 48 +Memory allocation - compiled block : 184 +Memory allocation - code portion : 48 ------------------------------------------------------------------ 0 9 Bra 2 5 CBra 1 @@ -21,7 +22,8 @@ Memory allocation (code space): 48 ------------------------------------------------------------------ /(?s)(.*X|^B)/ -Memory allocation (code space): 76 +Memory allocation - compiled block : 212 +Memory allocation - code portion : 76 ------------------------------------------------------------------ 0 16 Bra 2 7 CBra 1 @@ -36,7 +38,8 @@ Memory allocation (code space): 76 ------------------------------------------------------------------ /(?s:.*X|^B)/ -Memory allocation (code space): 72 +Memory allocation - compiled block : 208 +Memory allocation - code portion : 72 ------------------------------------------------------------------ 0 15 Bra 2 6 Bra @@ -51,7 +54,8 @@ Memory allocation (code space): 72 ------------------------------------------------------------------ /^[[:alnum:]]/ -Memory allocation (code space): 60 +Memory allocation - compiled block : 196 +Memory allocation - code portion : 60 ------------------------------------------------------------------ 0 12 Bra 2 ^ @@ -61,7 +65,8 @@ Memory allocation (code space): 60 ------------------------------------------------------------------ /#/Ix -Memory allocation (code space): 20 +Memory allocation - compiled block : 156 +Memory allocation - code portion : 20 ------------------------------------------------------------------ 0 2 Bra 2 2 Ket @@ -73,7 +78,8 @@ Options: extended Subject length lower bound = 0 /a#/Ix -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 a @@ -86,7 +92,8 @@ First code unit = 'a' Subject length lower bound = 1 /x?+/ -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 x?+ @@ -95,7 +102,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /x++/ -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 x++ @@ -104,7 +112,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /x{1,3}+/ -Memory allocation (code space): 40 +Memory allocation - compiled block : 176 +Memory allocation - code portion : 40 ------------------------------------------------------------------ 0 7 Bra 2 x @@ -114,7 +123,8 @@ Memory allocation (code space): 40 ------------------------------------------------------------------ /(x)*+/ -Memory allocation (code space): 52 +Memory allocation - compiled block : 188 +Memory allocation - code portion : 52 ------------------------------------------------------------------ 0 10 Bra 2 Braposzero @@ -126,7 +136,8 @@ Memory allocation (code space): 52 ------------------------------------------------------------------ /^((a+)(?U)([ab]+)(?-U)([bc]+)(\w*))/ -Memory allocation (code space): 220 +Memory allocation - compiled block : 356 +Memory allocation - code portion : 220 ------------------------------------------------------------------ 0 52 Bra 2 ^ @@ -149,7 +160,8 @@ Memory allocation (code space): 220 ------------------------------------------------------------------ "8J\$WE\<\.rX\+ix\[d1b\!H\#\?vV0vrK\:ZH1\=2M\>iV\;\?aPhFB\<\*vW\@QW\@sO9\}cfZA\-i\'w\%hKd6gt1UJP\,15_\#QY\$M\^Mss_U\/\]\&LK9\[5vQub\^w\[KDD\qmj\;2\}YWFdYx\.Ap\]hjCPTP\(n28k\+3\;o\&WXqs\/gOXdr\$\:r\'do0\;b4c\(f_Gr\=\"\\4\)\[01T7ajQJvL\$W\~mL_sS\/4h\:x\*\[ZN\=KLs\&L5zX\/\/\>it\,o\:aU\(\;Z\>pW\&T7oP\'2K\^E\:x9\'c\[\%z\-\,64JQ5AeH_G\#KijUKghQw\^\\vea3a\?kka_G\$8\#\`\*kynsxzBLru\'\]k_\[7FrVx\}\^\=\$blx\>s\-N\%j\;D\*aZDnsw\:YKZ\%Q\.Kne9\#hP\?\+b3\(SOvL\,\^\;\&u5\@\?5C5Bhb\=m\-vEh_L15Jl\]U\)0RP6\{q\%L\^_z5E\'Dw6X\b" -Memory allocation (code space): 3296 +Memory allocation - compiled block : 3432 +Memory allocation - code portion : 3296 ------------------------------------------------------------------ 0 821 Bra 2 8J$WE<.rX+ix[d1b!H#?vV0vrK:ZH1=2M>iV;?aPhFB<*vW@QW@sO9}cfZA-i'w%hKd6gt1UJP,15_#QY$M^Mss_U/]&LK9[5vQub^w[KDDqmj;2}YWFdYx.Ap]hjCPTP(n28k+3;o&WXqs/gOXdr$:r'do0;b4c(f_Gr="\4)[01T7ajQJvL$W~mL_sS/4h:x*[ZN=KLs&L5zX//>it,o:aU(;Z>pW&T7oP'2K^E:x9'c[%z-,64JQ5AeH_G#KijUKghQw^\vea3a?kka_G$8#`*kynsxzBLru']k_[7FrVx}^=$blx>s-N%j;D*aZDnsw:YKZ%Q.Kne9#hP?+b3(SOvL,^;&u5@?5C5Bhb=m-vEh_L15Jl]U)0RP6{q%L^_z5E'Dw6X @@ -159,7 +171,8 @@ Memory allocation (code space): 3296 ------------------------------------------------------------------ "\$\<\.X\+ix\[d1b\!H\#\?vV0vrK\:ZH1\=2M\>iV\;\?aPhFB\<\*vW\@QW\@sO9\}cfZA\-i\'w\%hKd6gt1UJP\,15_\#QY\$M\^Mss_U\/\]\&LK9\[5vQub\^w\[KDD\qmj\;2\}YWFdYx\.Ap\]hjCPTP\(n28k\+3\;o\&WXqs\/gOXdr\$\:r\'do0\;b4c\(f_Gr\=\"\\4\)\[01T7ajQJvL\$W\~mL_sS\/4h\:x\*\[ZN\=KLs\&L5zX\/\/\>it\,o\:aU\(\;Z\>pW\&T7oP\'2K\^E\:x9\'c\[\%z\-\,64JQ5AeH_G\#KijUKghQw\^\\vea3a\?kka_G\$8\#\`\*kynsxzBLru\'\]k_\[7FrVx\}\^\=\$blx\>s\-N\%j\;D\*aZDnsw\:YKZ\%Q\.Kne9\#hP\?\+b3\(SOvL\,\^\;\&u5\@\?5C5Bhb\=m\-vEh_L15Jl\]U\)0RP6\{q\%L\^_z5E\'Dw6X\b" -Memory allocation (code space): 3256 +Memory allocation - compiled block : 3392 +Memory allocation - code portion : 3256 ------------------------------------------------------------------ 0 811 Bra 2 $<.X+ix[d1b!H#?vV0vrK:ZH1=2M>iV;?aPhFB<*vW@QW@sO9}cfZA-i'w%hKd6gt1UJP,15_#QY$M^Mss_U/]&LK9[5vQub^w[KDDqmj;2}YWFdYx.Ap]hjCPTP(n28k+3;o&WXqs/gOXdr$:r'do0;b4c(f_Gr="\4)[01T7ajQJvL$W~mL_sS/4h:x*[ZN=KLs&L5zX//>it,o:aU(;Z>pW&T7oP'2K^E:x9'c[%z-,64JQ5AeH_G#KijUKghQw^\vea3a?kka_G$8#`*kynsxzBLru']k_[7FrVx}^=$blx>s-N%j;D*aZDnsw:YKZ%Q.Kne9#hP?+b3(SOvL,^;&u5@?5C5Bhb=m-vEh_L15Jl]U)0RP6{q%L^_z5E'Dw6X @@ -169,7 +182,8 @@ Memory allocation (code space): 3256 ------------------------------------------------------------------ /(a(?1)b)/ -Memory allocation (code space): 64 +Memory allocation - compiled block : 200 +Memory allocation - code portion : 64 ------------------------------------------------------------------ 0 13 Bra 2 9 CBra 1 @@ -182,7 +196,8 @@ Memory allocation (code space): 64 ------------------------------------------------------------------ /(a(?1)+b)/ -Memory allocation (code space): 80 +Memory allocation - compiled block : 216 +Memory allocation - code portion : 80 ------------------------------------------------------------------ 0 17 Bra 2 13 CBra 1 @@ -197,7 +212,8 @@ Memory allocation (code space): 80 ------------------------------------------------------------------ /a(?Pb|c)d(?Pe)/ -Memory allocation (code space): 108 +Memory allocation - compiled block : 348 +Memory allocation - code portion : 108 ------------------------------------------------------------------ 0 24 Bra 2 a @@ -215,7 +231,8 @@ Memory allocation (code space): 108 ------------------------------------------------------------------ /(?:a(?Pc(?Pd)))(?Pa)/ -Memory allocation (code space): 128 +Memory allocation - compiled block : 300 +Memory allocation - code portion : 128 ------------------------------------------------------------------ 0 29 Bra 2 18 Bra @@ -235,7 +252,8 @@ Memory allocation (code space): 128 ------------------------------------------------------------------ /(?Pa)...(?P=a)bbb(?P>a)d/ -Memory allocation (code space): 108 +Memory allocation - compiled block : 256 +Memory allocation - code portion : 108 ------------------------------------------------------------------ 0 24 Bra 2 5 CBra 1 @@ -253,7 +271,8 @@ Memory allocation (code space): 108 ------------------------------------------------------------------ /abc(?C255)de(?C)f/ -Memory allocation (code space): 100 +Memory allocation - compiled block : 236 +Memory allocation - code portion : 100 ------------------------------------------------------------------ 0 22 Bra 2 abc @@ -266,7 +285,8 @@ Memory allocation (code space): 100 ------------------------------------------------------------------ /abcde/auto_callout -Memory allocation (code space): 156 +Memory allocation - compiled block : 292 +Memory allocation - code portion : 156 ------------------------------------------------------------------ 0 36 Bra 2 Callout 255 0 1 @@ -285,7 +305,8 @@ Memory allocation (code space): 156 ------------------------------------------------------------------ /\x{100}/utf -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 \x{100} @@ -294,7 +315,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /\x{1000}/utf -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 \x{1000} @@ -303,7 +325,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /\x{10000}/utf -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 \x{10000} @@ -312,7 +335,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /\x{100000}/utf -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 \x{100000} @@ -321,7 +345,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /\x{10ffff}/utf -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 \x{10ffff} @@ -333,7 +358,8 @@ Memory allocation (code space): 28 Failed: error 134 at offset 9: character code point value in \x{} or \o{} is too large /[\x{ff}]/utf -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 \x{ff} @@ -342,7 +368,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /[\x{100}]/utf -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 \x{100} @@ -351,7 +378,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /\x80/utf -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 \x{80} @@ -360,7 +388,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /\xff/utf -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 \x{ff} @@ -369,7 +398,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /\x{0041}\x{2262}\x{0391}\x{002e}/I,utf -Memory allocation (code space): 52 +Memory allocation - compiled block : 188 +Memory allocation - code portion : 52 ------------------------------------------------------------------ 0 10 Bra 2 A\x{2262}\x{391}. @@ -383,7 +413,8 @@ Last code unit = '.' Subject length lower bound = 4 /\x{D55c}\x{ad6d}\x{C5B4}/I,utf -Memory allocation (code space): 44 +Memory allocation - compiled block : 180 +Memory allocation - code portion : 44 ------------------------------------------------------------------ 0 8 Bra 2 \x{d55c}\x{ad6d}\x{c5b4} @@ -397,7 +428,8 @@ Last code unit = \x{c5b4} Subject length lower bound = 3 /\x{65e5}\x{672c}\x{8a9e}/I,utf -Memory allocation (code space): 44 +Memory allocation - compiled block : 180 +Memory allocation - code portion : 44 ------------------------------------------------------------------ 0 8 Bra 2 \x{65e5}\x{672c}\x{8a9e} @@ -411,7 +443,8 @@ Last code unit = \x{8a9e} Subject length lower bound = 3 /[\x{100}]/utf -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 \x{100} @@ -420,7 +453,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /[Z\x{100}]/utf -Memory allocation (code space): 76 +Memory allocation - compiled block : 212 +Memory allocation - code portion : 76 ------------------------------------------------------------------ 0 16 Bra 2 [Z\x{100}] @@ -429,7 +463,8 @@ Memory allocation (code space): 76 ------------------------------------------------------------------ /^[\x{100}\E-\Q\E\x{150}]/utf -Memory allocation (code space): 52 +Memory allocation - compiled block : 188 +Memory allocation - code portion : 52 ------------------------------------------------------------------ 0 10 Bra 2 ^ @@ -439,7 +474,8 @@ Memory allocation (code space): 52 ------------------------------------------------------------------ /^[\QĀ\E-\QŐ\E]/utf -Memory allocation (code space): 52 +Memory allocation - compiled block : 188 +Memory allocation - code portion : 52 ------------------------------------------------------------------ 0 10 Bra 2 ^ @@ -452,7 +488,8 @@ Memory allocation (code space): 52 Failed: error 106 at offset 13: missing terminating ] for character class /[\p{L}]/ -Memory allocation (code space): 48 +Memory allocation - compiled block : 184 +Memory allocation - code portion : 48 ------------------------------------------------------------------ 0 9 Bra 2 [\p{L}] @@ -461,7 +498,8 @@ Memory allocation (code space): 48 ------------------------------------------------------------------ /[\p{^L}]/ -Memory allocation (code space): 48 +Memory allocation - compiled block : 184 +Memory allocation - code portion : 48 ------------------------------------------------------------------ 0 9 Bra 2 [\P{L}] @@ -470,7 +508,8 @@ Memory allocation (code space): 48 ------------------------------------------------------------------ /[\P{L}]/ -Memory allocation (code space): 48 +Memory allocation - compiled block : 184 +Memory allocation - code portion : 48 ------------------------------------------------------------------ 0 9 Bra 2 [\P{L}] @@ -479,7 +518,8 @@ Memory allocation (code space): 48 ------------------------------------------------------------------ /[\P{^L}]/ -Memory allocation (code space): 48 +Memory allocation - compiled block : 184 +Memory allocation - code portion : 48 ------------------------------------------------------------------ 0 9 Bra 2 [\p{L}] @@ -488,7 +528,8 @@ Memory allocation (code space): 48 ------------------------------------------------------------------ /[abc\p{L}\x{0660}]/utf -Memory allocation (code space): 88 +Memory allocation - compiled block : 224 +Memory allocation - code portion : 88 ------------------------------------------------------------------ 0 19 Bra 2 [a-c\p{L}\x{660}] @@ -497,7 +538,8 @@ Memory allocation (code space): 88 ------------------------------------------------------------------ /[\p{Nd}]/utf -Memory allocation (code space): 48 +Memory allocation - compiled block : 184 +Memory allocation - code portion : 48 ------------------------------------------------------------------ 0 9 Bra 2 [\p{Nd}] @@ -506,7 +548,8 @@ Memory allocation (code space): 48 ------------------------------------------------------------------ /[\p{Nd}+-]+/utf -Memory allocation (code space): 84 +Memory allocation - compiled block : 220 +Memory allocation - code portion : 84 ------------------------------------------------------------------ 0 18 Bra 2 [+\-\p{Nd}]++ @@ -515,7 +558,8 @@ Memory allocation (code space): 84 ------------------------------------------------------------------ /A\x{391}\x{10427}\x{ff3a}\x{1fb0}/i,utf -Memory allocation (code space): 60 +Memory allocation - compiled block : 196 +Memory allocation - code portion : 60 ------------------------------------------------------------------ 0 12 Bra 2 /i A\x{391}\x{10427}\x{ff3a}\x{1fb0} @@ -524,7 +568,8 @@ Memory allocation (code space): 60 ------------------------------------------------------------------ /A\x{391}\x{10427}\x{ff3a}\x{1fb0}/utf -Memory allocation (code space): 60 +Memory allocation - compiled block : 196 +Memory allocation - code portion : 60 ------------------------------------------------------------------ 0 12 Bra 2 A\x{391}\x{10427}\x{ff3a}\x{1fb0} @@ -533,7 +578,8 @@ Memory allocation (code space): 60 ------------------------------------------------------------------ /[\x{105}-\x{109}]/i,utf -Memory allocation (code space): 48 +Memory allocation - compiled block : 184 +Memory allocation - code portion : 48 ------------------------------------------------------------------ 0 9 Bra 2 [\x{104}-\x{109}] @@ -542,7 +588,8 @@ Memory allocation (code space): 48 ------------------------------------------------------------------ /( ( (?(1)0|) )* )/x -Memory allocation (code space): 104 +Memory allocation - compiled block : 240 +Memory allocation - code portion : 104 ------------------------------------------------------------------ 0 23 Bra 2 19 CBra 1 @@ -560,7 +607,8 @@ Memory allocation (code space): 104 ------------------------------------------------------------------ /( (?(1)0|)* )/x -Memory allocation (code space): 84 +Memory allocation - compiled block : 220 +Memory allocation - code portion : 84 ------------------------------------------------------------------ 0 18 Bra 2 14 CBra 1 @@ -576,7 +624,8 @@ Memory allocation (code space): 84 ------------------------------------------------------------------ /[a]/ -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 a @@ -585,7 +634,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /[a]/utf -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 a @@ -594,7 +644,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /[\xaa]/ -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 \x{aa} @@ -603,7 +654,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /[\xaa]/utf -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 \x{aa} @@ -612,7 +664,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /[^a]/ -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 [^a] @@ -621,7 +674,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /[^a]/utf -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 [^a] @@ -630,7 +684,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /[^\xaa]/ -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 [^\x{aa}] @@ -639,7 +694,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /[^\xaa]/utf -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 [^\x{aa}] diff --git a/testdata/testoutput8-32-3 b/testdata/testoutput8-32-3 index 91d96c9..d76f3aa 100644 --- a/testdata/testoutput8-32-3 +++ b/testdata/testoutput8-32-3 @@ -10,7 +10,8 @@ #pattern fullbincode,memory /((?i)b)/ -Memory allocation (code space): 48 +Memory allocation - compiled block : 184 +Memory allocation - code portion : 48 ------------------------------------------------------------------ 0 9 Bra 2 5 CBra 1 @@ -21,7 +22,8 @@ Memory allocation (code space): 48 ------------------------------------------------------------------ /(?s)(.*X|^B)/ -Memory allocation (code space): 76 +Memory allocation - compiled block : 212 +Memory allocation - code portion : 76 ------------------------------------------------------------------ 0 16 Bra 2 7 CBra 1 @@ -36,7 +38,8 @@ Memory allocation (code space): 76 ------------------------------------------------------------------ /(?s:.*X|^B)/ -Memory allocation (code space): 72 +Memory allocation - compiled block : 208 +Memory allocation - code portion : 72 ------------------------------------------------------------------ 0 15 Bra 2 6 Bra @@ -51,7 +54,8 @@ Memory allocation (code space): 72 ------------------------------------------------------------------ /^[[:alnum:]]/ -Memory allocation (code space): 60 +Memory allocation - compiled block : 196 +Memory allocation - code portion : 60 ------------------------------------------------------------------ 0 12 Bra 2 ^ @@ -61,7 +65,8 @@ Memory allocation (code space): 60 ------------------------------------------------------------------ /#/Ix -Memory allocation (code space): 20 +Memory allocation - compiled block : 156 +Memory allocation - code portion : 20 ------------------------------------------------------------------ 0 2 Bra 2 2 Ket @@ -73,7 +78,8 @@ Options: extended Subject length lower bound = 0 /a#/Ix -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 a @@ -86,7 +92,8 @@ First code unit = 'a' Subject length lower bound = 1 /x?+/ -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 x?+ @@ -95,7 +102,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /x++/ -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 x++ @@ -104,7 +112,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /x{1,3}+/ -Memory allocation (code space): 40 +Memory allocation - compiled block : 176 +Memory allocation - code portion : 40 ------------------------------------------------------------------ 0 7 Bra 2 x @@ -114,7 +123,8 @@ Memory allocation (code space): 40 ------------------------------------------------------------------ /(x)*+/ -Memory allocation (code space): 52 +Memory allocation - compiled block : 188 +Memory allocation - code portion : 52 ------------------------------------------------------------------ 0 10 Bra 2 Braposzero @@ -126,7 +136,8 @@ Memory allocation (code space): 52 ------------------------------------------------------------------ /^((a+)(?U)([ab]+)(?-U)([bc]+)(\w*))/ -Memory allocation (code space): 220 +Memory allocation - compiled block : 356 +Memory allocation - code portion : 220 ------------------------------------------------------------------ 0 52 Bra 2 ^ @@ -149,7 +160,8 @@ Memory allocation (code space): 220 ------------------------------------------------------------------ "8J\$WE\<\.rX\+ix\[d1b\!H\#\?vV0vrK\:ZH1\=2M\>iV\;\?aPhFB\<\*vW\@QW\@sO9\}cfZA\-i\'w\%hKd6gt1UJP\,15_\#QY\$M\^Mss_U\/\]\&LK9\[5vQub\^w\[KDD\qmj\;2\}YWFdYx\.Ap\]hjCPTP\(n28k\+3\;o\&WXqs\/gOXdr\$\:r\'do0\;b4c\(f_Gr\=\"\\4\)\[01T7ajQJvL\$W\~mL_sS\/4h\:x\*\[ZN\=KLs\&L5zX\/\/\>it\,o\:aU\(\;Z\>pW\&T7oP\'2K\^E\:x9\'c\[\%z\-\,64JQ5AeH_G\#KijUKghQw\^\\vea3a\?kka_G\$8\#\`\*kynsxzBLru\'\]k_\[7FrVx\}\^\=\$blx\>s\-N\%j\;D\*aZDnsw\:YKZ\%Q\.Kne9\#hP\?\+b3\(SOvL\,\^\;\&u5\@\?5C5Bhb\=m\-vEh_L15Jl\]U\)0RP6\{q\%L\^_z5E\'Dw6X\b" -Memory allocation (code space): 3296 +Memory allocation - compiled block : 3432 +Memory allocation - code portion : 3296 ------------------------------------------------------------------ 0 821 Bra 2 8J$WE<.rX+ix[d1b!H#?vV0vrK:ZH1=2M>iV;?aPhFB<*vW@QW@sO9}cfZA-i'w%hKd6gt1UJP,15_#QY$M^Mss_U/]&LK9[5vQub^w[KDDqmj;2}YWFdYx.Ap]hjCPTP(n28k+3;o&WXqs/gOXdr$:r'do0;b4c(f_Gr="\4)[01T7ajQJvL$W~mL_sS/4h:x*[ZN=KLs&L5zX//>it,o:aU(;Z>pW&T7oP'2K^E:x9'c[%z-,64JQ5AeH_G#KijUKghQw^\vea3a?kka_G$8#`*kynsxzBLru']k_[7FrVx}^=$blx>s-N%j;D*aZDnsw:YKZ%Q.Kne9#hP?+b3(SOvL,^;&u5@?5C5Bhb=m-vEh_L15Jl]U)0RP6{q%L^_z5E'Dw6X @@ -159,7 +171,8 @@ Memory allocation (code space): 3296 ------------------------------------------------------------------ "\$\<\.X\+ix\[d1b\!H\#\?vV0vrK\:ZH1\=2M\>iV\;\?aPhFB\<\*vW\@QW\@sO9\}cfZA\-i\'w\%hKd6gt1UJP\,15_\#QY\$M\^Mss_U\/\]\&LK9\[5vQub\^w\[KDD\qmj\;2\}YWFdYx\.Ap\]hjCPTP\(n28k\+3\;o\&WXqs\/gOXdr\$\:r\'do0\;b4c\(f_Gr\=\"\\4\)\[01T7ajQJvL\$W\~mL_sS\/4h\:x\*\[ZN\=KLs\&L5zX\/\/\>it\,o\:aU\(\;Z\>pW\&T7oP\'2K\^E\:x9\'c\[\%z\-\,64JQ5AeH_G\#KijUKghQw\^\\vea3a\?kka_G\$8\#\`\*kynsxzBLru\'\]k_\[7FrVx\}\^\=\$blx\>s\-N\%j\;D\*aZDnsw\:YKZ\%Q\.Kne9\#hP\?\+b3\(SOvL\,\^\;\&u5\@\?5C5Bhb\=m\-vEh_L15Jl\]U\)0RP6\{q\%L\^_z5E\'Dw6X\b" -Memory allocation (code space): 3256 +Memory allocation - compiled block : 3392 +Memory allocation - code portion : 3256 ------------------------------------------------------------------ 0 811 Bra 2 $<.X+ix[d1b!H#?vV0vrK:ZH1=2M>iV;?aPhFB<*vW@QW@sO9}cfZA-i'w%hKd6gt1UJP,15_#QY$M^Mss_U/]&LK9[5vQub^w[KDDqmj;2}YWFdYx.Ap]hjCPTP(n28k+3;o&WXqs/gOXdr$:r'do0;b4c(f_Gr="\4)[01T7ajQJvL$W~mL_sS/4h:x*[ZN=KLs&L5zX//>it,o:aU(;Z>pW&T7oP'2K^E:x9'c[%z-,64JQ5AeH_G#KijUKghQw^\vea3a?kka_G$8#`*kynsxzBLru']k_[7FrVx}^=$blx>s-N%j;D*aZDnsw:YKZ%Q.Kne9#hP?+b3(SOvL,^;&u5@?5C5Bhb=m-vEh_L15Jl]U)0RP6{q%L^_z5E'Dw6X @@ -169,7 +182,8 @@ Memory allocation (code space): 3256 ------------------------------------------------------------------ /(a(?1)b)/ -Memory allocation (code space): 64 +Memory allocation - compiled block : 200 +Memory allocation - code portion : 64 ------------------------------------------------------------------ 0 13 Bra 2 9 CBra 1 @@ -182,7 +196,8 @@ Memory allocation (code space): 64 ------------------------------------------------------------------ /(a(?1)+b)/ -Memory allocation (code space): 80 +Memory allocation - compiled block : 216 +Memory allocation - code portion : 80 ------------------------------------------------------------------ 0 17 Bra 2 13 CBra 1 @@ -197,7 +212,8 @@ Memory allocation (code space): 80 ------------------------------------------------------------------ /a(?Pb|c)d(?Pe)/ -Memory allocation (code space): 108 +Memory allocation - compiled block : 348 +Memory allocation - code portion : 108 ------------------------------------------------------------------ 0 24 Bra 2 a @@ -215,7 +231,8 @@ Memory allocation (code space): 108 ------------------------------------------------------------------ /(?:a(?Pc(?Pd)))(?Pa)/ -Memory allocation (code space): 128 +Memory allocation - compiled block : 300 +Memory allocation - code portion : 128 ------------------------------------------------------------------ 0 29 Bra 2 18 Bra @@ -235,7 +252,8 @@ Memory allocation (code space): 128 ------------------------------------------------------------------ /(?Pa)...(?P=a)bbb(?P>a)d/ -Memory allocation (code space): 108 +Memory allocation - compiled block : 256 +Memory allocation - code portion : 108 ------------------------------------------------------------------ 0 24 Bra 2 5 CBra 1 @@ -253,7 +271,8 @@ Memory allocation (code space): 108 ------------------------------------------------------------------ /abc(?C255)de(?C)f/ -Memory allocation (code space): 100 +Memory allocation - compiled block : 236 +Memory allocation - code portion : 100 ------------------------------------------------------------------ 0 22 Bra 2 abc @@ -266,7 +285,8 @@ Memory allocation (code space): 100 ------------------------------------------------------------------ /abcde/auto_callout -Memory allocation (code space): 156 +Memory allocation - compiled block : 292 +Memory allocation - code portion : 156 ------------------------------------------------------------------ 0 36 Bra 2 Callout 255 0 1 @@ -285,7 +305,8 @@ Memory allocation (code space): 156 ------------------------------------------------------------------ /\x{100}/utf -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 \x{100} @@ -294,7 +315,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /\x{1000}/utf -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 \x{1000} @@ -303,7 +325,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /\x{10000}/utf -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 \x{10000} @@ -312,7 +335,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /\x{100000}/utf -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 \x{100000} @@ -321,7 +345,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /\x{10ffff}/utf -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 \x{10ffff} @@ -333,7 +358,8 @@ Memory allocation (code space): 28 Failed: error 134 at offset 9: character code point value in \x{} or \o{} is too large /[\x{ff}]/utf -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 \x{ff} @@ -342,7 +368,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /[\x{100}]/utf -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 \x{100} @@ -351,7 +378,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /\x80/utf -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 \x{80} @@ -360,7 +388,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /\xff/utf -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 \x{ff} @@ -369,7 +398,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /\x{0041}\x{2262}\x{0391}\x{002e}/I,utf -Memory allocation (code space): 52 +Memory allocation - compiled block : 188 +Memory allocation - code portion : 52 ------------------------------------------------------------------ 0 10 Bra 2 A\x{2262}\x{391}. @@ -383,7 +413,8 @@ Last code unit = '.' Subject length lower bound = 4 /\x{D55c}\x{ad6d}\x{C5B4}/I,utf -Memory allocation (code space): 44 +Memory allocation - compiled block : 180 +Memory allocation - code portion : 44 ------------------------------------------------------------------ 0 8 Bra 2 \x{d55c}\x{ad6d}\x{c5b4} @@ -397,7 +428,8 @@ Last code unit = \x{c5b4} Subject length lower bound = 3 /\x{65e5}\x{672c}\x{8a9e}/I,utf -Memory allocation (code space): 44 +Memory allocation - compiled block : 180 +Memory allocation - code portion : 44 ------------------------------------------------------------------ 0 8 Bra 2 \x{65e5}\x{672c}\x{8a9e} @@ -411,7 +443,8 @@ Last code unit = \x{8a9e} Subject length lower bound = 3 /[\x{100}]/utf -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 \x{100} @@ -420,7 +453,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /[Z\x{100}]/utf -Memory allocation (code space): 76 +Memory allocation - compiled block : 212 +Memory allocation - code portion : 76 ------------------------------------------------------------------ 0 16 Bra 2 [Z\x{100}] @@ -429,7 +463,8 @@ Memory allocation (code space): 76 ------------------------------------------------------------------ /^[\x{100}\E-\Q\E\x{150}]/utf -Memory allocation (code space): 52 +Memory allocation - compiled block : 188 +Memory allocation - code portion : 52 ------------------------------------------------------------------ 0 10 Bra 2 ^ @@ -439,7 +474,8 @@ Memory allocation (code space): 52 ------------------------------------------------------------------ /^[\QĀ\E-\QŐ\E]/utf -Memory allocation (code space): 52 +Memory allocation - compiled block : 188 +Memory allocation - code portion : 52 ------------------------------------------------------------------ 0 10 Bra 2 ^ @@ -452,7 +488,8 @@ Memory allocation (code space): 52 Failed: error 106 at offset 13: missing terminating ] for character class /[\p{L}]/ -Memory allocation (code space): 48 +Memory allocation - compiled block : 184 +Memory allocation - code portion : 48 ------------------------------------------------------------------ 0 9 Bra 2 [\p{L}] @@ -461,7 +498,8 @@ Memory allocation (code space): 48 ------------------------------------------------------------------ /[\p{^L}]/ -Memory allocation (code space): 48 +Memory allocation - compiled block : 184 +Memory allocation - code portion : 48 ------------------------------------------------------------------ 0 9 Bra 2 [\P{L}] @@ -470,7 +508,8 @@ Memory allocation (code space): 48 ------------------------------------------------------------------ /[\P{L}]/ -Memory allocation (code space): 48 +Memory allocation - compiled block : 184 +Memory allocation - code portion : 48 ------------------------------------------------------------------ 0 9 Bra 2 [\P{L}] @@ -479,7 +518,8 @@ Memory allocation (code space): 48 ------------------------------------------------------------------ /[\P{^L}]/ -Memory allocation (code space): 48 +Memory allocation - compiled block : 184 +Memory allocation - code portion : 48 ------------------------------------------------------------------ 0 9 Bra 2 [\p{L}] @@ -488,7 +528,8 @@ Memory allocation (code space): 48 ------------------------------------------------------------------ /[abc\p{L}\x{0660}]/utf -Memory allocation (code space): 88 +Memory allocation - compiled block : 224 +Memory allocation - code portion : 88 ------------------------------------------------------------------ 0 19 Bra 2 [a-c\p{L}\x{660}] @@ -497,7 +538,8 @@ Memory allocation (code space): 88 ------------------------------------------------------------------ /[\p{Nd}]/utf -Memory allocation (code space): 48 +Memory allocation - compiled block : 184 +Memory allocation - code portion : 48 ------------------------------------------------------------------ 0 9 Bra 2 [\p{Nd}] @@ -506,7 +548,8 @@ Memory allocation (code space): 48 ------------------------------------------------------------------ /[\p{Nd}+-]+/utf -Memory allocation (code space): 84 +Memory allocation - compiled block : 220 +Memory allocation - code portion : 84 ------------------------------------------------------------------ 0 18 Bra 2 [+\-\p{Nd}]++ @@ -515,7 +558,8 @@ Memory allocation (code space): 84 ------------------------------------------------------------------ /A\x{391}\x{10427}\x{ff3a}\x{1fb0}/i,utf -Memory allocation (code space): 60 +Memory allocation - compiled block : 196 +Memory allocation - code portion : 60 ------------------------------------------------------------------ 0 12 Bra 2 /i A\x{391}\x{10427}\x{ff3a}\x{1fb0} @@ -524,7 +568,8 @@ Memory allocation (code space): 60 ------------------------------------------------------------------ /A\x{391}\x{10427}\x{ff3a}\x{1fb0}/utf -Memory allocation (code space): 60 +Memory allocation - compiled block : 196 +Memory allocation - code portion : 60 ------------------------------------------------------------------ 0 12 Bra 2 A\x{391}\x{10427}\x{ff3a}\x{1fb0} @@ -533,7 +578,8 @@ Memory allocation (code space): 60 ------------------------------------------------------------------ /[\x{105}-\x{109}]/i,utf -Memory allocation (code space): 48 +Memory allocation - compiled block : 184 +Memory allocation - code portion : 48 ------------------------------------------------------------------ 0 9 Bra 2 [\x{104}-\x{109}] @@ -542,7 +588,8 @@ Memory allocation (code space): 48 ------------------------------------------------------------------ /( ( (?(1)0|) )* )/x -Memory allocation (code space): 104 +Memory allocation - compiled block : 240 +Memory allocation - code portion : 104 ------------------------------------------------------------------ 0 23 Bra 2 19 CBra 1 @@ -560,7 +607,8 @@ Memory allocation (code space): 104 ------------------------------------------------------------------ /( (?(1)0|)* )/x -Memory allocation (code space): 84 +Memory allocation - compiled block : 220 +Memory allocation - code portion : 84 ------------------------------------------------------------------ 0 18 Bra 2 14 CBra 1 @@ -576,7 +624,8 @@ Memory allocation (code space): 84 ------------------------------------------------------------------ /[a]/ -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 a @@ -585,7 +634,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /[a]/utf -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 a @@ -594,7 +644,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /[\xaa]/ -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 \x{aa} @@ -603,7 +654,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /[\xaa]/utf -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 \x{aa} @@ -612,7 +664,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /[^a]/ -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 [^a] @@ -621,7 +674,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /[^a]/utf -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 [^a] @@ -630,7 +684,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /[^\xaa]/ -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 [^\x{aa}] @@ -639,7 +694,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /[^\xaa]/utf -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 [^\x{aa}] diff --git a/testdata/testoutput8-32-4 b/testdata/testoutput8-32-4 index 91d96c9..d76f3aa 100644 --- a/testdata/testoutput8-32-4 +++ b/testdata/testoutput8-32-4 @@ -10,7 +10,8 @@ #pattern fullbincode,memory /((?i)b)/ -Memory allocation (code space): 48 +Memory allocation - compiled block : 184 +Memory allocation - code portion : 48 ------------------------------------------------------------------ 0 9 Bra 2 5 CBra 1 @@ -21,7 +22,8 @@ Memory allocation (code space): 48 ------------------------------------------------------------------ /(?s)(.*X|^B)/ -Memory allocation (code space): 76 +Memory allocation - compiled block : 212 +Memory allocation - code portion : 76 ------------------------------------------------------------------ 0 16 Bra 2 7 CBra 1 @@ -36,7 +38,8 @@ Memory allocation (code space): 76 ------------------------------------------------------------------ /(?s:.*X|^B)/ -Memory allocation (code space): 72 +Memory allocation - compiled block : 208 +Memory allocation - code portion : 72 ------------------------------------------------------------------ 0 15 Bra 2 6 Bra @@ -51,7 +54,8 @@ Memory allocation (code space): 72 ------------------------------------------------------------------ /^[[:alnum:]]/ -Memory allocation (code space): 60 +Memory allocation - compiled block : 196 +Memory allocation - code portion : 60 ------------------------------------------------------------------ 0 12 Bra 2 ^ @@ -61,7 +65,8 @@ Memory allocation (code space): 60 ------------------------------------------------------------------ /#/Ix -Memory allocation (code space): 20 +Memory allocation - compiled block : 156 +Memory allocation - code portion : 20 ------------------------------------------------------------------ 0 2 Bra 2 2 Ket @@ -73,7 +78,8 @@ Options: extended Subject length lower bound = 0 /a#/Ix -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 a @@ -86,7 +92,8 @@ First code unit = 'a' Subject length lower bound = 1 /x?+/ -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 x?+ @@ -95,7 +102,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /x++/ -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 x++ @@ -104,7 +112,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /x{1,3}+/ -Memory allocation (code space): 40 +Memory allocation - compiled block : 176 +Memory allocation - code portion : 40 ------------------------------------------------------------------ 0 7 Bra 2 x @@ -114,7 +123,8 @@ Memory allocation (code space): 40 ------------------------------------------------------------------ /(x)*+/ -Memory allocation (code space): 52 +Memory allocation - compiled block : 188 +Memory allocation - code portion : 52 ------------------------------------------------------------------ 0 10 Bra 2 Braposzero @@ -126,7 +136,8 @@ Memory allocation (code space): 52 ------------------------------------------------------------------ /^((a+)(?U)([ab]+)(?-U)([bc]+)(\w*))/ -Memory allocation (code space): 220 +Memory allocation - compiled block : 356 +Memory allocation - code portion : 220 ------------------------------------------------------------------ 0 52 Bra 2 ^ @@ -149,7 +160,8 @@ Memory allocation (code space): 220 ------------------------------------------------------------------ "8J\$WE\<\.rX\+ix\[d1b\!H\#\?vV0vrK\:ZH1\=2M\>iV\;\?aPhFB\<\*vW\@QW\@sO9\}cfZA\-i\'w\%hKd6gt1UJP\,15_\#QY\$M\^Mss_U\/\]\&LK9\[5vQub\^w\[KDD\qmj\;2\}YWFdYx\.Ap\]hjCPTP\(n28k\+3\;o\&WXqs\/gOXdr\$\:r\'do0\;b4c\(f_Gr\=\"\\4\)\[01T7ajQJvL\$W\~mL_sS\/4h\:x\*\[ZN\=KLs\&L5zX\/\/\>it\,o\:aU\(\;Z\>pW\&T7oP\'2K\^E\:x9\'c\[\%z\-\,64JQ5AeH_G\#KijUKghQw\^\\vea3a\?kka_G\$8\#\`\*kynsxzBLru\'\]k_\[7FrVx\}\^\=\$blx\>s\-N\%j\;D\*aZDnsw\:YKZ\%Q\.Kne9\#hP\?\+b3\(SOvL\,\^\;\&u5\@\?5C5Bhb\=m\-vEh_L15Jl\]U\)0RP6\{q\%L\^_z5E\'Dw6X\b" -Memory allocation (code space): 3296 +Memory allocation - compiled block : 3432 +Memory allocation - code portion : 3296 ------------------------------------------------------------------ 0 821 Bra 2 8J$WE<.rX+ix[d1b!H#?vV0vrK:ZH1=2M>iV;?aPhFB<*vW@QW@sO9}cfZA-i'w%hKd6gt1UJP,15_#QY$M^Mss_U/]&LK9[5vQub^w[KDDqmj;2}YWFdYx.Ap]hjCPTP(n28k+3;o&WXqs/gOXdr$:r'do0;b4c(f_Gr="\4)[01T7ajQJvL$W~mL_sS/4h:x*[ZN=KLs&L5zX//>it,o:aU(;Z>pW&T7oP'2K^E:x9'c[%z-,64JQ5AeH_G#KijUKghQw^\vea3a?kka_G$8#`*kynsxzBLru']k_[7FrVx}^=$blx>s-N%j;D*aZDnsw:YKZ%Q.Kne9#hP?+b3(SOvL,^;&u5@?5C5Bhb=m-vEh_L15Jl]U)0RP6{q%L^_z5E'Dw6X @@ -159,7 +171,8 @@ Memory allocation (code space): 3296 ------------------------------------------------------------------ "\$\<\.X\+ix\[d1b\!H\#\?vV0vrK\:ZH1\=2M\>iV\;\?aPhFB\<\*vW\@QW\@sO9\}cfZA\-i\'w\%hKd6gt1UJP\,15_\#QY\$M\^Mss_U\/\]\&LK9\[5vQub\^w\[KDD\qmj\;2\}YWFdYx\.Ap\]hjCPTP\(n28k\+3\;o\&WXqs\/gOXdr\$\:r\'do0\;b4c\(f_Gr\=\"\\4\)\[01T7ajQJvL\$W\~mL_sS\/4h\:x\*\[ZN\=KLs\&L5zX\/\/\>it\,o\:aU\(\;Z\>pW\&T7oP\'2K\^E\:x9\'c\[\%z\-\,64JQ5AeH_G\#KijUKghQw\^\\vea3a\?kka_G\$8\#\`\*kynsxzBLru\'\]k_\[7FrVx\}\^\=\$blx\>s\-N\%j\;D\*aZDnsw\:YKZ\%Q\.Kne9\#hP\?\+b3\(SOvL\,\^\;\&u5\@\?5C5Bhb\=m\-vEh_L15Jl\]U\)0RP6\{q\%L\^_z5E\'Dw6X\b" -Memory allocation (code space): 3256 +Memory allocation - compiled block : 3392 +Memory allocation - code portion : 3256 ------------------------------------------------------------------ 0 811 Bra 2 $<.X+ix[d1b!H#?vV0vrK:ZH1=2M>iV;?aPhFB<*vW@QW@sO9}cfZA-i'w%hKd6gt1UJP,15_#QY$M^Mss_U/]&LK9[5vQub^w[KDDqmj;2}YWFdYx.Ap]hjCPTP(n28k+3;o&WXqs/gOXdr$:r'do0;b4c(f_Gr="\4)[01T7ajQJvL$W~mL_sS/4h:x*[ZN=KLs&L5zX//>it,o:aU(;Z>pW&T7oP'2K^E:x9'c[%z-,64JQ5AeH_G#KijUKghQw^\vea3a?kka_G$8#`*kynsxzBLru']k_[7FrVx}^=$blx>s-N%j;D*aZDnsw:YKZ%Q.Kne9#hP?+b3(SOvL,^;&u5@?5C5Bhb=m-vEh_L15Jl]U)0RP6{q%L^_z5E'Dw6X @@ -169,7 +182,8 @@ Memory allocation (code space): 3256 ------------------------------------------------------------------ /(a(?1)b)/ -Memory allocation (code space): 64 +Memory allocation - compiled block : 200 +Memory allocation - code portion : 64 ------------------------------------------------------------------ 0 13 Bra 2 9 CBra 1 @@ -182,7 +196,8 @@ Memory allocation (code space): 64 ------------------------------------------------------------------ /(a(?1)+b)/ -Memory allocation (code space): 80 +Memory allocation - compiled block : 216 +Memory allocation - code portion : 80 ------------------------------------------------------------------ 0 17 Bra 2 13 CBra 1 @@ -197,7 +212,8 @@ Memory allocation (code space): 80 ------------------------------------------------------------------ /a(?Pb|c)d(?Pe)/ -Memory allocation (code space): 108 +Memory allocation - compiled block : 348 +Memory allocation - code portion : 108 ------------------------------------------------------------------ 0 24 Bra 2 a @@ -215,7 +231,8 @@ Memory allocation (code space): 108 ------------------------------------------------------------------ /(?:a(?Pc(?Pd)))(?Pa)/ -Memory allocation (code space): 128 +Memory allocation - compiled block : 300 +Memory allocation - code portion : 128 ------------------------------------------------------------------ 0 29 Bra 2 18 Bra @@ -235,7 +252,8 @@ Memory allocation (code space): 128 ------------------------------------------------------------------ /(?Pa)...(?P=a)bbb(?P>a)d/ -Memory allocation (code space): 108 +Memory allocation - compiled block : 256 +Memory allocation - code portion : 108 ------------------------------------------------------------------ 0 24 Bra 2 5 CBra 1 @@ -253,7 +271,8 @@ Memory allocation (code space): 108 ------------------------------------------------------------------ /abc(?C255)de(?C)f/ -Memory allocation (code space): 100 +Memory allocation - compiled block : 236 +Memory allocation - code portion : 100 ------------------------------------------------------------------ 0 22 Bra 2 abc @@ -266,7 +285,8 @@ Memory allocation (code space): 100 ------------------------------------------------------------------ /abcde/auto_callout -Memory allocation (code space): 156 +Memory allocation - compiled block : 292 +Memory allocation - code portion : 156 ------------------------------------------------------------------ 0 36 Bra 2 Callout 255 0 1 @@ -285,7 +305,8 @@ Memory allocation (code space): 156 ------------------------------------------------------------------ /\x{100}/utf -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 \x{100} @@ -294,7 +315,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /\x{1000}/utf -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 \x{1000} @@ -303,7 +325,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /\x{10000}/utf -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 \x{10000} @@ -312,7 +335,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /\x{100000}/utf -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 \x{100000} @@ -321,7 +345,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /\x{10ffff}/utf -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 \x{10ffff} @@ -333,7 +358,8 @@ Memory allocation (code space): 28 Failed: error 134 at offset 9: character code point value in \x{} or \o{} is too large /[\x{ff}]/utf -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 \x{ff} @@ -342,7 +368,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /[\x{100}]/utf -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 \x{100} @@ -351,7 +378,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /\x80/utf -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 \x{80} @@ -360,7 +388,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /\xff/utf -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 \x{ff} @@ -369,7 +398,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /\x{0041}\x{2262}\x{0391}\x{002e}/I,utf -Memory allocation (code space): 52 +Memory allocation - compiled block : 188 +Memory allocation - code portion : 52 ------------------------------------------------------------------ 0 10 Bra 2 A\x{2262}\x{391}. @@ -383,7 +413,8 @@ Last code unit = '.' Subject length lower bound = 4 /\x{D55c}\x{ad6d}\x{C5B4}/I,utf -Memory allocation (code space): 44 +Memory allocation - compiled block : 180 +Memory allocation - code portion : 44 ------------------------------------------------------------------ 0 8 Bra 2 \x{d55c}\x{ad6d}\x{c5b4} @@ -397,7 +428,8 @@ Last code unit = \x{c5b4} Subject length lower bound = 3 /\x{65e5}\x{672c}\x{8a9e}/I,utf -Memory allocation (code space): 44 +Memory allocation - compiled block : 180 +Memory allocation - code portion : 44 ------------------------------------------------------------------ 0 8 Bra 2 \x{65e5}\x{672c}\x{8a9e} @@ -411,7 +443,8 @@ Last code unit = \x{8a9e} Subject length lower bound = 3 /[\x{100}]/utf -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 \x{100} @@ -420,7 +453,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /[Z\x{100}]/utf -Memory allocation (code space): 76 +Memory allocation - compiled block : 212 +Memory allocation - code portion : 76 ------------------------------------------------------------------ 0 16 Bra 2 [Z\x{100}] @@ -429,7 +463,8 @@ Memory allocation (code space): 76 ------------------------------------------------------------------ /^[\x{100}\E-\Q\E\x{150}]/utf -Memory allocation (code space): 52 +Memory allocation - compiled block : 188 +Memory allocation - code portion : 52 ------------------------------------------------------------------ 0 10 Bra 2 ^ @@ -439,7 +474,8 @@ Memory allocation (code space): 52 ------------------------------------------------------------------ /^[\QĀ\E-\QŐ\E]/utf -Memory allocation (code space): 52 +Memory allocation - compiled block : 188 +Memory allocation - code portion : 52 ------------------------------------------------------------------ 0 10 Bra 2 ^ @@ -452,7 +488,8 @@ Memory allocation (code space): 52 Failed: error 106 at offset 13: missing terminating ] for character class /[\p{L}]/ -Memory allocation (code space): 48 +Memory allocation - compiled block : 184 +Memory allocation - code portion : 48 ------------------------------------------------------------------ 0 9 Bra 2 [\p{L}] @@ -461,7 +498,8 @@ Memory allocation (code space): 48 ------------------------------------------------------------------ /[\p{^L}]/ -Memory allocation (code space): 48 +Memory allocation - compiled block : 184 +Memory allocation - code portion : 48 ------------------------------------------------------------------ 0 9 Bra 2 [\P{L}] @@ -470,7 +508,8 @@ Memory allocation (code space): 48 ------------------------------------------------------------------ /[\P{L}]/ -Memory allocation (code space): 48 +Memory allocation - compiled block : 184 +Memory allocation - code portion : 48 ------------------------------------------------------------------ 0 9 Bra 2 [\P{L}] @@ -479,7 +518,8 @@ Memory allocation (code space): 48 ------------------------------------------------------------------ /[\P{^L}]/ -Memory allocation (code space): 48 +Memory allocation - compiled block : 184 +Memory allocation - code portion : 48 ------------------------------------------------------------------ 0 9 Bra 2 [\p{L}] @@ -488,7 +528,8 @@ Memory allocation (code space): 48 ------------------------------------------------------------------ /[abc\p{L}\x{0660}]/utf -Memory allocation (code space): 88 +Memory allocation - compiled block : 224 +Memory allocation - code portion : 88 ------------------------------------------------------------------ 0 19 Bra 2 [a-c\p{L}\x{660}] @@ -497,7 +538,8 @@ Memory allocation (code space): 88 ------------------------------------------------------------------ /[\p{Nd}]/utf -Memory allocation (code space): 48 +Memory allocation - compiled block : 184 +Memory allocation - code portion : 48 ------------------------------------------------------------------ 0 9 Bra 2 [\p{Nd}] @@ -506,7 +548,8 @@ Memory allocation (code space): 48 ------------------------------------------------------------------ /[\p{Nd}+-]+/utf -Memory allocation (code space): 84 +Memory allocation - compiled block : 220 +Memory allocation - code portion : 84 ------------------------------------------------------------------ 0 18 Bra 2 [+\-\p{Nd}]++ @@ -515,7 +558,8 @@ Memory allocation (code space): 84 ------------------------------------------------------------------ /A\x{391}\x{10427}\x{ff3a}\x{1fb0}/i,utf -Memory allocation (code space): 60 +Memory allocation - compiled block : 196 +Memory allocation - code portion : 60 ------------------------------------------------------------------ 0 12 Bra 2 /i A\x{391}\x{10427}\x{ff3a}\x{1fb0} @@ -524,7 +568,8 @@ Memory allocation (code space): 60 ------------------------------------------------------------------ /A\x{391}\x{10427}\x{ff3a}\x{1fb0}/utf -Memory allocation (code space): 60 +Memory allocation - compiled block : 196 +Memory allocation - code portion : 60 ------------------------------------------------------------------ 0 12 Bra 2 A\x{391}\x{10427}\x{ff3a}\x{1fb0} @@ -533,7 +578,8 @@ Memory allocation (code space): 60 ------------------------------------------------------------------ /[\x{105}-\x{109}]/i,utf -Memory allocation (code space): 48 +Memory allocation - compiled block : 184 +Memory allocation - code portion : 48 ------------------------------------------------------------------ 0 9 Bra 2 [\x{104}-\x{109}] @@ -542,7 +588,8 @@ Memory allocation (code space): 48 ------------------------------------------------------------------ /( ( (?(1)0|) )* )/x -Memory allocation (code space): 104 +Memory allocation - compiled block : 240 +Memory allocation - code portion : 104 ------------------------------------------------------------------ 0 23 Bra 2 19 CBra 1 @@ -560,7 +607,8 @@ Memory allocation (code space): 104 ------------------------------------------------------------------ /( (?(1)0|)* )/x -Memory allocation (code space): 84 +Memory allocation - compiled block : 220 +Memory allocation - code portion : 84 ------------------------------------------------------------------ 0 18 Bra 2 14 CBra 1 @@ -576,7 +624,8 @@ Memory allocation (code space): 84 ------------------------------------------------------------------ /[a]/ -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 a @@ -585,7 +634,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /[a]/utf -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 a @@ -594,7 +644,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /[\xaa]/ -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 \x{aa} @@ -603,7 +654,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /[\xaa]/utf -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 \x{aa} @@ -612,7 +664,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /[^a]/ -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 [^a] @@ -621,7 +674,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /[^a]/utf -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 [^a] @@ -630,7 +684,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /[^\xaa]/ -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 [^\x{aa}] @@ -639,7 +694,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /[^\xaa]/utf -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 4 Bra 2 [^\x{aa}] diff --git a/testdata/testoutput8-8-2 b/testdata/testoutput8-8-2 index e9568e5..f3811d9 100644 --- a/testdata/testoutput8-8-2 +++ b/testdata/testoutput8-8-2 @@ -10,7 +10,8 @@ #pattern fullbincode,memory /((?i)b)/ -Memory allocation (code space): 17 +Memory allocation - compiled block : 153 +Memory allocation - code portion : 17 ------------------------------------------------------------------ 0 13 Bra 3 7 CBra 1 @@ -21,7 +22,8 @@ Memory allocation (code space): 17 ------------------------------------------------------------------ /(?s)(.*X|^B)/ -Memory allocation (code space): 25 +Memory allocation - compiled block : 161 +Memory allocation - code portion : 25 ------------------------------------------------------------------ 0 21 Bra 3 9 CBra 1 @@ -36,7 +38,8 @@ Memory allocation (code space): 25 ------------------------------------------------------------------ /(?s:.*X|^B)/ -Memory allocation (code space): 23 +Memory allocation - compiled block : 159 +Memory allocation - code portion : 23 ------------------------------------------------------------------ 0 19 Bra 3 7 Bra @@ -51,7 +54,8 @@ Memory allocation (code space): 23 ------------------------------------------------------------------ /^[[:alnum:]]/ -Memory allocation (code space): 41 +Memory allocation - compiled block : 177 +Memory allocation - code portion : 41 ------------------------------------------------------------------ 0 37 Bra 3 ^ @@ -61,7 +65,8 @@ Memory allocation (code space): 41 ------------------------------------------------------------------ /#/Ix -Memory allocation (code space): 7 +Memory allocation - compiled block : 143 +Memory allocation - code portion : 7 ------------------------------------------------------------------ 0 3 Bra 3 3 Ket @@ -73,7 +78,8 @@ Options: extended Subject length lower bound = 0 /a#/Ix -Memory allocation (code space): 9 +Memory allocation - compiled block : 145 +Memory allocation - code portion : 9 ------------------------------------------------------------------ 0 5 Bra 3 a @@ -86,7 +92,8 @@ First code unit = 'a' Subject length lower bound = 1 /x?+/ -Memory allocation (code space): 9 +Memory allocation - compiled block : 145 +Memory allocation - code portion : 9 ------------------------------------------------------------------ 0 5 Bra 3 x?+ @@ -95,7 +102,8 @@ Memory allocation (code space): 9 ------------------------------------------------------------------ /x++/ -Memory allocation (code space): 9 +Memory allocation - compiled block : 145 +Memory allocation - code portion : 9 ------------------------------------------------------------------ 0 5 Bra 3 x++ @@ -104,7 +112,8 @@ Memory allocation (code space): 9 ------------------------------------------------------------------ /x{1,3}+/ -Memory allocation (code space): 13 +Memory allocation - compiled block : 149 +Memory allocation - code portion : 13 ------------------------------------------------------------------ 0 9 Bra 3 x @@ -114,7 +123,8 @@ Memory allocation (code space): 13 ------------------------------------------------------------------ /(x)*+/ -Memory allocation (code space): 18 +Memory allocation - compiled block : 154 +Memory allocation - code portion : 18 ------------------------------------------------------------------ 0 14 Bra 3 Braposzero @@ -126,7 +136,8 @@ Memory allocation (code space): 18 ------------------------------------------------------------------ /^((a+)(?U)([ab]+)(?-U)([bc]+)(\w*))/ -Memory allocation (code space): 120 +Memory allocation - compiled block : 256 +Memory allocation - code portion : 120 ------------------------------------------------------------------ 0 116 Bra 3 ^ @@ -149,7 +160,8 @@ Memory allocation (code space): 120 ------------------------------------------------------------------ "8J\$WE\<\.rX\+ix\[d1b\!H\#\?vV0vrK\:ZH1\=2M\>iV\;\?aPhFB\<\*vW\@QW\@sO9\}cfZA\-i\'w\%hKd6gt1UJP\,15_\#QY\$M\^Mss_U\/\]\&LK9\[5vQub\^w\[KDD\qmj\;2\}YWFdYx\.Ap\]hjCPTP\(n28k\+3\;o\&WXqs\/gOXdr\$\:r\'do0\;b4c\(f_Gr\=\"\\4\)\[01T7ajQJvL\$W\~mL_sS\/4h\:x\*\[ZN\=KLs\&L5zX\/\/\>it\,o\:aU\(\;Z\>pW\&T7oP\'2K\^E\:x9\'c\[\%z\-\,64JQ5AeH_G\#KijUKghQw\^\\vea3a\?kka_G\$8\#\`\*kynsxzBLru\'\]k_\[7FrVx\}\^\=\$blx\>s\-N\%j\;D\*aZDnsw\:YKZ\%Q\.Kne9\#hP\?\+b3\(SOvL\,\^\;\&u5\@\?5C5Bhb\=m\-vEh_L15Jl\]U\)0RP6\{q\%L\^_z5E\'Dw6X\b" -Memory allocation (code space): 826 +Memory allocation - compiled block : 962 +Memory allocation - code portion : 826 ------------------------------------------------------------------ 0 822 Bra 3 8J$WE<.rX+ix[d1b!H#?vV0vrK:ZH1=2M>iV;?aPhFB<*vW@QW@sO9}cfZA-i'w%hKd6gt1UJP,15_#QY$M^Mss_U/]&LK9[5vQub^w[KDDqmj;2}YWFdYx.Ap]hjCPTP(n28k+3;o&WXqs/gOXdr$:r'do0;b4c(f_Gr="\4)[01T7ajQJvL$W~mL_sS/4h:x*[ZN=KLs&L5zX//>it,o:aU(;Z>pW&T7oP'2K^E:x9'c[%z-,64JQ5AeH_G#KijUKghQw^\vea3a?kka_G$8#`*kynsxzBLru']k_[7FrVx}^=$blx>s-N%j;D*aZDnsw:YKZ%Q.Kne9#hP?+b3(SOvL,^;&u5@?5C5Bhb=m-vEh_L15Jl]U)0RP6{q%L^_z5E'Dw6X @@ -159,7 +171,8 @@ Memory allocation (code space): 826 ------------------------------------------------------------------ "\$\<\.X\+ix\[d1b\!H\#\?vV0vrK\:ZH1\=2M\>iV\;\?aPhFB\<\*vW\@QW\@sO9\}cfZA\-i\'w\%hKd6gt1UJP\,15_\#QY\$M\^Mss_U\/\]\&LK9\[5vQub\^w\[KDD\qmj\;2\}YWFdYx\.Ap\]hjCPTP\(n28k\+3\;o\&WXqs\/gOXdr\$\:r\'do0\;b4c\(f_Gr\=\"\\4\)\[01T7ajQJvL\$W\~mL_sS\/4h\:x\*\[ZN\=KLs\&L5zX\/\/\>it\,o\:aU\(\;Z\>pW\&T7oP\'2K\^E\:x9\'c\[\%z\-\,64JQ5AeH_G\#KijUKghQw\^\\vea3a\?kka_G\$8\#\`\*kynsxzBLru\'\]k_\[7FrVx\}\^\=\$blx\>s\-N\%j\;D\*aZDnsw\:YKZ\%Q\.Kne9\#hP\?\+b3\(SOvL\,\^\;\&u5\@\?5C5Bhb\=m\-vEh_L15Jl\]U\)0RP6\{q\%L\^_z5E\'Dw6X\b" -Memory allocation (code space): 816 +Memory allocation - compiled block : 952 +Memory allocation - code portion : 816 ------------------------------------------------------------------ 0 812 Bra 3 $<.X+ix[d1b!H#?vV0vrK:ZH1=2M>iV;?aPhFB<*vW@QW@sO9}cfZA-i'w%hKd6gt1UJP,15_#QY$M^Mss_U/]&LK9[5vQub^w[KDDqmj;2}YWFdYx.Ap]hjCPTP(n28k+3;o&WXqs/gOXdr$:r'do0;b4c(f_Gr="\4)[01T7ajQJvL$W~mL_sS/4h:x*[ZN=KLs&L5zX//>it,o:aU(;Z>pW&T7oP'2K^E:x9'c[%z-,64JQ5AeH_G#KijUKghQw^\vea3a?kka_G$8#`*kynsxzBLru']k_[7FrVx}^=$blx>s-N%j;D*aZDnsw:YKZ%Q.Kne9#hP?+b3(SOvL,^;&u5@?5C5Bhb=m-vEh_L15Jl]U)0RP6{q%L^_z5E'Dw6X @@ -169,7 +182,8 @@ Memory allocation (code space): 816 ------------------------------------------------------------------ /(a(?1)b)/ -Memory allocation (code space): 22 +Memory allocation - compiled block : 158 +Memory allocation - code portion : 22 ------------------------------------------------------------------ 0 18 Bra 3 12 CBra 1 @@ -182,7 +196,8 @@ Memory allocation (code space): 22 ------------------------------------------------------------------ /(a(?1)+b)/ -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 24 Bra 3 18 CBra 1 @@ -197,7 +212,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /a(?Pb|c)d(?Pe)/ -Memory allocation (code space): 36 +Memory allocation - compiled block : 200 +Memory allocation - code portion : 36 ------------------------------------------------------------------ 0 32 Bra 3 a @@ -215,7 +231,8 @@ Memory allocation (code space): 36 ------------------------------------------------------------------ /(?:a(?Pc(?Pd)))(?Pa)/ -Memory allocation (code space): 45 +Memory allocation - compiled block : 193 +Memory allocation - code portion : 45 ------------------------------------------------------------------ 0 41 Bra 3 25 Bra @@ -235,7 +252,8 @@ Memory allocation (code space): 45 ------------------------------------------------------------------ /(?Pa)...(?P=a)bbb(?P>a)d/ -Memory allocation (code space): 34 +Memory allocation - compiled block : 174 +Memory allocation - code portion : 34 ------------------------------------------------------------------ 0 30 Bra 3 7 CBra 1 @@ -253,7 +271,8 @@ Memory allocation (code space): 34 ------------------------------------------------------------------ /abc(?C255)de(?C)f/ -Memory allocation (code space): 31 +Memory allocation - compiled block : 167 +Memory allocation - code portion : 31 ------------------------------------------------------------------ 0 27 Bra 3 abc @@ -266,7 +285,8 @@ Memory allocation (code space): 31 ------------------------------------------------------------------ /abcde/auto_callout -Memory allocation (code space): 53 +Memory allocation - compiled block : 189 +Memory allocation - code portion : 53 ------------------------------------------------------------------ 0 49 Bra 3 Callout 255 0 1 @@ -285,7 +305,8 @@ Memory allocation (code space): 53 ------------------------------------------------------------------ /\x{100}/utf -Memory allocation (code space): 10 +Memory allocation - compiled block : 146 +Memory allocation - code portion : 10 ------------------------------------------------------------------ 0 6 Bra 3 \x{100} @@ -294,7 +315,8 @@ Memory allocation (code space): 10 ------------------------------------------------------------------ /\x{1000}/utf -Memory allocation (code space): 11 +Memory allocation - compiled block : 147 +Memory allocation - code portion : 11 ------------------------------------------------------------------ 0 7 Bra 3 \x{1000} @@ -303,7 +325,8 @@ Memory allocation (code space): 11 ------------------------------------------------------------------ /\x{10000}/utf -Memory allocation (code space): 12 +Memory allocation - compiled block : 148 +Memory allocation - code portion : 12 ------------------------------------------------------------------ 0 8 Bra 3 \x{10000} @@ -312,7 +335,8 @@ Memory allocation (code space): 12 ------------------------------------------------------------------ /\x{100000}/utf -Memory allocation (code space): 12 +Memory allocation - compiled block : 148 +Memory allocation - code portion : 12 ------------------------------------------------------------------ 0 8 Bra 3 \x{100000} @@ -321,7 +345,8 @@ Memory allocation (code space): 12 ------------------------------------------------------------------ /\x{10ffff}/utf -Memory allocation (code space): 12 +Memory allocation - compiled block : 148 +Memory allocation - code portion : 12 ------------------------------------------------------------------ 0 8 Bra 3 \x{10ffff} @@ -333,7 +358,8 @@ Memory allocation (code space): 12 Failed: error 134 at offset 9: character code point value in \x{} or \o{} is too large /[\x{ff}]/utf -Memory allocation (code space): 10 +Memory allocation - compiled block : 146 +Memory allocation - code portion : 10 ------------------------------------------------------------------ 0 6 Bra 3 \x{ff} @@ -342,7 +368,8 @@ Memory allocation (code space): 10 ------------------------------------------------------------------ /[\x{100}]/utf -Memory allocation (code space): 10 +Memory allocation - compiled block : 146 +Memory allocation - code portion : 10 ------------------------------------------------------------------ 0 6 Bra 3 \x{100} @@ -351,7 +378,8 @@ Memory allocation (code space): 10 ------------------------------------------------------------------ /\x80/utf -Memory allocation (code space): 10 +Memory allocation - compiled block : 146 +Memory allocation - code portion : 10 ------------------------------------------------------------------ 0 6 Bra 3 \x{80} @@ -360,7 +388,8 @@ Memory allocation (code space): 10 ------------------------------------------------------------------ /\xff/utf -Memory allocation (code space): 10 +Memory allocation - compiled block : 146 +Memory allocation - code portion : 10 ------------------------------------------------------------------ 0 6 Bra 3 \x{ff} @@ -369,7 +398,8 @@ Memory allocation (code space): 10 ------------------------------------------------------------------ /\x{0041}\x{2262}\x{0391}\x{002e}/I,utf -Memory allocation (code space): 18 +Memory allocation - compiled block : 154 +Memory allocation - code portion : 18 ------------------------------------------------------------------ 0 14 Bra 3 A\x{2262}\x{391}. @@ -383,7 +413,8 @@ Last code unit = '.' Subject length lower bound = 4 /\x{D55c}\x{ad6d}\x{C5B4}/I,utf -Memory allocation (code space): 19 +Memory allocation - compiled block : 155 +Memory allocation - code portion : 19 ------------------------------------------------------------------ 0 15 Bra 3 \x{d55c}\x{ad6d}\x{c5b4} @@ -397,7 +428,8 @@ Last code unit = \xb4 Subject length lower bound = 3 /\x{65e5}\x{672c}\x{8a9e}/I,utf -Memory allocation (code space): 19 +Memory allocation - compiled block : 155 +Memory allocation - code portion : 19 ------------------------------------------------------------------ 0 15 Bra 3 \x{65e5}\x{672c}\x{8a9e} @@ -411,7 +443,8 @@ Last code unit = \x9e Subject length lower bound = 3 /[\x{100}]/utf -Memory allocation (code space): 10 +Memory allocation - compiled block : 146 +Memory allocation - code portion : 10 ------------------------------------------------------------------ 0 6 Bra 3 \x{100} @@ -420,7 +453,8 @@ Memory allocation (code space): 10 ------------------------------------------------------------------ /[Z\x{100}]/utf -Memory allocation (code space): 47 +Memory allocation - compiled block : 183 +Memory allocation - code portion : 47 ------------------------------------------------------------------ 0 43 Bra 3 [Z\x{100}] @@ -429,7 +463,8 @@ Memory allocation (code space): 47 ------------------------------------------------------------------ /^[\x{100}\E-\Q\E\x{150}]/utf -Memory allocation (code space): 18 +Memory allocation - compiled block : 154 +Memory allocation - code portion : 18 ------------------------------------------------------------------ 0 14 Bra 3 ^ @@ -439,7 +474,8 @@ Memory allocation (code space): 18 ------------------------------------------------------------------ /^[\QĀ\E-\QŐ\E]/utf -Memory allocation (code space): 18 +Memory allocation - compiled block : 154 +Memory allocation - code portion : 18 ------------------------------------------------------------------ 0 14 Bra 3 ^ @@ -452,7 +488,8 @@ Memory allocation (code space): 18 Failed: error 106 at offset 15: missing terminating ] for character class /[\p{L}]/ -Memory allocation (code space): 15 +Memory allocation - compiled block : 151 +Memory allocation - code portion : 15 ------------------------------------------------------------------ 0 11 Bra 3 [\p{L}] @@ -461,7 +498,8 @@ Memory allocation (code space): 15 ------------------------------------------------------------------ /[\p{^L}]/ -Memory allocation (code space): 15 +Memory allocation - compiled block : 151 +Memory allocation - code portion : 15 ------------------------------------------------------------------ 0 11 Bra 3 [\P{L}] @@ -470,7 +508,8 @@ Memory allocation (code space): 15 ------------------------------------------------------------------ /[\P{L}]/ -Memory allocation (code space): 15 +Memory allocation - compiled block : 151 +Memory allocation - code portion : 15 ------------------------------------------------------------------ 0 11 Bra 3 [\P{L}] @@ -479,7 +518,8 @@ Memory allocation (code space): 15 ------------------------------------------------------------------ /[\P{^L}]/ -Memory allocation (code space): 15 +Memory allocation - compiled block : 151 +Memory allocation - code portion : 15 ------------------------------------------------------------------ 0 11 Bra 3 [\p{L}] @@ -488,7 +528,8 @@ Memory allocation (code space): 15 ------------------------------------------------------------------ /[abc\p{L}\x{0660}]/utf -Memory allocation (code space): 50 +Memory allocation - compiled block : 186 +Memory allocation - code portion : 50 ------------------------------------------------------------------ 0 46 Bra 3 [a-c\p{L}\x{660}] @@ -497,7 +538,8 @@ Memory allocation (code space): 50 ------------------------------------------------------------------ /[\p{Nd}]/utf -Memory allocation (code space): 15 +Memory allocation - compiled block : 151 +Memory allocation - code portion : 15 ------------------------------------------------------------------ 0 11 Bra 3 [\p{Nd}] @@ -506,7 +548,8 @@ Memory allocation (code space): 15 ------------------------------------------------------------------ /[\p{Nd}+-]+/utf -Memory allocation (code space): 48 +Memory allocation - compiled block : 184 +Memory allocation - code portion : 48 ------------------------------------------------------------------ 0 44 Bra 3 [+\-\p{Nd}]++ @@ -515,7 +558,8 @@ Memory allocation (code space): 48 ------------------------------------------------------------------ /A\x{391}\x{10427}\x{ff3a}\x{1fb0}/i,utf -Memory allocation (code space): 25 +Memory allocation - compiled block : 161 +Memory allocation - code portion : 25 ------------------------------------------------------------------ 0 21 Bra 3 /i A\x{391}\x{10427}\x{ff3a}\x{1fb0} @@ -524,7 +568,8 @@ Memory allocation (code space): 25 ------------------------------------------------------------------ /A\x{391}\x{10427}\x{ff3a}\x{1fb0}/utf -Memory allocation (code space): 25 +Memory allocation - compiled block : 161 +Memory allocation - code portion : 25 ------------------------------------------------------------------ 0 21 Bra 3 A\x{391}\x{10427}\x{ff3a}\x{1fb0} @@ -533,7 +578,8 @@ Memory allocation (code space): 25 ------------------------------------------------------------------ /[\x{105}-\x{109}]/i,utf -Memory allocation (code space): 17 +Memory allocation - compiled block : 153 +Memory allocation - code portion : 17 ------------------------------------------------------------------ 0 13 Bra 3 [\x{104}-\x{109}] @@ -542,7 +588,8 @@ Memory allocation (code space): 17 ------------------------------------------------------------------ /( ( (?(1)0|) )* )/x -Memory allocation (code space): 38 +Memory allocation - compiled block : 174 +Memory allocation - code portion : 38 ------------------------------------------------------------------ 0 34 Bra 3 28 CBra 1 @@ -560,7 +607,8 @@ Memory allocation (code space): 38 ------------------------------------------------------------------ /( (?(1)0|)* )/x -Memory allocation (code space): 30 +Memory allocation - compiled block : 166 +Memory allocation - code portion : 30 ------------------------------------------------------------------ 0 26 Bra 3 20 CBra 1 @@ -576,7 +624,8 @@ Memory allocation (code space): 30 ------------------------------------------------------------------ /[a]/ -Memory allocation (code space): 9 +Memory allocation - compiled block : 145 +Memory allocation - code portion : 9 ------------------------------------------------------------------ 0 5 Bra 3 a @@ -585,7 +634,8 @@ Memory allocation (code space): 9 ------------------------------------------------------------------ /[a]/utf -Memory allocation (code space): 9 +Memory allocation - compiled block : 145 +Memory allocation - code portion : 9 ------------------------------------------------------------------ 0 5 Bra 3 a @@ -594,7 +644,8 @@ Memory allocation (code space): 9 ------------------------------------------------------------------ /[\xaa]/ -Memory allocation (code space): 9 +Memory allocation - compiled block : 145 +Memory allocation - code portion : 9 ------------------------------------------------------------------ 0 5 Bra 3 \x{aa} @@ -603,7 +654,8 @@ Memory allocation (code space): 9 ------------------------------------------------------------------ /[\xaa]/utf -Memory allocation (code space): 10 +Memory allocation - compiled block : 146 +Memory allocation - code portion : 10 ------------------------------------------------------------------ 0 6 Bra 3 \x{aa} @@ -612,7 +664,8 @@ Memory allocation (code space): 10 ------------------------------------------------------------------ /[^a]/ -Memory allocation (code space): 9 +Memory allocation - compiled block : 145 +Memory allocation - code portion : 9 ------------------------------------------------------------------ 0 5 Bra 3 [^a] @@ -621,7 +674,8 @@ Memory allocation (code space): 9 ------------------------------------------------------------------ /[^a]/utf -Memory allocation (code space): 9 +Memory allocation - compiled block : 145 +Memory allocation - code portion : 9 ------------------------------------------------------------------ 0 5 Bra 3 [^a] @@ -630,7 +684,8 @@ Memory allocation (code space): 9 ------------------------------------------------------------------ /[^\xaa]/ -Memory allocation (code space): 9 +Memory allocation - compiled block : 145 +Memory allocation - code portion : 9 ------------------------------------------------------------------ 0 5 Bra 3 [^\x{aa}] @@ -639,7 +694,8 @@ Memory allocation (code space): 9 ------------------------------------------------------------------ /[^\xaa]/utf -Memory allocation (code space): 10 +Memory allocation - compiled block : 146 +Memory allocation - code portion : 10 ------------------------------------------------------------------ 0 6 Bra 3 [^\x{aa}] diff --git a/testdata/testoutput8-8-3 b/testdata/testoutput8-8-3 index 963700a..48e0b8a 100644 --- a/testdata/testoutput8-8-3 +++ b/testdata/testoutput8-8-3 @@ -10,7 +10,8 @@ #pattern fullbincode,memory /((?i)b)/ -Memory allocation (code space): 21 +Memory allocation - compiled block : 157 +Memory allocation - code portion : 21 ------------------------------------------------------------------ 0 16 Bra 4 8 CBra 1 @@ -21,7 +22,8 @@ Memory allocation (code space): 21 ------------------------------------------------------------------ /(?s)(.*X|^B)/ -Memory allocation (code space): 30 +Memory allocation - compiled block : 166 +Memory allocation - code portion : 30 ------------------------------------------------------------------ 0 25 Bra 4 10 CBra 1 @@ -36,7 +38,8 @@ Memory allocation (code space): 30 ------------------------------------------------------------------ /(?s:.*X|^B)/ -Memory allocation (code space): 28 +Memory allocation - compiled block : 164 +Memory allocation - code portion : 28 ------------------------------------------------------------------ 0 23 Bra 4 8 Bra @@ -51,7 +54,8 @@ Memory allocation (code space): 28 ------------------------------------------------------------------ /^[[:alnum:]]/ -Memory allocation (code space): 43 +Memory allocation - compiled block : 179 +Memory allocation - code portion : 43 ------------------------------------------------------------------ 0 38 Bra 4 ^ @@ -61,7 +65,8 @@ Memory allocation (code space): 43 ------------------------------------------------------------------ /#/Ix -Memory allocation (code space): 9 +Memory allocation - compiled block : 145 +Memory allocation - code portion : 9 ------------------------------------------------------------------ 0 4 Bra 4 4 Ket @@ -73,7 +78,8 @@ Options: extended Subject length lower bound = 0 /a#/Ix -Memory allocation (code space): 11 +Memory allocation - compiled block : 147 +Memory allocation - code portion : 11 ------------------------------------------------------------------ 0 6 Bra 4 a @@ -86,7 +92,8 @@ First code unit = 'a' Subject length lower bound = 1 /x?+/ -Memory allocation (code space): 11 +Memory allocation - compiled block : 147 +Memory allocation - code portion : 11 ------------------------------------------------------------------ 0 6 Bra 4 x?+ @@ -95,7 +102,8 @@ Memory allocation (code space): 11 ------------------------------------------------------------------ /x++/ -Memory allocation (code space): 11 +Memory allocation - compiled block : 147 +Memory allocation - code portion : 11 ------------------------------------------------------------------ 0 6 Bra 4 x++ @@ -104,7 +112,8 @@ Memory allocation (code space): 11 ------------------------------------------------------------------ /x{1,3}+/ -Memory allocation (code space): 15 +Memory allocation - compiled block : 151 +Memory allocation - code portion : 15 ------------------------------------------------------------------ 0 10 Bra 4 x @@ -114,7 +123,8 @@ Memory allocation (code space): 15 ------------------------------------------------------------------ /(x)*+/ -Memory allocation (code space): 22 +Memory allocation - compiled block : 158 +Memory allocation - code portion : 22 ------------------------------------------------------------------ 0 17 Bra 4 Braposzero @@ -126,7 +136,8 @@ Memory allocation (code space): 22 ------------------------------------------------------------------ /^((a+)(?U)([ab]+)(?-U)([bc]+)(\w*))/ -Memory allocation (code space): 132 +Memory allocation - compiled block : 268 +Memory allocation - code portion : 132 ------------------------------------------------------------------ 0 127 Bra 4 ^ @@ -149,7 +160,8 @@ Memory allocation (code space): 132 ------------------------------------------------------------------ "8J\$WE\<\.rX\+ix\[d1b\!H\#\?vV0vrK\:ZH1\=2M\>iV\;\?aPhFB\<\*vW\@QW\@sO9\}cfZA\-i\'w\%hKd6gt1UJP\,15_\#QY\$M\^Mss_U\/\]\&LK9\[5vQub\^w\[KDD\qmj\;2\}YWFdYx\.Ap\]hjCPTP\(n28k\+3\;o\&WXqs\/gOXdr\$\:r\'do0\;b4c\(f_Gr\=\"\\4\)\[01T7ajQJvL\$W\~mL_sS\/4h\:x\*\[ZN\=KLs\&L5zX\/\/\>it\,o\:aU\(\;Z\>pW\&T7oP\'2K\^E\:x9\'c\[\%z\-\,64JQ5AeH_G\#KijUKghQw\^\\vea3a\?kka_G\$8\#\`\*kynsxzBLru\'\]k_\[7FrVx\}\^\=\$blx\>s\-N\%j\;D\*aZDnsw\:YKZ\%Q\.Kne9\#hP\?\+b3\(SOvL\,\^\;\&u5\@\?5C5Bhb\=m\-vEh_L15Jl\]U\)0RP6\{q\%L\^_z5E\'Dw6X\b" -Memory allocation (code space): 828 +Memory allocation - compiled block : 964 +Memory allocation - code portion : 828 ------------------------------------------------------------------ 0 823 Bra 4 8J$WE<.rX+ix[d1b!H#?vV0vrK:ZH1=2M>iV;?aPhFB<*vW@QW@sO9}cfZA-i'w%hKd6gt1UJP,15_#QY$M^Mss_U/]&LK9[5vQub^w[KDDqmj;2}YWFdYx.Ap]hjCPTP(n28k+3;o&WXqs/gOXdr$:r'do0;b4c(f_Gr="\4)[01T7ajQJvL$W~mL_sS/4h:x*[ZN=KLs&L5zX//>it,o:aU(;Z>pW&T7oP'2K^E:x9'c[%z-,64JQ5AeH_G#KijUKghQw^\vea3a?kka_G$8#`*kynsxzBLru']k_[7FrVx}^=$blx>s-N%j;D*aZDnsw:YKZ%Q.Kne9#hP?+b3(SOvL,^;&u5@?5C5Bhb=m-vEh_L15Jl]U)0RP6{q%L^_z5E'Dw6X @@ -159,7 +171,8 @@ Memory allocation (code space): 828 ------------------------------------------------------------------ "\$\<\.X\+ix\[d1b\!H\#\?vV0vrK\:ZH1\=2M\>iV\;\?aPhFB\<\*vW\@QW\@sO9\}cfZA\-i\'w\%hKd6gt1UJP\,15_\#QY\$M\^Mss_U\/\]\&LK9\[5vQub\^w\[KDD\qmj\;2\}YWFdYx\.Ap\]hjCPTP\(n28k\+3\;o\&WXqs\/gOXdr\$\:r\'do0\;b4c\(f_Gr\=\"\\4\)\[01T7ajQJvL\$W\~mL_sS\/4h\:x\*\[ZN\=KLs\&L5zX\/\/\>it\,o\:aU\(\;Z\>pW\&T7oP\'2K\^E\:x9\'c\[\%z\-\,64JQ5AeH_G\#KijUKghQw\^\\vea3a\?kka_G\$8\#\`\*kynsxzBLru\'\]k_\[7FrVx\}\^\=\$blx\>s\-N\%j\;D\*aZDnsw\:YKZ\%Q\.Kne9\#hP\?\+b3\(SOvL\,\^\;\&u5\@\?5C5Bhb\=m\-vEh_L15Jl\]U\)0RP6\{q\%L\^_z5E\'Dw6X\b" -Memory allocation (code space): 818 +Memory allocation - compiled block : 954 +Memory allocation - code portion : 818 ------------------------------------------------------------------ 0 813 Bra 4 $<.X+ix[d1b!H#?vV0vrK:ZH1=2M>iV;?aPhFB<*vW@QW@sO9}cfZA-i'w%hKd6gt1UJP,15_#QY$M^Mss_U/]&LK9[5vQub^w[KDDqmj;2}YWFdYx.Ap]hjCPTP(n28k+3;o&WXqs/gOXdr$:r'do0;b4c(f_Gr="\4)[01T7ajQJvL$W~mL_sS/4h:x*[ZN=KLs&L5zX//>it,o:aU(;Z>pW&T7oP'2K^E:x9'c[%z-,64JQ5AeH_G#KijUKghQw^\vea3a?kka_G$8#`*kynsxzBLru']k_[7FrVx}^=$blx>s-N%j;D*aZDnsw:YKZ%Q.Kne9#hP?+b3(SOvL,^;&u5@?5C5Bhb=m-vEh_L15Jl]U)0RP6{q%L^_z5E'Dw6X @@ -169,7 +182,8 @@ Memory allocation (code space): 818 ------------------------------------------------------------------ /(a(?1)b)/ -Memory allocation (code space): 27 +Memory allocation - compiled block : 163 +Memory allocation - code portion : 27 ------------------------------------------------------------------ 0 22 Bra 4 14 CBra 1 @@ -182,7 +196,8 @@ Memory allocation (code space): 27 ------------------------------------------------------------------ /(a(?1)+b)/ -Memory allocation (code space): 35 +Memory allocation - compiled block : 171 +Memory allocation - code portion : 35 ------------------------------------------------------------------ 0 30 Bra 4 22 CBra 1 @@ -197,7 +212,8 @@ Memory allocation (code space): 35 ------------------------------------------------------------------ /a(?Pb|c)d(?Pe)/ -Memory allocation (code space): 43 +Memory allocation - compiled block : 207 +Memory allocation - code portion : 43 ------------------------------------------------------------------ 0 38 Bra 4 a @@ -215,7 +231,8 @@ Memory allocation (code space): 43 ------------------------------------------------------------------ /(?:a(?Pc(?Pd)))(?Pa)/ -Memory allocation (code space): 55 +Memory allocation - compiled block : 203 +Memory allocation - code portion : 55 ------------------------------------------------------------------ 0 50 Bra 4 30 Bra @@ -235,7 +252,8 @@ Memory allocation (code space): 55 ------------------------------------------------------------------ /(?Pa)...(?P=a)bbb(?P>a)d/ -Memory allocation (code space): 39 +Memory allocation - compiled block : 179 +Memory allocation - code portion : 39 ------------------------------------------------------------------ 0 34 Bra 4 8 CBra 1 @@ -253,7 +271,8 @@ Memory allocation (code space): 39 ------------------------------------------------------------------ /abc(?C255)de(?C)f/ -Memory allocation (code space): 37 +Memory allocation - compiled block : 173 +Memory allocation - code portion : 37 ------------------------------------------------------------------ 0 32 Bra 4 abc @@ -266,7 +285,8 @@ Memory allocation (code space): 37 ------------------------------------------------------------------ /abcde/auto_callout -Memory allocation (code space): 67 +Memory allocation - compiled block : 203 +Memory allocation - code portion : 67 ------------------------------------------------------------------ 0 62 Bra 4 Callout 255 0 1 @@ -285,7 +305,8 @@ Memory allocation (code space): 67 ------------------------------------------------------------------ /\x{100}/utf -Memory allocation (code space): 12 +Memory allocation - compiled block : 148 +Memory allocation - code portion : 12 ------------------------------------------------------------------ 0 7 Bra 4 \x{100} @@ -294,7 +315,8 @@ Memory allocation (code space): 12 ------------------------------------------------------------------ /\x{1000}/utf -Memory allocation (code space): 13 +Memory allocation - compiled block : 149 +Memory allocation - code portion : 13 ------------------------------------------------------------------ 0 8 Bra 4 \x{1000} @@ -303,7 +325,8 @@ Memory allocation (code space): 13 ------------------------------------------------------------------ /\x{10000}/utf -Memory allocation (code space): 14 +Memory allocation - compiled block : 150 +Memory allocation - code portion : 14 ------------------------------------------------------------------ 0 9 Bra 4 \x{10000} @@ -312,7 +335,8 @@ Memory allocation (code space): 14 ------------------------------------------------------------------ /\x{100000}/utf -Memory allocation (code space): 14 +Memory allocation - compiled block : 150 +Memory allocation - code portion : 14 ------------------------------------------------------------------ 0 9 Bra 4 \x{100000} @@ -321,7 +345,8 @@ Memory allocation (code space): 14 ------------------------------------------------------------------ /\x{10ffff}/utf -Memory allocation (code space): 14 +Memory allocation - compiled block : 150 +Memory allocation - code portion : 14 ------------------------------------------------------------------ 0 9 Bra 4 \x{10ffff} @@ -333,7 +358,8 @@ Memory allocation (code space): 14 Failed: error 134 at offset 9: character code point value in \x{} or \o{} is too large /[\x{ff}]/utf -Memory allocation (code space): 12 +Memory allocation - compiled block : 148 +Memory allocation - code portion : 12 ------------------------------------------------------------------ 0 7 Bra 4 \x{ff} @@ -342,7 +368,8 @@ Memory allocation (code space): 12 ------------------------------------------------------------------ /[\x{100}]/utf -Memory allocation (code space): 12 +Memory allocation - compiled block : 148 +Memory allocation - code portion : 12 ------------------------------------------------------------------ 0 7 Bra 4 \x{100} @@ -351,7 +378,8 @@ Memory allocation (code space): 12 ------------------------------------------------------------------ /\x80/utf -Memory allocation (code space): 12 +Memory allocation - compiled block : 148 +Memory allocation - code portion : 12 ------------------------------------------------------------------ 0 7 Bra 4 \x{80} @@ -360,7 +388,8 @@ Memory allocation (code space): 12 ------------------------------------------------------------------ /\xff/utf -Memory allocation (code space): 12 +Memory allocation - compiled block : 148 +Memory allocation - code portion : 12 ------------------------------------------------------------------ 0 7 Bra 4 \x{ff} @@ -369,7 +398,8 @@ Memory allocation (code space): 12 ------------------------------------------------------------------ /\x{0041}\x{2262}\x{0391}\x{002e}/I,utf -Memory allocation (code space): 20 +Memory allocation - compiled block : 156 +Memory allocation - code portion : 20 ------------------------------------------------------------------ 0 15 Bra 4 A\x{2262}\x{391}. @@ -383,7 +413,8 @@ Last code unit = '.' Subject length lower bound = 4 /\x{D55c}\x{ad6d}\x{C5B4}/I,utf -Memory allocation (code space): 21 +Memory allocation - compiled block : 157 +Memory allocation - code portion : 21 ------------------------------------------------------------------ 0 16 Bra 4 \x{d55c}\x{ad6d}\x{c5b4} @@ -397,7 +428,8 @@ Last code unit = \xb4 Subject length lower bound = 3 /\x{65e5}\x{672c}\x{8a9e}/I,utf -Memory allocation (code space): 21 +Memory allocation - compiled block : 157 +Memory allocation - code portion : 21 ------------------------------------------------------------------ 0 16 Bra 4 \x{65e5}\x{672c}\x{8a9e} @@ -411,7 +443,8 @@ Last code unit = \x9e Subject length lower bound = 3 /[\x{100}]/utf -Memory allocation (code space): 12 +Memory allocation - compiled block : 148 +Memory allocation - code portion : 12 ------------------------------------------------------------------ 0 7 Bra 4 \x{100} @@ -420,7 +453,8 @@ Memory allocation (code space): 12 ------------------------------------------------------------------ /[Z\x{100}]/utf -Memory allocation (code space): 50 +Memory allocation - compiled block : 186 +Memory allocation - code portion : 50 ------------------------------------------------------------------ 0 45 Bra 4 [Z\x{100}] @@ -429,7 +463,8 @@ Memory allocation (code space): 50 ------------------------------------------------------------------ /^[\x{100}\E-\Q\E\x{150}]/utf -Memory allocation (code space): 21 +Memory allocation - compiled block : 157 +Memory allocation - code portion : 21 ------------------------------------------------------------------ 0 16 Bra 4 ^ @@ -439,7 +474,8 @@ Memory allocation (code space): 21 ------------------------------------------------------------------ /^[\QĀ\E-\QŐ\E]/utf -Memory allocation (code space): 21 +Memory allocation - compiled block : 157 +Memory allocation - code portion : 21 ------------------------------------------------------------------ 0 16 Bra 4 ^ @@ -452,7 +488,8 @@ Memory allocation (code space): 21 Failed: error 106 at offset 15: missing terminating ] for character class /[\p{L}]/ -Memory allocation (code space): 18 +Memory allocation - compiled block : 154 +Memory allocation - code portion : 18 ------------------------------------------------------------------ 0 13 Bra 4 [\p{L}] @@ -461,7 +498,8 @@ Memory allocation (code space): 18 ------------------------------------------------------------------ /[\p{^L}]/ -Memory allocation (code space): 18 +Memory allocation - compiled block : 154 +Memory allocation - code portion : 18 ------------------------------------------------------------------ 0 13 Bra 4 [\P{L}] @@ -470,7 +508,8 @@ Memory allocation (code space): 18 ------------------------------------------------------------------ /[\P{L}]/ -Memory allocation (code space): 18 +Memory allocation - compiled block : 154 +Memory allocation - code portion : 18 ------------------------------------------------------------------ 0 13 Bra 4 [\P{L}] @@ -479,7 +518,8 @@ Memory allocation (code space): 18 ------------------------------------------------------------------ /[\P{^L}]/ -Memory allocation (code space): 18 +Memory allocation - compiled block : 154 +Memory allocation - code portion : 18 ------------------------------------------------------------------ 0 13 Bra 4 [\p{L}] @@ -488,7 +528,8 @@ Memory allocation (code space): 18 ------------------------------------------------------------------ /[abc\p{L}\x{0660}]/utf -Memory allocation (code space): 53 +Memory allocation - compiled block : 189 +Memory allocation - code portion : 53 ------------------------------------------------------------------ 0 48 Bra 4 [a-c\p{L}\x{660}] @@ -497,7 +538,8 @@ Memory allocation (code space): 53 ------------------------------------------------------------------ /[\p{Nd}]/utf -Memory allocation (code space): 18 +Memory allocation - compiled block : 154 +Memory allocation - code portion : 18 ------------------------------------------------------------------ 0 13 Bra 4 [\p{Nd}] @@ -506,7 +548,8 @@ Memory allocation (code space): 18 ------------------------------------------------------------------ /[\p{Nd}+-]+/utf -Memory allocation (code space): 51 +Memory allocation - compiled block : 187 +Memory allocation - code portion : 51 ------------------------------------------------------------------ 0 46 Bra 4 [+\-\p{Nd}]++ @@ -515,7 +558,8 @@ Memory allocation (code space): 51 ------------------------------------------------------------------ /A\x{391}\x{10427}\x{ff3a}\x{1fb0}/i,utf -Memory allocation (code space): 27 +Memory allocation - compiled block : 163 +Memory allocation - code portion : 27 ------------------------------------------------------------------ 0 22 Bra 4 /i A\x{391}\x{10427}\x{ff3a}\x{1fb0} @@ -524,7 +568,8 @@ Memory allocation (code space): 27 ------------------------------------------------------------------ /A\x{391}\x{10427}\x{ff3a}\x{1fb0}/utf -Memory allocation (code space): 27 +Memory allocation - compiled block : 163 +Memory allocation - code portion : 27 ------------------------------------------------------------------ 0 22 Bra 4 A\x{391}\x{10427}\x{ff3a}\x{1fb0} @@ -533,7 +578,8 @@ Memory allocation (code space): 27 ------------------------------------------------------------------ /[\x{105}-\x{109}]/i,utf -Memory allocation (code space): 20 +Memory allocation - compiled block : 156 +Memory allocation - code portion : 20 ------------------------------------------------------------------ 0 15 Bra 4 [\x{104}-\x{109}] @@ -542,7 +588,8 @@ Memory allocation (code space): 20 ------------------------------------------------------------------ /( ( (?(1)0|) )* )/x -Memory allocation (code space): 47 +Memory allocation - compiled block : 183 +Memory allocation - code portion : 47 ------------------------------------------------------------------ 0 42 Bra 4 34 CBra 1 @@ -560,7 +607,8 @@ Memory allocation (code space): 47 ------------------------------------------------------------------ /( (?(1)0|)* )/x -Memory allocation (code space): 37 +Memory allocation - compiled block : 173 +Memory allocation - code portion : 37 ------------------------------------------------------------------ 0 32 Bra 4 24 CBra 1 @@ -576,7 +624,8 @@ Memory allocation (code space): 37 ------------------------------------------------------------------ /[a]/ -Memory allocation (code space): 11 +Memory allocation - compiled block : 147 +Memory allocation - code portion : 11 ------------------------------------------------------------------ 0 6 Bra 4 a @@ -585,7 +634,8 @@ Memory allocation (code space): 11 ------------------------------------------------------------------ /[a]/utf -Memory allocation (code space): 11 +Memory allocation - compiled block : 147 +Memory allocation - code portion : 11 ------------------------------------------------------------------ 0 6 Bra 4 a @@ -594,7 +644,8 @@ Memory allocation (code space): 11 ------------------------------------------------------------------ /[\xaa]/ -Memory allocation (code space): 11 +Memory allocation - compiled block : 147 +Memory allocation - code portion : 11 ------------------------------------------------------------------ 0 6 Bra 4 \x{aa} @@ -603,7 +654,8 @@ Memory allocation (code space): 11 ------------------------------------------------------------------ /[\xaa]/utf -Memory allocation (code space): 12 +Memory allocation - compiled block : 148 +Memory allocation - code portion : 12 ------------------------------------------------------------------ 0 7 Bra 4 \x{aa} @@ -612,7 +664,8 @@ Memory allocation (code space): 12 ------------------------------------------------------------------ /[^a]/ -Memory allocation (code space): 11 +Memory allocation - compiled block : 147 +Memory allocation - code portion : 11 ------------------------------------------------------------------ 0 6 Bra 4 [^a] @@ -621,7 +674,8 @@ Memory allocation (code space): 11 ------------------------------------------------------------------ /[^a]/utf -Memory allocation (code space): 11 +Memory allocation - compiled block : 147 +Memory allocation - code portion : 11 ------------------------------------------------------------------ 0 6 Bra 4 [^a] @@ -630,7 +684,8 @@ Memory allocation (code space): 11 ------------------------------------------------------------------ /[^\xaa]/ -Memory allocation (code space): 11 +Memory allocation - compiled block : 147 +Memory allocation - code portion : 11 ------------------------------------------------------------------ 0 6 Bra 4 [^\x{aa}] @@ -639,7 +694,8 @@ Memory allocation (code space): 11 ------------------------------------------------------------------ /[^\xaa]/utf -Memory allocation (code space): 12 +Memory allocation - compiled block : 148 +Memory allocation - code portion : 12 ------------------------------------------------------------------ 0 7 Bra 4 [^\x{aa}] diff --git a/testdata/testoutput8-8-4 b/testdata/testoutput8-8-4 index 8e19908..81cf0f7 100644 --- a/testdata/testoutput8-8-4 +++ b/testdata/testoutput8-8-4 @@ -10,7 +10,8 @@ #pattern fullbincode,memory /((?i)b)/ -Memory allocation (code space): 25 +Memory allocation - compiled block : 161 +Memory allocation - code portion : 25 ------------------------------------------------------------------ 0 19 Bra 5 9 CBra 1 @@ -21,7 +22,8 @@ Memory allocation (code space): 25 ------------------------------------------------------------------ /(?s)(.*X|^B)/ -Memory allocation (code space): 35 +Memory allocation - compiled block : 171 +Memory allocation - code portion : 35 ------------------------------------------------------------------ 0 29 Bra 5 11 CBra 1 @@ -36,7 +38,8 @@ Memory allocation (code space): 35 ------------------------------------------------------------------ /(?s:.*X|^B)/ -Memory allocation (code space): 33 +Memory allocation - compiled block : 169 +Memory allocation - code portion : 33 ------------------------------------------------------------------ 0 27 Bra 5 9 Bra @@ -51,7 +54,8 @@ Memory allocation (code space): 33 ------------------------------------------------------------------ /^[[:alnum:]]/ -Memory allocation (code space): 45 +Memory allocation - compiled block : 181 +Memory allocation - code portion : 45 ------------------------------------------------------------------ 0 39 Bra 5 ^ @@ -61,7 +65,8 @@ Memory allocation (code space): 45 ------------------------------------------------------------------ /#/Ix -Memory allocation (code space): 11 +Memory allocation - compiled block : 147 +Memory allocation - code portion : 11 ------------------------------------------------------------------ 0 5 Bra 5 5 Ket @@ -73,7 +78,8 @@ Options: extended Subject length lower bound = 0 /a#/Ix -Memory allocation (code space): 13 +Memory allocation - compiled block : 149 +Memory allocation - code portion : 13 ------------------------------------------------------------------ 0 7 Bra 5 a @@ -86,7 +92,8 @@ First code unit = 'a' Subject length lower bound = 1 /x?+/ -Memory allocation (code space): 13 +Memory allocation - compiled block : 149 +Memory allocation - code portion : 13 ------------------------------------------------------------------ 0 7 Bra 5 x?+ @@ -95,7 +102,8 @@ Memory allocation (code space): 13 ------------------------------------------------------------------ /x++/ -Memory allocation (code space): 13 +Memory allocation - compiled block : 149 +Memory allocation - code portion : 13 ------------------------------------------------------------------ 0 7 Bra 5 x++ @@ -104,7 +112,8 @@ Memory allocation (code space): 13 ------------------------------------------------------------------ /x{1,3}+/ -Memory allocation (code space): 17 +Memory allocation - compiled block : 153 +Memory allocation - code portion : 17 ------------------------------------------------------------------ 0 11 Bra 5 x @@ -114,7 +123,8 @@ Memory allocation (code space): 17 ------------------------------------------------------------------ /(x)*+/ -Memory allocation (code space): 26 +Memory allocation - compiled block : 162 +Memory allocation - code portion : 26 ------------------------------------------------------------------ 0 20 Bra 5 Braposzero @@ -126,7 +136,8 @@ Memory allocation (code space): 26 ------------------------------------------------------------------ /^((a+)(?U)([ab]+)(?-U)([bc]+)(\w*))/ -Memory allocation (code space): 144 +Memory allocation - compiled block : 280 +Memory allocation - code portion : 144 ------------------------------------------------------------------ 0 138 Bra 5 ^ @@ -149,7 +160,8 @@ Memory allocation (code space): 144 ------------------------------------------------------------------ "8J\$WE\<\.rX\+ix\[d1b\!H\#\?vV0vrK\:ZH1\=2M\>iV\;\?aPhFB\<\*vW\@QW\@sO9\}cfZA\-i\'w\%hKd6gt1UJP\,15_\#QY\$M\^Mss_U\/\]\&LK9\[5vQub\^w\[KDD\qmj\;2\}YWFdYx\.Ap\]hjCPTP\(n28k\+3\;o\&WXqs\/gOXdr\$\:r\'do0\;b4c\(f_Gr\=\"\\4\)\[01T7ajQJvL\$W\~mL_sS\/4h\:x\*\[ZN\=KLs\&L5zX\/\/\>it\,o\:aU\(\;Z\>pW\&T7oP\'2K\^E\:x9\'c\[\%z\-\,64JQ5AeH_G\#KijUKghQw\^\\vea3a\?kka_G\$8\#\`\*kynsxzBLru\'\]k_\[7FrVx\}\^\=\$blx\>s\-N\%j\;D\*aZDnsw\:YKZ\%Q\.Kne9\#hP\?\+b3\(SOvL\,\^\;\&u5\@\?5C5Bhb\=m\-vEh_L15Jl\]U\)0RP6\{q\%L\^_z5E\'Dw6X\b" -Memory allocation (code space): 830 +Memory allocation - compiled block : 966 +Memory allocation - code portion : 830 ------------------------------------------------------------------ 0 824 Bra 5 8J$WE<.rX+ix[d1b!H#?vV0vrK:ZH1=2M>iV;?aPhFB<*vW@QW@sO9}cfZA-i'w%hKd6gt1UJP,15_#QY$M^Mss_U/]&LK9[5vQub^w[KDDqmj;2}YWFdYx.Ap]hjCPTP(n28k+3;o&WXqs/gOXdr$:r'do0;b4c(f_Gr="\4)[01T7ajQJvL$W~mL_sS/4h:x*[ZN=KLs&L5zX//>it,o:aU(;Z>pW&T7oP'2K^E:x9'c[%z-,64JQ5AeH_G#KijUKghQw^\vea3a?kka_G$8#`*kynsxzBLru']k_[7FrVx}^=$blx>s-N%j;D*aZDnsw:YKZ%Q.Kne9#hP?+b3(SOvL,^;&u5@?5C5Bhb=m-vEh_L15Jl]U)0RP6{q%L^_z5E'Dw6X @@ -159,7 +171,8 @@ Memory allocation (code space): 830 ------------------------------------------------------------------ "\$\<\.X\+ix\[d1b\!H\#\?vV0vrK\:ZH1\=2M\>iV\;\?aPhFB\<\*vW\@QW\@sO9\}cfZA\-i\'w\%hKd6gt1UJP\,15_\#QY\$M\^Mss_U\/\]\&LK9\[5vQub\^w\[KDD\qmj\;2\}YWFdYx\.Ap\]hjCPTP\(n28k\+3\;o\&WXqs\/gOXdr\$\:r\'do0\;b4c\(f_Gr\=\"\\4\)\[01T7ajQJvL\$W\~mL_sS\/4h\:x\*\[ZN\=KLs\&L5zX\/\/\>it\,o\:aU\(\;Z\>pW\&T7oP\'2K\^E\:x9\'c\[\%z\-\,64JQ5AeH_G\#KijUKghQw\^\\vea3a\?kka_G\$8\#\`\*kynsxzBLru\'\]k_\[7FrVx\}\^\=\$blx\>s\-N\%j\;D\*aZDnsw\:YKZ\%Q\.Kne9\#hP\?\+b3\(SOvL\,\^\;\&u5\@\?5C5Bhb\=m\-vEh_L15Jl\]U\)0RP6\{q\%L\^_z5E\'Dw6X\b" -Memory allocation (code space): 820 +Memory allocation - compiled block : 956 +Memory allocation - code portion : 820 ------------------------------------------------------------------ 0 814 Bra 5 $<.X+ix[d1b!H#?vV0vrK:ZH1=2M>iV;?aPhFB<*vW@QW@sO9}cfZA-i'w%hKd6gt1UJP,15_#QY$M^Mss_U/]&LK9[5vQub^w[KDDqmj;2}YWFdYx.Ap]hjCPTP(n28k+3;o&WXqs/gOXdr$:r'do0;b4c(f_Gr="\4)[01T7ajQJvL$W~mL_sS/4h:x*[ZN=KLs&L5zX//>it,o:aU(;Z>pW&T7oP'2K^E:x9'c[%z-,64JQ5AeH_G#KijUKghQw^\vea3a?kka_G$8#`*kynsxzBLru']k_[7FrVx}^=$blx>s-N%j;D*aZDnsw:YKZ%Q.Kne9#hP?+b3(SOvL,^;&u5@?5C5Bhb=m-vEh_L15Jl]U)0RP6{q%L^_z5E'Dw6X @@ -169,7 +182,8 @@ Memory allocation (code space): 820 ------------------------------------------------------------------ /(a(?1)b)/ -Memory allocation (code space): 32 +Memory allocation - compiled block : 168 +Memory allocation - code portion : 32 ------------------------------------------------------------------ 0 26 Bra 5 16 CBra 1 @@ -182,7 +196,8 @@ Memory allocation (code space): 32 ------------------------------------------------------------------ /(a(?1)+b)/ -Memory allocation (code space): 42 +Memory allocation - compiled block : 178 +Memory allocation - code portion : 42 ------------------------------------------------------------------ 0 36 Bra 5 26 CBra 1 @@ -197,7 +212,8 @@ Memory allocation (code space): 42 ------------------------------------------------------------------ /a(?Pb|c)d(?Pe)/ -Memory allocation (code space): 50 +Memory allocation - compiled block : 214 +Memory allocation - code portion : 50 ------------------------------------------------------------------ 0 44 Bra 5 a @@ -215,7 +231,8 @@ Memory allocation (code space): 50 ------------------------------------------------------------------ /(?:a(?Pc(?Pd)))(?Pa)/ -Memory allocation (code space): 65 +Memory allocation - compiled block : 213 +Memory allocation - code portion : 65 ------------------------------------------------------------------ 0 59 Bra 5 35 Bra @@ -235,7 +252,8 @@ Memory allocation (code space): 65 ------------------------------------------------------------------ /(?Pa)...(?P=a)bbb(?P>a)d/ -Memory allocation (code space): 44 +Memory allocation - compiled block : 184 +Memory allocation - code portion : 44 ------------------------------------------------------------------ 0 38 Bra 5 9 CBra 1 @@ -253,7 +271,8 @@ Memory allocation (code space): 44 ------------------------------------------------------------------ /abc(?C255)de(?C)f/ -Memory allocation (code space): 43 +Memory allocation - compiled block : 179 +Memory allocation - code portion : 43 ------------------------------------------------------------------ 0 37 Bra 5 abc @@ -266,7 +285,8 @@ Memory allocation (code space): 43 ------------------------------------------------------------------ /abcde/auto_callout -Memory allocation (code space): 81 +Memory allocation - compiled block : 217 +Memory allocation - code portion : 81 ------------------------------------------------------------------ 0 75 Bra 5 Callout 255 0 1 @@ -285,7 +305,8 @@ Memory allocation (code space): 81 ------------------------------------------------------------------ /\x{100}/utf -Memory allocation (code space): 14 +Memory allocation - compiled block : 150 +Memory allocation - code portion : 14 ------------------------------------------------------------------ 0 8 Bra 5 \x{100} @@ -294,7 +315,8 @@ Memory allocation (code space): 14 ------------------------------------------------------------------ /\x{1000}/utf -Memory allocation (code space): 15 +Memory allocation - compiled block : 151 +Memory allocation - code portion : 15 ------------------------------------------------------------------ 0 9 Bra 5 \x{1000} @@ -303,7 +325,8 @@ Memory allocation (code space): 15 ------------------------------------------------------------------ /\x{10000}/utf -Memory allocation (code space): 16 +Memory allocation - compiled block : 152 +Memory allocation - code portion : 16 ------------------------------------------------------------------ 0 10 Bra 5 \x{10000} @@ -312,7 +335,8 @@ Memory allocation (code space): 16 ------------------------------------------------------------------ /\x{100000}/utf -Memory allocation (code space): 16 +Memory allocation - compiled block : 152 +Memory allocation - code portion : 16 ------------------------------------------------------------------ 0 10 Bra 5 \x{100000} @@ -321,7 +345,8 @@ Memory allocation (code space): 16 ------------------------------------------------------------------ /\x{10ffff}/utf -Memory allocation (code space): 16 +Memory allocation - compiled block : 152 +Memory allocation - code portion : 16 ------------------------------------------------------------------ 0 10 Bra 5 \x{10ffff} @@ -333,7 +358,8 @@ Memory allocation (code space): 16 Failed: error 134 at offset 9: character code point value in \x{} or \o{} is too large /[\x{ff}]/utf -Memory allocation (code space): 14 +Memory allocation - compiled block : 150 +Memory allocation - code portion : 14 ------------------------------------------------------------------ 0 8 Bra 5 \x{ff} @@ -342,7 +368,8 @@ Memory allocation (code space): 14 ------------------------------------------------------------------ /[\x{100}]/utf -Memory allocation (code space): 14 +Memory allocation - compiled block : 150 +Memory allocation - code portion : 14 ------------------------------------------------------------------ 0 8 Bra 5 \x{100} @@ -351,7 +378,8 @@ Memory allocation (code space): 14 ------------------------------------------------------------------ /\x80/utf -Memory allocation (code space): 14 +Memory allocation - compiled block : 150 +Memory allocation - code portion : 14 ------------------------------------------------------------------ 0 8 Bra 5 \x{80} @@ -360,7 +388,8 @@ Memory allocation (code space): 14 ------------------------------------------------------------------ /\xff/utf -Memory allocation (code space): 14 +Memory allocation - compiled block : 150 +Memory allocation - code portion : 14 ------------------------------------------------------------------ 0 8 Bra 5 \x{ff} @@ -369,7 +398,8 @@ Memory allocation (code space): 14 ------------------------------------------------------------------ /\x{0041}\x{2262}\x{0391}\x{002e}/I,utf -Memory allocation (code space): 22 +Memory allocation - compiled block : 158 +Memory allocation - code portion : 22 ------------------------------------------------------------------ 0 16 Bra 5 A\x{2262}\x{391}. @@ -383,7 +413,8 @@ Last code unit = '.' Subject length lower bound = 4 /\x{D55c}\x{ad6d}\x{C5B4}/I,utf -Memory allocation (code space): 23 +Memory allocation - compiled block : 159 +Memory allocation - code portion : 23 ------------------------------------------------------------------ 0 17 Bra 5 \x{d55c}\x{ad6d}\x{c5b4} @@ -397,7 +428,8 @@ Last code unit = \xb4 Subject length lower bound = 3 /\x{65e5}\x{672c}\x{8a9e}/I,utf -Memory allocation (code space): 23 +Memory allocation - compiled block : 159 +Memory allocation - code portion : 23 ------------------------------------------------------------------ 0 17 Bra 5 \x{65e5}\x{672c}\x{8a9e} @@ -411,7 +443,8 @@ Last code unit = \x9e Subject length lower bound = 3 /[\x{100}]/utf -Memory allocation (code space): 14 +Memory allocation - compiled block : 150 +Memory allocation - code portion : 14 ------------------------------------------------------------------ 0 8 Bra 5 \x{100} @@ -420,7 +453,8 @@ Memory allocation (code space): 14 ------------------------------------------------------------------ /[Z\x{100}]/utf -Memory allocation (code space): 53 +Memory allocation - compiled block : 189 +Memory allocation - code portion : 53 ------------------------------------------------------------------ 0 47 Bra 5 [Z\x{100}] @@ -429,7 +463,8 @@ Memory allocation (code space): 53 ------------------------------------------------------------------ /^[\x{100}\E-\Q\E\x{150}]/utf -Memory allocation (code space): 24 +Memory allocation - compiled block : 160 +Memory allocation - code portion : 24 ------------------------------------------------------------------ 0 18 Bra 5 ^ @@ -439,7 +474,8 @@ Memory allocation (code space): 24 ------------------------------------------------------------------ /^[\QĀ\E-\QŐ\E]/utf -Memory allocation (code space): 24 +Memory allocation - compiled block : 160 +Memory allocation - code portion : 24 ------------------------------------------------------------------ 0 18 Bra 5 ^ @@ -452,7 +488,8 @@ Memory allocation (code space): 24 Failed: error 106 at offset 15: missing terminating ] for character class /[\p{L}]/ -Memory allocation (code space): 21 +Memory allocation - compiled block : 157 +Memory allocation - code portion : 21 ------------------------------------------------------------------ 0 15 Bra 5 [\p{L}] @@ -461,7 +498,8 @@ Memory allocation (code space): 21 ------------------------------------------------------------------ /[\p{^L}]/ -Memory allocation (code space): 21 +Memory allocation - compiled block : 157 +Memory allocation - code portion : 21 ------------------------------------------------------------------ 0 15 Bra 5 [\P{L}] @@ -470,7 +508,8 @@ Memory allocation (code space): 21 ------------------------------------------------------------------ /[\P{L}]/ -Memory allocation (code space): 21 +Memory allocation - compiled block : 157 +Memory allocation - code portion : 21 ------------------------------------------------------------------ 0 15 Bra 5 [\P{L}] @@ -479,7 +518,8 @@ Memory allocation (code space): 21 ------------------------------------------------------------------ /[\P{^L}]/ -Memory allocation (code space): 21 +Memory allocation - compiled block : 157 +Memory allocation - code portion : 21 ------------------------------------------------------------------ 0 15 Bra 5 [\p{L}] @@ -488,7 +528,8 @@ Memory allocation (code space): 21 ------------------------------------------------------------------ /[abc\p{L}\x{0660}]/utf -Memory allocation (code space): 56 +Memory allocation - compiled block : 192 +Memory allocation - code portion : 56 ------------------------------------------------------------------ 0 50 Bra 5 [a-c\p{L}\x{660}] @@ -497,7 +538,8 @@ Memory allocation (code space): 56 ------------------------------------------------------------------ /[\p{Nd}]/utf -Memory allocation (code space): 21 +Memory allocation - compiled block : 157 +Memory allocation - code portion : 21 ------------------------------------------------------------------ 0 15 Bra 5 [\p{Nd}] @@ -506,7 +548,8 @@ Memory allocation (code space): 21 ------------------------------------------------------------------ /[\p{Nd}+-]+/utf -Memory allocation (code space): 54 +Memory allocation - compiled block : 190 +Memory allocation - code portion : 54 ------------------------------------------------------------------ 0 48 Bra 5 [+\-\p{Nd}]++ @@ -515,7 +558,8 @@ Memory allocation (code space): 54 ------------------------------------------------------------------ /A\x{391}\x{10427}\x{ff3a}\x{1fb0}/i,utf -Memory allocation (code space): 29 +Memory allocation - compiled block : 165 +Memory allocation - code portion : 29 ------------------------------------------------------------------ 0 23 Bra 5 /i A\x{391}\x{10427}\x{ff3a}\x{1fb0} @@ -524,7 +568,8 @@ Memory allocation (code space): 29 ------------------------------------------------------------------ /A\x{391}\x{10427}\x{ff3a}\x{1fb0}/utf -Memory allocation (code space): 29 +Memory allocation - compiled block : 165 +Memory allocation - code portion : 29 ------------------------------------------------------------------ 0 23 Bra 5 A\x{391}\x{10427}\x{ff3a}\x{1fb0} @@ -533,7 +578,8 @@ Memory allocation (code space): 29 ------------------------------------------------------------------ /[\x{105}-\x{109}]/i,utf -Memory allocation (code space): 23 +Memory allocation - compiled block : 159 +Memory allocation - code portion : 23 ------------------------------------------------------------------ 0 17 Bra 5 [\x{104}-\x{109}] @@ -542,7 +588,8 @@ Memory allocation (code space): 23 ------------------------------------------------------------------ /( ( (?(1)0|) )* )/x -Memory allocation (code space): 56 +Memory allocation - compiled block : 192 +Memory allocation - code portion : 56 ------------------------------------------------------------------ 0 50 Bra 5 40 CBra 1 @@ -560,7 +607,8 @@ Memory allocation (code space): 56 ------------------------------------------------------------------ /( (?(1)0|)* )/x -Memory allocation (code space): 44 +Memory allocation - compiled block : 180 +Memory allocation - code portion : 44 ------------------------------------------------------------------ 0 38 Bra 5 28 CBra 1 @@ -576,7 +624,8 @@ Memory allocation (code space): 44 ------------------------------------------------------------------ /[a]/ -Memory allocation (code space): 13 +Memory allocation - compiled block : 149 +Memory allocation - code portion : 13 ------------------------------------------------------------------ 0 7 Bra 5 a @@ -585,7 +634,8 @@ Memory allocation (code space): 13 ------------------------------------------------------------------ /[a]/utf -Memory allocation (code space): 13 +Memory allocation - compiled block : 149 +Memory allocation - code portion : 13 ------------------------------------------------------------------ 0 7 Bra 5 a @@ -594,7 +644,8 @@ Memory allocation (code space): 13 ------------------------------------------------------------------ /[\xaa]/ -Memory allocation (code space): 13 +Memory allocation - compiled block : 149 +Memory allocation - code portion : 13 ------------------------------------------------------------------ 0 7 Bra 5 \x{aa} @@ -603,7 +654,8 @@ Memory allocation (code space): 13 ------------------------------------------------------------------ /[\xaa]/utf -Memory allocation (code space): 14 +Memory allocation - compiled block : 150 +Memory allocation - code portion : 14 ------------------------------------------------------------------ 0 8 Bra 5 \x{aa} @@ -612,7 +664,8 @@ Memory allocation (code space): 14 ------------------------------------------------------------------ /[^a]/ -Memory allocation (code space): 13 +Memory allocation - compiled block : 149 +Memory allocation - code portion : 13 ------------------------------------------------------------------ 0 7 Bra 5 [^a] @@ -621,7 +674,8 @@ Memory allocation (code space): 13 ------------------------------------------------------------------ /[^a]/utf -Memory allocation (code space): 13 +Memory allocation - compiled block : 149 +Memory allocation - code portion : 13 ------------------------------------------------------------------ 0 7 Bra 5 [^a] @@ -630,7 +684,8 @@ Memory allocation (code space): 13 ------------------------------------------------------------------ /[^\xaa]/ -Memory allocation (code space): 13 +Memory allocation - compiled block : 149 +Memory allocation - code portion : 13 ------------------------------------------------------------------ 0 7 Bra 5 [^\x{aa}] @@ -639,7 +694,8 @@ Memory allocation (code space): 13 ------------------------------------------------------------------ /[^\xaa]/utf -Memory allocation (code space): 14 +Memory allocation - compiled block : 150 +Memory allocation - code portion : 14 ------------------------------------------------------------------ 0 8 Bra 5 [^\x{aa}] diff --git a/vms/configure.com b/vms/configure.com new file mode 100644 index 0000000..b50365d --- /dev/null +++ b/vms/configure.com @@ -0,0 +1,1144 @@ +$! Configure procedure +$! (c) Alexey Chupahin 11-APR-2024 +$! alexey@vaxman.de, alexey_chupahin@mail.ru +$! +$! +$ SET NOON +$SET NOVER +$WRITE SYS$OUTPUT " " +$WRITE SYS$OUTPUT "Configuring PCRE2 library for OpenVMS " +$WRITE SYS$OUTPUT "(c) Alexey Chupahin CHAPG" +$WRITE SYS$OUTPUT " " +$! Checking architecture +$DECC = F$SEARCH("SYS$SYSTEM:DECC$COMPILER.EXE") .NES. "" +$ IF F$GETSYI("ARCH_TYPE").EQ.1 THEN CPU = "VAX" +$ IF F$GETSYI("ARCH_TYPE").EQ.2 THEN CPU = "Alpha" +$ IF F$GETSYI("ARCH_TYPE").EQ.3 THEN CPU = "I64" +$ IF F$GETSYI("ARCH_TYPE").EQ.4 THEN CPU = "x86" +$WRITE SYS$OUTPUT "Checking architecture ... ", CPU +$IF ( (CPU.EQS."Alpha").OR.(CPU.EQS."I64").OR(CPU.EQS."x86") ) +$ THEN +$ SHARED=64 +$ ELSE +$ SHARED=32 +$ENDIF +$! +$IF (DECC) THEN $WRITE SYS$OUTPUT "Compiler ... DEC C" +$IF (.NOT. DECC) THEN $WRITE SYS$OUTPUT "BAD compiler" GOTO EXIT +$MMS = F$SEARCH("SYS$SYSTEM:MMS.EXE") .NES. "" +$MMK = F$TYPE(MMK) +$IF (MMS .OR. MMK.NES."") THEN GOTO TEST_LIBRARIES +$! I cant find any make tool +$ WRITE SYS$OUTPUT "Install MMS or MMK" +$GOTO EXIT +$!PERL = F$TYPE(MMK) +$!IF (PERL.NES."") THEN GOTO TEST_LIBRARIES +$!WRITE SYS$OUTPUT "Install PERL" +$!GOTO EXIT +$! +$! +$! Is it package root directory? If no, go to [-] +$ IF (F$SEARCH("[]VMS.DIR").EQS."") .AND. (F$SEARCH("[]vms.dir").EQS."") +$ THEN +$ SET DEF [-] +$ ENDIF +$! +$TEST_LIBRARIES: +$! Setting as MAKE utility one of MMS or MMK. I prefer MMS. +$IF (MMK.NES."") THEN MAKE="MMK" +$IF (MMS) THEN MAKE="MMS" +$WRITE SYS$OUTPUT "Checking build utility ... ''MAKE'" +$!WRITE SYS$OUTPUT "Checking PERL ... found" +$WRITE SYS$OUTPUT " " +$! +$! +$! Check files and ODS-2. unzip makes files FILE.H.GENERIC like FILE_H.GENERIC. Should rename to FILE.H_GENERIC +$IF F$SEARCH("[.SRC]PCRE2_H.GENERIC") .NES. "" +$ THEN +$ REN [.SRC]PCRE2_H.GENERIC [.SRC]PCRE2.H_GENERIC +$ ELSE +$ IF F$SEARCH("[.SRC]PCRE2.H_GENERIC") .EQS. "" +$ THEN +$ WRITE SYS$OUTPUT "Not ODS-2 volume, or PCRE2_H.GENERIC not found" +$ EXIT +$ ENDIF +$ENDIF +$IF F$SEARCH("[.SRC]PCRE2_CHARTABLES_C.DIST") .NES. "" +$ THEN +$ REN [.SRC]PCRE2_CHARTABLES_C.DIST [.SRC]PCRE2_CHARTABLES.C_DIST +$ ELSE +$ IF F$SEARCH("[.SRC]PCRE2_CHARTABLES.C_DIST") .EQS. "" +$ THEN +$ WRITE SYS$OUTPUT "Not ODS-2 volume, or PCRE2_CHARTABLES_C.DIST not found" +$ EXIT +$ ENDIF +$ENDIF +$WRITE SYS$OUTPUT "Source Files OK" +$! +$! +$I18 = F$SEARCH("SYS$I18N_ICONV:ISO8859-1_UTF-8.ICONV") .NES. "" +$IF (I18) +$ THEN +$ WRITE SYS$OUTPUT "Found I18 extension ICONV codes" +$!"Checking for iconv " +$ DEFINE SYS$ERROR _NLA0: +$ DEFINE SYS$OUTPUT _NLA0: +$ CC/OBJECT=TEST.OBJ SYS$INPUT +#include +#include +#include +#include + +int main () +{ + /* */ + /* Declare variables to be used */ + /* */ + char fromcodeset[30]; + char tocodeset[30]; + int iconv_opened; + iconv_t iconv_struct; /* Iconv descriptor */ + + /* */ + /* Initialize variables */ + /* */ + sprintf(fromcodeset,"UTF-8"); + sprintf(tocodeset,"ISO8859-1"); + iconv_opened = FALSE; + + /* */ + /* Attempt to create a conversion descriptor for the codesets */ + /* specified. If the return value from iconv_open is -1 then */ + /* an error has occurred. Check value of errno. */ + /* */ + if ((iconv_struct = iconv_open (tocodeset, fromcodeset)) == (iconv_t)-1) + { + /* */ + /* Check the value of errno */ + /* */ + switch (errno) + { + case EMFILE: + case ENFILE: + printf("Too many iconv conversion files open\n"); + exit(2); + break; + + case ENOMEM: + printf("Not enough memory\n"); + printf("Checking iconv ..... no\n"); + exit(2); + break; + + case EINVAL: + printf("Unsupported conversion\n"); + exit(2); + break; + + default: + printf("Unexpected error from iconv_open\n"); + exit(2); + break; + } + } + else + /* */ + /* Successfully allocated a conversion descriptor */ + /* */ + iconv_opened = TRUE; + + /* */ + /* Was a conversion descriptor allocated */ + /* */ + if (iconv_opened) + { + /* */ + /* Attempt to deallocate the conversion descriptor. If */ + /* iconv_close returns -1 then an error has occurred. */ + /* */ + if (iconv_close (iconv_struct) == -1) + { + /* */ + /* An error occurred. Check the value of errno */ + /* */ + switch (errno) + { + case EBADF: + printf("Conversion descriptor is invalid\n"); + exit(2); + break; + default: + break; + } + } + else + printf("Checking iconv ..... yes\n"); + } + return(1); +} +$! +$TMP = $STATUS +$DEASS SYS$ERROR +$DEAS SYS$OUTPUT +$!WRITE SYS$OUTPUT TMP +$IF (TMP .NE. %X10B90001) +$ THEN +$ HAVE_ICONV=0 +$ GOTO NEXT0 +$ENDIF +$DEFINE SYS$ERROR _NLA0: +$DEFINE SYS$OUTPUT _NLA0: +$LINK/EXE=TEST TEST +$TMP = $STATUS +$DEAS SYS$ERROR +$DEAS SYS$OUTPUT +$!WRITE SYS$OUTPUT TMP +$IF (TMP .NE. %X10000001) +$ THEN +$ HAVE_ICONV=0 +$ GOTO NEXT0 +$ ELSE +$ HAVE_ICONV=1 +$ENDIF +$NEXT0: +$IF (HAVE_ICONV.EQ.1) +$ THEN +$ WRITE SYS$OUTPUT "Checking for iconv ... Yes" +$ ELSE +$ WRITE SYS$OUTPUT "Checking for iconv ... No" +$ENDIF +$! +$! +$! Checking for BZIP2 library +$! +$ DEFINE SYS$ERROR _NLA0: +$ DEFINE SYS$OUTPUT _NLA0: +$ CC/OBJECT=TEST.OBJ/INCLUDE=(BZ2LIB) SYS$INPUT + #include + #include + #include + int main() + { + printf("checking version bzip2 library: %s\n",BZ2_bzlibVersion()); + } +$TMP = $STATUS +$DEASS SYS$ERROR +$DEAS SYS$OUTPUT +$!WRITE SYS$OUTPUT TMP +$IF (TMP .NE. %X10B90001) +$ THEN +$ HAVE_BZIP2=0 +$ GOTO ERR0 +$ENDIF +$DEFINE SYS$ERROR _NLA0: +$DEFINE SYS$OUTPUT _NLA0: +$!Testing for CHAPG BZIP2 +$! +$LINK/EXE=TEST TEST,BZ2LIB:BZIP2/OPT +$TMP = $STATUS +$DEAS SYS$ERROR +$DEAS SYS$OUTPUT +$IF (TMP .NE. %X10000001) +$ THEN +$ HAVE_BZIP2=0 +$ GOTO ERR0 +$ ELSE +$ HAVE_BZIP2=1 +$ENDIF +$ERR0: +$IF (HAVE_BZIP2.EQ.1) +$ THEN +$ WRITE SYS$OUTPUT "Checking for CHAPG bzip2 library ... Yes" +$ RUN TEST +$ GOTO NEXT4 +$ ELSE +$ WRITE SYS$OUTPUT "Checking for correct bzip2 library ... No" +$ WRITE SYS$OUTPUT "To get bzip2 archives support, please download" +$ WRITE SYS$OUTPUT "and install good library ported by Alexey Chupahin" +$ WRITE SYS$OUTPUT "from openvms clamav site http://vaxvms.org/clamav/" +$ WRITE SYS$OUTPUT "" +$ GOTO EXIT +$ENDIF +$NEXT4: +$! +$! +$!"Checking for CHAPG zlib library " +$DEFINE SYS$ERROR _NLA0: +$DEFINE SYS$OUTPUT _NLA0: +$ CC/OBJECT=TEST.OBJ/INCLUDE=(ZLIB) SYS$INPUT + #include + #include + #include + #include + int main() + { + printf("checking version zlib: %s\n",zlibVersion()); + // printf("checking zlib is correct "); + } + +$TMP = $STATUS +$DEASS SYS$ERROR +$DEAS SYS$OUTPUT +$IF (TMP .NE. %X10B90001) +$ THEN +$ HAVE_ZLIB=0 +$ GOTO ERR4 +$ENDIF +$DEFINE SYS$ERROR _NLA0: +$DEFINE SYS$OUTPUT _NLA0: +$! +$LINK/EXE=TEST TEST,ZLIB:ZLIB.OPT/OPT +$TMP = $STATUS +$DEAS SYS$ERROR +$DEAS SYS$OUTPUT +$IF (TMP .NE. %X10000001) +$ THEN +$ HAVE_ZLIB=0 +$ GOTO ERR4 +$ ELSE +$ HAVE_ZLIB=1 +$ENDIF +$ERR4: +$IF (HAVE_ZLIB.EQ.1) +$ THEN +$ WRITE SYS$OUTPUT "Checking for CHAPG zlib library ... Yes" +$ RUN TEST +$ GOTO NEXT5 +$ ELSE +$ WRITE SYS$OUTPUT "Checking for CHAPG zlib library ... No" +$ WRITE SYS$OUTPUT "Please install ZLIB from" +$ WRITE SYS$OUTPUT "http://vaxvms.org/libsdl/required.html" +$ GOTO EXIT +$ENDIF +$! +$NEXT5: + +$! +$!WRITING BUILD FILES +$OPEN/WRITE OUT BUILD.COM +$ WRITE OUT "$","SET DEF [.SRC]" +$ WRITE OUT "$",MAKE +$ WRITE OUT "$ CURRENT = F$ENVIRONMENT (""DEFAULT"") " +$ WRITE OUT "$","SET DEF [-]" +$ WRITE OUT "$CLAM=CURRENT" +$ WRITE OUT "$OPEN/WRITE OUTT PCRE2$STARTUP.COM" +$ WRITE OUT "$WRITE OUTT ""DEFINE PCRE2 ","'","'","CLAM'"" " +$ WRITE OUT "$WRITE OUTT ""DEFINE PCRE2$SHR ","'","'","CLAM'PCRE2$SHR.EXE"" " +$ WRITE OUT "$WRITE OUTT ""PCRE2GREP:==$", "'","'","CLAM'PCRE2GREP.EXE""" +$ WRITE OUT "$CLOSE OUTT" +$ WRITE OUT "$WRITE SYS$OUTPUT "" "" " +$ WRITE OUT "$WRITE SYS$OUTPUT ""***************************************************************************** "" " +$ WRITE OUT "$WRITE SYS$OUTPUT ""Compilation is completed."" " +$ WRITE OUT "$WRITE SYS$OUTPUT ""PCRE2$STARTUP.COM is created. "" " +$ WRITE OUT "$WRITE SYS$OUTPUT ""This file setups all logicals needed."" " +$ WRITE OUT "$WRITE SYS$OUTPUT ""It should be executed before using PCRE2 Library. "" " +$ WRITE OUT "$WRITE SYS$OUTPUT ""Use PCRE2:PCRE2.OPT to link you program"" " +$ WRITE OUT "$WRITE SYS$OUTPUT ""PCRE2GREP grep utility is installed here for your needs "" " +$ WRITE OUT "$WRITE SYS$OUTPUT ""***************************************************************************** "" " +$CLOSE OUT +$! BUILD.COM finished +$ WRITE SYS$OUTPUT "BUILD.COM has been created" +$! +$!Creating OPT.OPT file containig external libraries for linker +$OPEN/WRITE OUT [.SRC]PCRE2.OPT +$IF (SHARED.GT.0) THEN WRITE OUT "PCRE2:PCRE2$SHR/SHARE" +$IF (SHARED.EQ.0) +$ THEN +$ WRITE OUT "PCRE2:PCRE2/LIB" +$ENDIF +$CLOSE OUT +$WRITE SYS$OUTPUT "PCRE2.OPT has been created" +$IF (SHARED.EQ.64) +$ THEN +$ COPY SYS$INPUT [.SRC]PCRE2$DEF.OPT +! +case_sensitive=NO +symbol_vector = (PCRE2_CONFIG_8 = PROCEDURE) +symbol_vector = (PCRE2_MAKETABLES_8 = PROCEDURE) +symbol_vector = (PCRE2_MAKETABLES_FREE_8 = PROCEDURE) +symbol_vector = (PCRE2_CODE_COPY_8 = PROCEDURE) +symbol_vector = (PCRE2_CODE_FREE_8 = PROCEDURE) +symbol_vector = (_PCRE2_CHECK_ESCAPE_8 = PROCEDURE) +symbol_vector = (PCRE2_COMPILE_8 = PROCEDURE) +symbol_vector = (PCRE2_CODE_COPY_WITH_TABLES_8 = PROCEDURE) +symbol_vector = (PCRE2_GET_ERROR_MESSAGE_8 = PROCEDURE) +symbol_vector = (PCRE2_MATCH_DATA_CREATE_8 = PROCEDURE) +symbol_vector = (VMS_PCRE2_GET_M_D_HPFRAM_S_8 = PROCEDURE) +symbol_vector = (PCRE2_GET_MATCH_DATA_SIZE_8 = PROCEDURE) +symbol_vector = (PCRE2_GET_STARTCHAR_8 = PROCEDURE) +symbol_vector = (PCRE2_GET_OVECTOR_COUNT_8 = PROCEDURE) +symbol_vector = (PCRE2_GET_OVECTOR_POINTER_8 = PROCEDURE) +symbol_vector = (PCRE2_GET_MARK_8 = PROCEDURE) +symbol_vector = (PCRE2_MATCH_DATA_FREE_8 = PROCEDURE) +symbol_vector = (VMS_PCRE2_M_D_CRT_FR_PATT_8 = PROCEDURE) +symbol_vector = (PCRE2_MATCH_8 = PROCEDURE) +symbol_vector = (PCRE2_PATTERN_INFO_8 = PROCEDURE) +symbol_vector = (PCRE2_CALLOUT_ENUMERATE_8 = PROCEDURE) +symbol_vector = (PCRE2_SET_GLOB_ESCAPE_8 = PROCEDURE) +symbol_vector = (PCRE2_SET_GLOB_SEPARATOR_8 = PROCEDURE) +symbol_vector = (VMS_PCRE2_SET_RCRS_MEM_MNG_8 = PROCEDURE) +symbol_vector = (PCRE2_SET_DEPTH_LIMIT_8 = PROCEDURE) +symbol_vector = (PCRE2_SET_RECURSION_LIMIT_8 = PROCEDURE) +symbol_vector = (PCRE2_SET_OFFSET_LIMIT_8 = PROCEDURE) +symbol_vector = (PCRE2_SET_MATCH_LIMIT_8 = PROCEDURE) +symbol_vector = (PCRE2_SET_HEAP_LIMIT_8 = PROCEDURE) +symbol_vector = (PCRE2_SET_SUBSTITUTE_CALLOUT_8 = PROCEDURE) +symbol_vector = (PCRE2_SET_CALLOUT_8 = PROCEDURE) +symbol_vector = (VMS_PCRE2_SET_CMPL_RCRS_GRD_8 = PROCEDURE) +symbol_vector = (VMS_PCRE2_SET_CMPL_EXT_OPT_8 = PROCEDURE) +symbol_vector = (PCRE2_SET_PARENS_NEST_LIMIT_8 = PROCEDURE) +symbol_vector = (PCRE2_SET_MAX_VARLOOKBEHIND_8 = PROCEDURE) +symbol_vector = (PCRE2_SET_NEWLINE_8 = PROCEDURE) +symbol_vector = (PCRE2_SET_MAX_PATTERN_LENGTH_8 = PROCEDURE) +symbol_vector = (PCRE2_SET_BSR_8 = PROCEDURE) +symbol_vector = (PCRE2_SET_CHARACTER_TABLES_8 = PROCEDURE) +symbol_vector = (PCRE2_CONVERT_CONTEXT_FREE_8 = PROCEDURE) +symbol_vector = (PCRE2_MATCH_CONTEXT_FREE_8 = PROCEDURE) +symbol_vector = (PCRE2_COMPILE_CONTEXT_FREE_8 = PROCEDURE) +symbol_vector = (PCRE2_GENERAL_CONTEXT_FREE_8 = PROCEDURE) +symbol_vector = (PCRE2_CONVERT_CONTEXT_COPY_8 = PROCEDURE) +symbol_vector = (PCRE2_MATCH_CONTEXT_COPY_8 = PROCEDURE) +symbol_vector = (PCRE2_COMPILE_CONTEXT_COPY_8 = PROCEDURE) +symbol_vector = (PCRE2_GENERAL_CONTEXT_COPY_8 = PROCEDURE) +symbol_vector = (_PCRE2_MEMCTL_MALLOC_8 = PROCEDURE) +symbol_vector = (PCRE2_CONVERT_CONTEXT_CREATE_8 = PROCEDURE) +symbol_vector = (PCRE2_MATCH_CONTEXT_CREATE_8 = PROCEDURE) +symbol_vector = (PCRE2_COMPILE_CONTEXT_CREATE_8 = PROCEDURE) +symbol_vector = (PCRE2_GENERAL_CONTEXT_CREATE_8 = PROCEDURE) +symbol_vector = (_PCRE2_AUTO_POSSESSIFY_8 = PROCEDURE) +symbol_vector = (_PCRE2_CKD_SMUL = PROCEDURE) +symbol_vector = (_PCRE2_FIND_BRACKET_8 = PROCEDURE) +symbol_vector = (_PCRE2_IS_NEWLINE_8 = PROCEDURE) +symbol_vector = (_PCRE2_WAS_NEWLINE_8 = PROCEDURE) +symbol_vector = (_PCRE2_SCRIPT_RUN_8 = PROCEDURE) +symbol_vector = (_PCRE2_STRCMP_8 = PROCEDURE) +symbol_vector = (_PCRE2_STRCPY_C8_8 = PROCEDURE) +symbol_vector = (_PCRE2_STRLEN_8 = PROCEDURE) +symbol_vector = (_PCRE2_STRNCMP_C8_8 = PROCEDURE) +symbol_vector = (_PCRE2_STRNCMP_8 = PROCEDURE) +symbol_vector = (_PCRE2_STRCMP_C8_8 = PROCEDURE) +symbol_vector = (_PCRE2_STUDY_8 = PROCEDURE) +symbol_vector = (_PCRE2_VALID_UTF_8 = PROCEDURE) +symbol_vector = (VMS_PCRE2_DEF_CMPL_CNTXT_8 = DATA) +symbol_vector = (VMS_PCRE2_DEF_CNVRT_CNTXT_8 = DATA) +symbol_vector = (_PCRE2_CALLOUT_END_DELIMS_8 = DATA) +symbol_vector = (_PCRE2_CALLOUT_START_DELIMS_8 = DATA) +symbol_vector = (_PCRE2_DEFAULT_MATCH_CONTEXT_8 = DATA) +symbol_vector = (_PCRE2_DEFAULT_TABLES_8 = DATA) +symbol_vector = (_PCRE2_HSPACE_LIST_8 = DATA) +symbol_vector = (_PCRE2_OP_LENGTHS_8 = DATA) +symbol_vector = (_PCRE2_UCD_CASELESS_SETS_8 = DATA) +symbol_vector = (_PCRE2_UCD_RECORDS_8 = DATA) +symbol_vector = (_PCRE2_UCD_STAGE1_8 = DATA) +symbol_vector = (_PCRE2_UCD_STAGE2_8 = DATA) +symbol_vector = (_PCRE2_VSPACE_LIST_8 = DATA) +! +! ### PSECT list extracted from PCRE2.MAP;1 +! +$ENDIF +$! +$! +COPY SYS$INPUT [.SRC]CONFIG.H +/* src/config.h.in. Generated from configure.ac by autoheader. */ + + +/* PCRE2 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. + +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 PCRE2 "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, +but if you do, default values will be taken from config.h for non-boolean +macros that are not defined on the command line. + +Boolean macros such as HAVE_STDLIB_H and SUPPORT_PCRE2_8 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. + +PCRE2 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 (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 PCRE2 at runtime. + */ +#undef BSR_ANYCRLF + +/* Define to any value to disable the use of the z and t modifiers in + formatting settings such as %zu or %td (this is rarely needed). */ +#undef DISABLE_PERCENT_ZT + +/* If you are compiling for a system that uses EBCDIC instead of ASCII + character codes, define this macro to any value. When EBCDIC is set, PCRE2 + assumes that all input strings are in EBCDIC. If you do not define this + macro, PCRE2 will assume input strings are ASCII or UTF-8/16/32 Unicode. It + is not possible to build a version of PCRE2 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. */ +#undef EBCDIC_NL25 + +/* Define this if your compiler supports __attribute__((uninitialized)) */ +#undef HAVE_ATTRIBUTE_UNINITIALIZED + +/* Define to 1 if you have the 'bcopy' function. */ +#define HAVE_BCOPY 1 + +/* Define this if your compiler provides __builtin_mul_overflow() */ +#undef HAVE_BUILTIN_MUL_OVERFLOW + + +/* Define to 1 if you have the header file. */ +#define HAVE_DIRENT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the header file. */ +#undef HAVE_EDITLINE_READLINE_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_EDIT_READLINE_READLINE_H + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define to 1 if you have the 'memfd_create' function. */ +#undef HAVE_MEMFD_CREATE + +/* Define to 1 if you have the 'memmove' function. */ +#define HAVE_MEMMOVE 1 + +/* Define to 1 if you have the header file. */ +#undef HAVE_MINIX_CONFIG_H + +/* Define to 1 if you have the 'mkostemp' function. */ +#undef HAVE_MKOSTEMP + +/* Define if you have POSIX threads libraries and header files. */ +#define HAVE_PTHREAD 1 + +/* Have PTHREAD_PRIO_INHERIT. */ +#undef HAVE_PTHREAD_PRIO_INHERIT + +/* Define to 1 if you have the header file. */ +#undef HAVE_READLINE_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_READLINE_HISTORY_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_READLINE_READLINE_H + +/* Define to 1 if you have the `realpath' function. */ +#define HAVE_REALPATH 1 + +/* Define to 1 if you have the 'secure_getenv' function. */ +#undef HAVE_SECURE_GETENV + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDIO_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the 'strerror' function. */ +#define HAVE_STRERROR 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_WAIT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if the compiler supports simple visibility declarations. */ +#undef HAVE_VISIBILITY + +/* Define to 1 if you have the header file. */ +#define HAVE_WCHAR_H 1 + +/* Define to 1 if you have the header file. */ +#undef HAVE_WINDOWS_H + +/* Define to 1 if you have the header file. */ + +/* This limits the amount of memory that may be used while matching a pattern. + It applies to both pcre2_match() and pcre2_dfa_match(). It does not apply + to JIT matching. The value is in kibibytes (units of 1024 bytes). */ +#undef HEAP_LIMIT + +/* The value of LINK_SIZE determines the number of bytes used to store links + as offsets within the compiled regex. The default is 2, which allows for + compiled patterns up to 65535 code units long. This covers the vast + majority of cases. However, PCRE2 can also be compiled to use 3 or 4 bytes + instead. This allows for longer patterns in extreme cases. */ +#undef LINK_SIZE + +/* Define to the sub-directory where libtool stores uninstalled libraries. */ +#undef LT_OBJDIR + +/* The value of MATCH_LIMIT determines the default number of times the + pcre2_match() function can record a backtrack position during a single + matching attempt. The value is also used to limit a loop counter in + pcre2_dfa_match(). There is a runtime interface for setting a different + limit. The limit exists in order to catch runaway regular expressions that + take forever to determine that they do not match. The default is set very + large so that it does not accidentally catch legitimate cases. */ +#undef MATCH_LIMIT + +/* The above limit applies to all backtracks, whether or not they are nested. + In some environments it is desirable to limit the nesting of backtracking + (that is, the depth of tree that is searched) more strictly, in order to + restrict the maximum amount of heap memory that is used. The value of + MATCH_LIMIT_DEPTH provides this facility. 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. In the case of pcre2_dfa_match(), this limit controls the depth of + the internal nested function calls that are used for pattern recursions, + lookarounds, and atomic groups. */ +#undef MATCH_LIMIT_DEPTH + +/* This limit is parameterized just in case anybody ever wants to change it. + Care must be taken if it is increased, because it guards against integer + overflow caused by enormously large patterns. */ +#undef MAX_NAME_COUNT + +/* This limit is parameterized just in case anybody ever wants to change it. + Care must be taken if it is increased, because it guards against integer + overflow caused by enormously large patterns. */ +#undef MAX_NAME_SIZE + +/* The value of MAX_VARLOOKBEHIND specifies the default maximum length, in + characters, for a variable-length lookbehind assertion. */ +#undef MAX_VARLOOKBEHIND + +/* Defining NEVER_BACKSLASH_C locks out the use of \C in all patterns. */ +#undef NEVER_BACKSLASH_C + +/* The value of NEWLINE_DEFAULT determines the default newline character + sequence. PCRE2 client programs can override this by selecting other values + at run time. The valid values are 1 (CR), 2 (LF), 3 (CRLF), 4 (ANY), 5 + (ANYCRLF), and 6 (NUL). */ +#undef NEWLINE_DEFAULT + +/* Name of package */ +#define PACKAGE "pcre2" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "PCRE2" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "PCRE2 10.43 VMS" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "pcre2" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "10.43" + +/* 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. */ +#undef PARENS_NEST_LIMIT + +/* The value of PCRE2GREP_BUFSIZE is the starting size of the buffer used by + pcre2grep to hold parts of the file it is searching. The buffer will be + expanded up to PCRE2GREP_MAX_BUFSIZE if necessary, for files containing + very long lines. The actual amount of memory used by pcre2grep is three + times this number, because it allows for the buffering of "before" and + "after" lines. */ +#define PCRE2GREP_BUFSIZE 20480 + +/* The value of PCRE2GREP_MAX_BUFSIZE specifies the maximum size of the buffer + used by pcre2grep to hold parts of the file it is searching. The actual + amount of memory used by pcre2grep is three times this number, because it + allows for the buffering of "before" and "after" lines. */ +#define PCRE2GREP_MAX_BUFSIZE 1048576 + +/* Define to any value to include debugging code. */ +#undef PCRE2_DEBUG + +/* to make a symbol visible */ +#undef PCRE2_EXPORT + + +/* 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, a suitable + __declspec value is used for Windows systems; in other environments + a compiler relevant "extern" is used with any "visibility" related + attributes from PCRE2_EXPORT included. + 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 PCRE2_EXP_DEFN + +/* Define to any value if linking statically (TODO: make nice with Libtool) */ +#undef PCRE2_STATIC + +/* Define to necessary symbol if this constant uses a non-standard name on + your system. */ +#undef PTHREAD_CREATE_JOINABLE + +/* Define to any non-zero number to enable support for SELinux compatible + executable memory allocator in JIT. Note that this will have no effect + unless SUPPORT_JIT is also defined. */ +#undef SLJIT_PROT_EXECUTABLE_ALLOCATOR + +/* Define to 1 if all of the C89 standard headers exist (not just the ones + required in a freestanding environment). This macro is provided for + backward compatibility; new code need not use it. */ +#define STDC_HEADERS 1 + +/* Define to any value to enable differential fuzzing support. */ +#undef SUPPORT_DIFF_FUZZ + +/* Define to any value to enable support for Just-In-Time compiling. */ +#undef SUPPORT_JIT + +/* Define to any value to allow pcre2grep to be linked with libbz2, so that it + is able to handle .bz2 files. */ + +/* Define to any value to allow pcre2test to be linked with libedit. */ +#undef SUPPORT_LIBEDIT + +/* Define to any value to allow pcre2test to be linked with libreadline. */ +#undef SUPPORT_LIBREADLINE + +/* Define to any value to allow pcre2grep to be linked with libz, so that it + is able to handle .gz files. */ + +/* Define to any value to enable callout script support in pcre2grep. */ +#undef SUPPORT_PCRE2GREP_CALLOUT + +/* Define to any value to enable fork support in pcre2grep callout scripts. + This will have no effect unless SUPPORT_PCRE2GREP_CALLOUT is also defined. + */ +#undef SUPPORT_PCRE2GREP_CALLOUT_FORK + +/* Define to any value to enable JIT support in pcre2grep. Note that this will + have no effect unless SUPPORT_JIT is also defined. */ +#undef SUPPORT_PCRE2GREP_JIT + +/* Define to any value to enable the 16 bit PCRE2 library. */ +#undef SUPPORT_PCRE2_16 + +/* Define to any value to enable the 32 bit PCRE2 library. */ +#undef SUPPORT_PCRE2_32 + +/* Define to any value to enable the 8 bit PCRE2 library. */ +#define SUPPORT_PCRE2_8 1 + +/* Define to any value to enable support for Unicode and UTF encoding. This + will work even in an EBCDIC environment, but it is incompatible with the + EBCDIC macro. That is, PCRE2 can support *either* EBCDIC code *or* + ASCII/Unicode, but not both at once. */ +#undef SUPPORT_UNICODE + +/* Define to any value for valgrind support to find invalid memory reads. */ +#undef SUPPORT_VALGRIND + +/* Enable extensions on AIX, Interix, z/OS. */ +#ifndef _ALL_SOURCE +# undef _ALL_SOURCE +#endif +/* Enable general extensions on macOS. */ +#ifndef _DARWIN_C_SOURCE +# undef _DARWIN_C_SOURCE +#endif +/* Enable general extensions on Solaris. */ +#ifndef __EXTENSIONS__ +# undef __EXTENSIONS__ +#endif +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +# undef _GNU_SOURCE +#endif +/* Enable X/Open compliant socket functions that do not require linking + with -lxnet on HP-UX 11.11. */ +#ifndef _HPUX_ALT_XOPEN_SOCKET_API +# undef _HPUX_ALT_XOPEN_SOCKET_API +#endif +/* Identify the host operating system as Minix. + This macro does not affect the system headers' behavior. + A future release of Autoconf may stop defining this macro. */ +#ifndef _MINIX +# undef _MINIX +#endif +/* Enable general extensions on NetBSD. + Enable NetBSD compatibility extensions on Minix. */ +#ifndef _NETBSD_SOURCE +# undef _NETBSD_SOURCE +#endif +/* Enable OpenBSD compatibility extensions on NetBSD. + Oddly enough, this does nothing on OpenBSD. */ +#ifndef _OPENBSD_SOURCE +# undef _OPENBSD_SOURCE +#endif +/* Define to 1 if needed for POSIX-compatible behavior. */ +#ifndef _POSIX_SOURCE +# undef _POSIX_SOURCE +#endif +/* Define to 2 if needed for POSIX-compatible behavior. */ +#ifndef _POSIX_1_SOURCE +# undef _POSIX_1_SOURCE +#endif +/* Enable POSIX-compatible threading on Solaris. */ +#ifndef _POSIX_PTHREAD_SEMANTICS +# undef _POSIX_PTHREAD_SEMANTICS +#endif +/* Enable extensions specified by ISO/IEC TS 18661-5:2014. */ +#ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__ +# undef __STDC_WANT_IEC_60559_ATTRIBS_EXT__ +#endif +/* Enable extensions specified by ISO/IEC TS 18661-1:2014. */ +#ifndef __STDC_WANT_IEC_60559_BFP_EXT__ +# undef __STDC_WANT_IEC_60559_BFP_EXT__ +#endif +/* Enable extensions specified by ISO/IEC TS 18661-2:2015. */ +#ifndef __STDC_WANT_IEC_60559_DFP_EXT__ +# undef __STDC_WANT_IEC_60559_DFP_EXT__ +#endif +/* Enable extensions specified by C23 Annex F. */ +#ifndef __STDC_WANT_IEC_60559_EXT__ +# undef __STDC_WANT_IEC_60559_EXT__ +#endif +/* Enable extensions specified by ISO/IEC TS 18661-4:2015. */ +#ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__ +# undef __STDC_WANT_IEC_60559_FUNCS_EXT__ +#endif +/* Enable extensions specified by C23 Annex H and ISO/IEC TS 18661-3:2015. */ +#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__ +# undef __STDC_WANT_IEC_60559_TYPES_EXT__ +#endif +/* Enable extensions specified by ISO/IEC TR 24731-2:2010. */ +#ifndef __STDC_WANT_LIB_EXT2__ +# undef __STDC_WANT_LIB_EXT2__ +#endif +/* Enable extensions specified by ISO/IEC 24747:2009. */ +#ifndef __STDC_WANT_MATH_SPEC_FUNCS__ +# undef __STDC_WANT_MATH_SPEC_FUNCS__ +#endif +/* Enable extensions on HP NonStop. */ +#ifndef _TANDEM_SOURCE +# undef _TANDEM_SOURCE +#endif +/* Enable X/Open extensions. Define to 500 only if necessary + to make mbstate_t available. */ +#ifndef _XOPEN_SOURCE +# undef _XOPEN_SOURCE +#endif + + +/* Version number of package */ +#undef VERSION + +/* Number of bits in a file offset, on hosts where this is settable. */ +#undef _FILE_OFFSET_BITS + +/* Define to 1 on platforms where this makes off_t a 64-bit type. */ +#undef _LARGE_FILES + +/* Number of bits in time_t, on hosts where this is settable. */ +#undef _TIME_BITS + +/* Define to 1 on platforms where this makes time_t a 64-bit type. */ +#undef __MINGW_USE_VC2005_COMPAT + +/* Define to empty if 'const' does not conform to ANSI C. */ +#undef const + +/* Define to the type of a signed integer type of width exactly 64 bits if + such a type exists and the standard includes do not define it. */ +#undef int64_t + +/* Define as 'unsigned int' if doesn't define. */ +#undef size_t + +// VMS +#include +#define PCRE2_EXPORT +#define LINK_SIZE 2 +#define MAX_NAME_COUNT 10000 +#define MAX_NAME_SIZE 32 +#define MATCH_LIMIT 10000000 +#define HEAP_LIMIT 20000000 +#define NEWLINE_DEFAULT 2 +#define PARENS_NEST_LIMIT 250 +#define MATCH_LIMIT_DEPTH MATCH_LIMIT +#define MAX_VARLOOKBEHIND 255 + +/* +#define _pcre2_default_compile_context_ vms_pcre2_def_cmpl_cntxt_ +#define _pcre2_default_convert_context_ vms_pcre2_def_cnvrt_cntxt_ +#define pcre2_set_compile_extra_options_8 vms_pcre2_set_cmpl_ext_opt_8 +#define pcre2_set_compile_recursion_guard_8 vms_pcre2_set_cmpl_rcrs_grd_8 +#define pcre2_set_recursion_memory_management_8 vms_pcre2_set_rcrs_mem_mng_8 +#define pcre2_match_data_create_from_pattern_8 vms_pcre2_m_d_crt_fr_patt_8 +#define pcre2_get_match_data_heapframes_size_8 vms_pcre2_get_m_d_hpfram_s_8 +#define pcre2_serialize_get_number_of_codes_8 vms_pcre2_ser_get_n_of_cod_8 +#define pcre2_substring_nametable_scan_8 vms_pcre2_substr_nmtab_scan_8 +#define pcre2_substring_length_bynumber_8 vms_pcre2_substr_len_bynum_8 +#define pcre2_substring_number_from_name_8 vms_pcre2_substr_num_f_nam_8 +*/ + +#define HAVE_BZLIB_H 1 +#define SUPPORT_LIBBZ2 1 + +#define HAVE_ZLIB_H 1 +#define SUPPORT_LIBZ 1 +$! +$! +$WRITE SYS$OUTPUT "config.h created" +$! +$!Creating Descrip.mms in each directory needed +$! +$! +$COPY SYS$INPUT [.SRC]DESCRIP.MMS +# (c) Alexey Chupahin 09-APR-2024 +# OpenVMS 7.3-2, DEC 2000 mod.300 +# OpenVMS 8.3, Digital PW 600au +# OpenVMS 8.4, Compaq DS10L +# OpenVMS 8.3, HP rx1620 + + +.FIRST + DEF PCRE2 [] + + +CC=cc +CFLAGS = /INCLUDE=([],[-],[-.VMS],ZLIB,BZ2LIB) \ + /DEFINE=(HAVE_CONFIG_H,PCRE2_CODE_UNIT_WIDTH=8)\ + /OPTIMIZE=(INLINE=SPEED) \ + /DEB + +OBJ=\ +PCRE2POSIX.OBJ,\ +PCRE2_AUTO_POSSESS.OBJ,\ +PCRE2_CHKDINT.OBJ,\ +PCRE2_CHARTABLES.OBJ,\ +PCRE2_COMPILE.OBJ,\ +PCRE2_CONFIG.OBJ,\ +PCRE2_CONTEXT.OBJ,\ +PCRE2_CONVERT.OBJ,\ +PCRE2_DFA_MATCH.OBJ,\ +PCRE2_ERROR.OBJ,\ +PCRE2_EXTUNI.OBJ,\ +PCRE2_FIND_BRACKET.OBJ,\ +PCRE2_JIT_COMPILE.OBJ,\ +PCRE2_MAKETABLES.OBJ,\ +PCRE2_MATCH.OBJ,\ +PCRE2_MATCH_DATA.OBJ,\ +PCRE2_NEWLINE.OBJ,\ +PCRE2_ORD2UTF.OBJ,\ +PCRE2_PATTERN_INFO.OBJ,\ +PCRE2_SCRIPT_RUN.OBJ,\ +PCRE2_SERIALIZE.OBJ,\ +PCRE2_STRING_UTILS.OBJ,\ +PCRE2_STUDY.OBJ,\ +PCRE2_SUBSTITUTE.OBJ,\ +PCRE2_SUBSTRING.OBJ,\ +PCRE2_TABLES.OBJ,\ +PCRE2_UCD.OBJ,\ +PCRE2_VALID_UTF.OBJ,\ +PCRE2_XCLASS.OBJ + +ALL : PCRE2.H PCRE2.OLB PCRE2$SHR.EXE PCRE2DEMO.EXE PCRE2GREP.EXE + $! + +PCRE2$SHR.EXE : PCRE2.OLB + LINK/SHARE=PCRE2$SHR.EXE PCRE2:PCRE2.OLB/LIB,PCRE2:PCRE2$DEF.OPT/OPT + +PCRE2.OLB : $(OBJ) + LIB/CREA PCRE2.OLB $(OBJ) + +PCRE2DEMO.EXE : PCRE2DEMO.OBJ + LINK/EXE=PCRE2DEMO PCRE2DEMO,PCRE2:PCRE2.OPT/OPT + +PCRE2GREP.EXE : PCRE2GREP.OBJ + LINK/EXE=PCRE2GREP PCRE2GREP,PCRE2:PCRE2.OPT/OPT,ZLIB:ZLIB.OPT/OPT,BZ2LIB:BZIP2.OPT/OPT + +PCRE2.H : PCRE2.H_GENERIC + WRITE SYS$OUTPUT "Patching PCRE2.H" + COPY/CONCAT [-.VMS]PCRE2.H_PATCH,[]PCRE2.H_GENERIC PCRE2.H + +PCRE2_CHARTABLES.OBJ : PCRE2_CHARTABLES.C + $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET) + +PCRE2_CHARTABLES.C : PCRE2_CHARTABLES.C_DIST + COPY PCRE2_CHARTABLES.C_DIST PCRE2_CHARTABLES.C + +PCRE2DEMO.OBJ : PCRE2DEMO.C + $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET) + +PCRE2GREP.OBJ : PCRE2GREP.C + $(CC) $(CFLAGS) /WARN=DIS=ALL $(MMS$SOURCE) /OBJ=$(MMS$TARGET) + +PCRE2POSIX.OBJ : PCRE2POSIX.C + $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET) + +PCRE2POSIX_TEST.OBJ : PCRE2POSIX_TEST.C + $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET) + +PCRE2TEST.OBJ : PCRE2TEST.C + $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET) + +PCRE2_AUTO_POSSESS.OBJ : PCRE2_AUTO_POSSESS.C + $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET) + +PCRE2_CHKDINT.OBJ : PCRE2_CHKDINT.C + $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET) + +PCRE2_COMPILE.OBJ : PCRE2_COMPILE.C + $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET) + +PCRE2_CONFIG.OBJ : PCRE2_CONFIG.C + $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET) + +PCRE2_CONTEXT.OBJ : PCRE2_CONTEXT.C + $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET) + +PCRE2_CONVERT.OBJ : PCRE2_CONVERT.C + $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET) + +PCRE2_DFA_MATCH.OBJ : PCRE2_DFA_MATCH.C + $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET) + +PCRE2_DFTABLES.OBJ : PCRE2_DFTABLES.C + $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET) + +PCRE2_ERROR.OBJ : PCRE2_ERROR.C + $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET) + +PCRE2_EXTUNI.OBJ : PCRE2_EXTUNI.C + $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET) + +PCRE2_FIND_BRACKET.OBJ : PCRE2_FIND_BRACKET.C + $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET) + +PCRE2_FUZZSUPPORT.OBJ : PCRE2_FUZZSUPPORT.C + $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET) + +PCRE2_JIT_COMPILE.OBJ : PCRE2_JIT_COMPILE.C + $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET) + +PCRE2_JIT_MATCH.OBJ : PCRE2_JIT_MATCH.C + $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET) + +PCRE2_JIT_MISC.OBJ : PCRE2_JIT_MISC.C + $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET) + +PCRE2_JIT_TEST.OBJ : PCRE2_JIT_TEST.C + $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET) + +PCRE2_MAKETABLES.OBJ : PCRE2_MAKETABLES.C + $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET) + +PCRE2_MATCH.OBJ : PCRE2_MATCH.C + $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET) + +PCRE2_MATCH_DATA.OBJ : PCRE2_MATCH_DATA.C + $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET) + +PCRE2_NEWLINE.OBJ : PCRE2_NEWLINE.C + $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET) + +PCRE2_ORD2UTF.OBJ : PCRE2_ORD2UTF.C + $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET) + +PCRE2_PATTERN_INFO.OBJ : PCRE2_PATTERN_INFO.C + $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET) + +PCRE2_PRINTINT.OBJ : PCRE2_PRINTINT.C + $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET) + +PCRE2_SCRIPT_RUN.OBJ : PCRE2_SCRIPT_RUN.C + $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET) + +PCRE2_SERIALIZE.OBJ : PCRE2_SERIALIZE.C + $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET) + +PCRE2_STRING_UTILS.OBJ : PCRE2_STRING_UTILS.C + $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET) + +PCRE2_STUDY.OBJ : PCRE2_STUDY.C + $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET) + +PCRE2_SUBSTITUTE.OBJ : PCRE2_SUBSTITUTE.C + $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET) + +PCRE2_SUBSTRING.OBJ : PCRE2_SUBSTRING.C + $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET) + +PCRE2_TABLES.OBJ : PCRE2_TABLES.C + $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET) + +PCRE2_UCD.OBJ : PCRE2_UCD.C + $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET) + +PCRE2_UCPTABLES.OBJ : PCRE2_UCPTABLES.C + $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET) + +PCRE2_VALID_UTF.OBJ : PCRE2_VALID_UTF.C + $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET) + +PCRE2_XCLASS.OBJ : PCRE2_XCLASS.C + $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET) + +$! +$! +$WRITE SYS$OUTPUT "DESCRIP.MMS's have been created" +$WRITE SYS$OUTPUT " " +$WRITE SYS$OUTPUT " " +$WRITE SYS$OUTPUT "Now you can type @BUILD " +$! +$EXIT: +$DEFINE SYS$ERROR _NLA0: +$DEFINE SYS$OUTPUT _NLA0: +$DEL TEST.C;* +$DEL TEST.OBJ;* +$DEL TEST.EXE;* +$DEL TEST.OPT;* +$DEAS SYS$ERROR +$DEAS SYS$OUTPUT + diff --git a/vms/openvms_readme.txt b/vms/openvms_readme.txt new file mode 100644 index 0000000..7978a75 --- /dev/null +++ b/vms/openvms_readme.txt @@ -0,0 +1,20 @@ +This is directory for OpenVMS support, +provided shared and static library, +pcre2grep utility also. + +Requires: +bzip2 library : http://vaxvms.org/clamav/ +zlib library : http://vaxvms.org/libsdl/required.html + + +To build the library please: + +@[.VMS]CONFIGURE.COM +@BUILD + +After build, PCRE2$STARTUP.COM has been created +it should be started before use (good place from LOGIN.COM) + +Feel free to contact: +alexey@vaxman.de +Alexey Chupahin diff --git a/vms/pcre2.h_patch b/vms/pcre2.h_patch new file mode 100644 index 0000000..0134734 --- /dev/null +++ b/vms/pcre2.h_patch @@ -0,0 +1,12 @@ +#define _pcre2_default_compile_context_ vms_pcre2_def_cmpl_cntxt_ +#define _pcre2_default_convert_context_ vms_pcre2_def_cnvrt_cntxt_ +#define pcre2_set_compile_extra_options_8 vms_pcre2_set_cmpl_ext_opt_8 +#define pcre2_set_compile_recursion_guard_8 vms_pcre2_set_cmpl_rcrs_grd_8 +#define pcre2_set_recursion_memory_management_8 vms_pcre2_set_rcrs_mem_mng_8 +#define pcre2_match_data_create_from_pattern_8 vms_pcre2_m_d_crt_fr_patt_8 +#define pcre2_get_match_data_heapframes_size_8 vms_pcre2_get_m_d_hpfram_s_8 +#define pcre2_serialize_get_number_of_codes_8 vms_pcre2_ser_get_n_of_cod_8 +#define pcre2_substring_nametable_scan_8 vms_pcre2_substr_nmtab_scan_8 +#define pcre2_substring_length_bynumber_8 vms_pcre2_substr_len_bynum_8 +#define pcre2_substring_number_from_name_8 vms_pcre2_substr_num_f_nam_8 +#define pcre2_set_max_pattern_compiled_length vms_pcre2_set_max_pat_cmpl_len diff --git a/vms/stdint.h b/vms/stdint.h new file mode 100644 index 0000000..3a5a5a2 --- /dev/null +++ b/vms/stdint.h @@ -0,0 +1,9 @@ +#ifndef MY_VMS_STDINT +#define MY_VMS_STDINT +#include +#include +#include +#define SIZE_MAX UINT_MAX +#define UINT32_MAX 4294967295u +#define UINT16_MAX (65535) +#endif