From c917f1848c6bc7e5e57ba126fab03e3df518075e Mon Sep 17 00:00:00 2001 From: Relintai Date: Sat, 16 Dec 2023 15:35:14 +0100 Subject: [PATCH] Removed the regex module. --- modules/regex/SCsub | 76 - modules/regex/config.py | 17 - modules/regex/doc_classes/RegEx.xml | 124 - modules/regex/doc_classes/RegExMatch.xml | 56 - modules/regex/pcre2/AUTHORS | 36 - modules/regex/pcre2/LICENCE | 94 - .../patches/sljit-macos11-conditional.patch | 31 - modules/regex/pcre2/src/config.h | 457 - modules/regex/pcre2/src/pcre2.h | 993 -- modules/regex/pcre2/src/pcre2_auto_possess.c | 1365 -- modules/regex/pcre2/src/pcre2_chartables.c | 202 - modules/regex/pcre2/src/pcre2_compile.c | 10631 ----------- modules/regex/pcre2/src/pcre2_config.c | 252 - modules/regex/pcre2/src/pcre2_context.c | 494 - modules/regex/pcre2/src/pcre2_convert.c | 1181 -- modules/regex/pcre2/src/pcre2_dfa_match.c | 4066 ----- modules/regex/pcre2/src/pcre2_error.c | 341 - modules/regex/pcre2/src/pcre2_extuni.c | 148 - modules/regex/pcre2/src/pcre2_find_bracket.c | 219 - modules/regex/pcre2/src/pcre2_internal.h | 2047 --- modules/regex/pcre2/src/pcre2_intmodedep.h | 934 - modules/regex/pcre2/src/pcre2_jit_compile.c | 14507 ---------------- modules/regex/pcre2/src/pcre2_jit_match.c | 186 - modules/regex/pcre2/src/pcre2_jit_misc.c | 234 - modules/regex/pcre2/src/pcre2_jit_neon_inc.h | 349 - modules/regex/pcre2/src/pcre2_jit_simd_inc.h | 1858 -- modules/regex/pcre2/src/pcre2_maketables.c | 163 - modules/regex/pcre2/src/pcre2_match.c | 7544 -------- modules/regex/pcre2/src/pcre2_match_data.c | 173 - modules/regex/pcre2/src/pcre2_newline.c | 243 - modules/regex/pcre2/src/pcre2_ord2utf.c | 120 - modules/regex/pcre2/src/pcre2_pattern_info.c | 432 - modules/regex/pcre2/src/pcre2_script_run.c | 344 - modules/regex/pcre2/src/pcre2_serialize.c | 286 - modules/regex/pcre2/src/pcre2_string_utils.c | 237 - modules/regex/pcre2/src/pcre2_study.c | 1825 -- modules/regex/pcre2/src/pcre2_substitute.c | 1009 -- modules/regex/pcre2/src/pcre2_substring.c | 547 - modules/regex/pcre2/src/pcre2_tables.c | 234 - modules/regex/pcre2/src/pcre2_ucd.c | 5396 ------ modules/regex/pcre2/src/pcre2_ucp.h | 394 - modules/regex/pcre2/src/pcre2_ucptables.c | 1524 -- modules/regex/pcre2/src/pcre2_valid_utf.c | 398 - modules/regex/pcre2/src/pcre2_xclass.c | 289 - modules/regex/pcre2/src/sljit/sljitConfig.h | 162 - .../pcre2/src/sljit/sljitConfigInternal.h | 851 - .../pcre2/src/sljit/sljitExecAllocator.c | 411 - modules/regex/pcre2/src/sljit/sljitLir.c | 3136 ---- modules/regex/pcre2/src/sljit/sljitLir.h | 1823 -- .../regex/pcre2/src/sljit/sljitNativeARM_32.c | 3700 ---- .../regex/pcre2/src/sljit/sljitNativeARM_64.c | 2417 --- .../pcre2/src/sljit/sljitNativeARM_T2_32.c | 3150 ---- .../pcre2/src/sljit/sljitNativeMIPS_32.c | 314 - .../pcre2/src/sljit/sljitNativeMIPS_64.c | 319 - .../pcre2/src/sljit/sljitNativeMIPS_common.c | 3720 ---- .../regex/pcre2/src/sljit/sljitNativePPC_32.c | 340 - .../regex/pcre2/src/sljit/sljitNativePPC_64.c | 579 - .../pcre2/src/sljit/sljitNativePPC_common.c | 2851 --- .../pcre2/src/sljit/sljitNativeRISCV_32.c | 73 - .../pcre2/src/sljit/sljitNativeRISCV_64.c | 183 - .../pcre2/src/sljit/sljitNativeRISCV_common.c | 2762 --- .../regex/pcre2/src/sljit/sljitNativeS390X.c | 3747 ---- .../regex/pcre2/src/sljit/sljitNativeX86_32.c | 1298 -- .../regex/pcre2/src/sljit/sljitNativeX86_64.c | 1092 -- .../pcre2/src/sljit/sljitNativeX86_common.c | 3422 ---- .../pcre2/src/sljit/sljitProtExecAllocator.c | 474 - modules/regex/pcre2/src/sljit/sljitUtils.c | 344 - .../pcre2/src/sljit/sljitWXExecAllocator.c | 204 - modules/regex/regex.cpp | 407 - modules/regex/regex.h | 100 - modules/regex/register_types.cpp | 43 - modules/regex/register_types.h | 38 - scu_builders.py | 2 +- 73 files changed, 1 insertion(+), 100017 deletions(-) delete mode 100644 modules/regex/SCsub delete mode 100644 modules/regex/config.py delete mode 100644 modules/regex/doc_classes/RegEx.xml delete mode 100644 modules/regex/doc_classes/RegExMatch.xml delete mode 100644 modules/regex/pcre2/AUTHORS delete mode 100644 modules/regex/pcre2/LICENCE delete mode 100644 modules/regex/pcre2/patches/sljit-macos11-conditional.patch delete mode 100644 modules/regex/pcre2/src/config.h delete mode 100644 modules/regex/pcre2/src/pcre2.h delete mode 100644 modules/regex/pcre2/src/pcre2_auto_possess.c delete mode 100644 modules/regex/pcre2/src/pcre2_chartables.c delete mode 100644 modules/regex/pcre2/src/pcre2_compile.c delete mode 100644 modules/regex/pcre2/src/pcre2_config.c delete mode 100644 modules/regex/pcre2/src/pcre2_context.c delete mode 100644 modules/regex/pcre2/src/pcre2_convert.c delete mode 100644 modules/regex/pcre2/src/pcre2_dfa_match.c delete mode 100644 modules/regex/pcre2/src/pcre2_error.c delete mode 100644 modules/regex/pcre2/src/pcre2_extuni.c delete mode 100644 modules/regex/pcre2/src/pcre2_find_bracket.c delete mode 100644 modules/regex/pcre2/src/pcre2_internal.h delete mode 100644 modules/regex/pcre2/src/pcre2_intmodedep.h delete mode 100644 modules/regex/pcre2/src/pcre2_jit_compile.c delete mode 100644 modules/regex/pcre2/src/pcre2_jit_match.c delete mode 100644 modules/regex/pcre2/src/pcre2_jit_misc.c delete mode 100644 modules/regex/pcre2/src/pcre2_jit_neon_inc.h delete mode 100644 modules/regex/pcre2/src/pcre2_jit_simd_inc.h delete mode 100644 modules/regex/pcre2/src/pcre2_maketables.c delete mode 100644 modules/regex/pcre2/src/pcre2_match.c delete mode 100644 modules/regex/pcre2/src/pcre2_match_data.c delete mode 100644 modules/regex/pcre2/src/pcre2_newline.c delete mode 100644 modules/regex/pcre2/src/pcre2_ord2utf.c delete mode 100644 modules/regex/pcre2/src/pcre2_pattern_info.c delete mode 100644 modules/regex/pcre2/src/pcre2_script_run.c delete mode 100644 modules/regex/pcre2/src/pcre2_serialize.c delete mode 100644 modules/regex/pcre2/src/pcre2_string_utils.c delete mode 100644 modules/regex/pcre2/src/pcre2_study.c delete mode 100644 modules/regex/pcre2/src/pcre2_substitute.c delete mode 100644 modules/regex/pcre2/src/pcre2_substring.c delete mode 100644 modules/regex/pcre2/src/pcre2_tables.c delete mode 100644 modules/regex/pcre2/src/pcre2_ucd.c delete mode 100644 modules/regex/pcre2/src/pcre2_ucp.h delete mode 100644 modules/regex/pcre2/src/pcre2_ucptables.c delete mode 100644 modules/regex/pcre2/src/pcre2_valid_utf.c delete mode 100644 modules/regex/pcre2/src/pcre2_xclass.c delete mode 100644 modules/regex/pcre2/src/sljit/sljitConfig.h delete mode 100644 modules/regex/pcre2/src/sljit/sljitConfigInternal.h delete mode 100644 modules/regex/pcre2/src/sljit/sljitExecAllocator.c delete mode 100644 modules/regex/pcre2/src/sljit/sljitLir.c delete mode 100644 modules/regex/pcre2/src/sljit/sljitLir.h delete mode 100644 modules/regex/pcre2/src/sljit/sljitNativeARM_32.c delete mode 100644 modules/regex/pcre2/src/sljit/sljitNativeARM_64.c delete mode 100644 modules/regex/pcre2/src/sljit/sljitNativeARM_T2_32.c delete mode 100644 modules/regex/pcre2/src/sljit/sljitNativeMIPS_32.c delete mode 100644 modules/regex/pcre2/src/sljit/sljitNativeMIPS_64.c delete mode 100644 modules/regex/pcre2/src/sljit/sljitNativeMIPS_common.c delete mode 100644 modules/regex/pcre2/src/sljit/sljitNativePPC_32.c delete mode 100644 modules/regex/pcre2/src/sljit/sljitNativePPC_64.c delete mode 100644 modules/regex/pcre2/src/sljit/sljitNativePPC_common.c delete mode 100644 modules/regex/pcre2/src/sljit/sljitNativeRISCV_32.c delete mode 100644 modules/regex/pcre2/src/sljit/sljitNativeRISCV_64.c delete mode 100644 modules/regex/pcre2/src/sljit/sljitNativeRISCV_common.c delete mode 100644 modules/regex/pcre2/src/sljit/sljitNativeS390X.c delete mode 100644 modules/regex/pcre2/src/sljit/sljitNativeX86_32.c delete mode 100644 modules/regex/pcre2/src/sljit/sljitNativeX86_64.c delete mode 100644 modules/regex/pcre2/src/sljit/sljitNativeX86_common.c delete mode 100644 modules/regex/pcre2/src/sljit/sljitProtExecAllocator.c delete mode 100644 modules/regex/pcre2/src/sljit/sljitUtils.c delete mode 100644 modules/regex/pcre2/src/sljit/sljitWXExecAllocator.c delete mode 100644 modules/regex/regex.cpp delete mode 100644 modules/regex/regex.h delete mode 100644 modules/regex/register_types.cpp delete mode 100644 modules/regex/register_types.h diff --git a/modules/regex/SCsub b/modules/regex/SCsub deleted file mode 100644 index d7983de..0000000 --- a/modules/regex/SCsub +++ /dev/null @@ -1,76 +0,0 @@ -#!/usr/bin/env python - -Import("env") -Import("env_modules") - -env_regex = env_modules.Clone() - -# Thirdparty source files - -thirdparty_obj = [] - -if env["builtin_pcre2"]: - thirdparty_dir = "pcre2/src/" - thirdparty_flags = ["PCRE2_STATIC", "HAVE_CONFIG_H", "SUPPORT_UNICODE"] - - if env["builtin_pcre2_with_jit"]: - thirdparty_flags.append("SUPPORT_JIT") - - thirdparty_sources = [ - "pcre2_auto_possess.c", - "pcre2_chartables.c", - "pcre2_compile.c", - "pcre2_config.c", - "pcre2_context.c", - "pcre2_convert.c", - "pcre2_dfa_match.c", - "pcre2_error.c", - "pcre2_extuni.c", - "pcre2_find_bracket.c", - "pcre2_jit_compile.c", - # "pcre2_jit_match.c", "pcre2_jit_misc.c", # these files are included in pcre2_jit_compile.c. - "pcre2_maketables.c", - "pcre2_match.c", - "pcre2_match_data.c", - "pcre2_newline.c", - "pcre2_ord2utf.c", - "pcre2_pattern_info.c", - "pcre2_script_run.c", - "pcre2_serialize.c", - "pcre2_string_utils.c", - "pcre2_study.c", - "pcre2_substitute.c", - "pcre2_substring.c", - "pcre2_tables.c", - "pcre2_ucd.c", - "pcre2_valid_utf.c", - "pcre2_xclass.c", - ] - - thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] - - env_regex.Prepend(CPPPATH=[thirdparty_dir]) - env_regex.Append(CPPDEFINES=thirdparty_flags) - - def pcre2_builtin(width): - env_pcre2 = env_regex.Clone() - env_pcre2.disable_warnings() - env_pcre2["OBJSUFFIX"] = "_" + width + env_pcre2["OBJSUFFIX"] - env_pcre2.Append(CPPDEFINES=[("PCRE2_CODE_UNIT_WIDTH", width)]) - env_pcre2.add_source_files(thirdparty_obj, thirdparty_sources) - - pcre2_builtin("16") - pcre2_builtin("32") - env.modules_sources += thirdparty_obj - - -# Pandemonium source files - -module_obj = [] - -env_regex.Append(CPPDEFINES=[("PCRE2_CODE_UNIT_WIDTH", 0)]) -env_regex.add_source_files(module_obj, "*.cpp") -env.modules_sources += module_obj - -# Needed to force rebuilding the module files when the thirdparty library is updated. -env.Depends(module_obj, thirdparty_obj) diff --git a/modules/regex/config.py b/modules/regex/config.py deleted file mode 100644 index df9f44c..0000000 --- a/modules/regex/config.py +++ /dev/null @@ -1,17 +0,0 @@ -def can_build(env, platform): - return True - - -def configure(env): - pass - - -def get_doc_classes(): - return [ - "RegEx", - "RegExMatch", - ] - - -def get_doc_path(): - return "doc_classes" diff --git a/modules/regex/doc_classes/RegEx.xml b/modules/regex/doc_classes/RegEx.xml deleted file mode 100644 index 83b389a..0000000 --- a/modules/regex/doc_classes/RegEx.xml +++ /dev/null @@ -1,124 +0,0 @@ - - - - Class for searching text for patterns using regular expressions. - - - A regular expression (or regex) is a compact language that can be used to recognise strings that follow a specific pattern, such as URLs, email addresses, complete sentences, etc. For instance, a regex of [code]ab[0-9][/code] would find any string that is [code]ab[/code] followed by any number from [code]0[/code] to [code]9[/code]. For a more in-depth look, you can easily find various tutorials and detailed explanations on the Internet. - To begin, the RegEx object needs to be compiled with the search pattern using [method compile] before it can be used. - [codeblock] - var regex = RegEx.new() - regex.compile("\\w-(\\d+)") - [/codeblock] - The search pattern must be escaped first for GDScript before it is escaped for the expression. For example, [code]compile("\\d+")[/code] would be read by RegEx as [code]\d+[/code]. Similarly, [code]compile("\"(?:\\\\.|[^\"])*\"")[/code] would be read as [code]"(?:\\.|[^"])*"[/code]. - Using [method search], you can find the pattern within the given text. If a pattern is found, [RegExMatch] is returned and you can retrieve details of the results using methods such as [method RegExMatch.get_string] and [method RegExMatch.get_start]. - [codeblock] - var regex = RegEx.new() - regex.compile("\\w-(\\d+)") - var result = regex.search("abc n-0123") - if result: - print(result.get_string()) # Would print n-0123 - [/codeblock] - The results of capturing groups [code]()[/code] can be retrieved by passing the group number to the various methods in [RegExMatch]. Group 0 is the default and will always refer to the entire pattern. In the above example, calling [code]result.get_string(1)[/code] would give you [code]0123[/code]. - This version of RegEx also supports named capturing groups, and the names can be used to retrieve the results. If two or more groups have the same name, the name would only refer to the first one with a match. - [codeblock] - var regex = RegEx.new() - regex.compile("d(?<digit>[0-9]+)|x(?<digit>[0-9a-f]+)") - var result = regex.search("the number is x2f") - if result: - print(result.get_string("digit")) # Would print 2f - [/codeblock] - If you need to process multiple results, [method search_all] generates a list of all non-overlapping results. This can be combined with a [code]for[/code] loop for convenience. - [codeblock] - for result in regex.search_all("d01, d03, d0c, x3f and x42"): - print(result.get_string("digit")) - # Would print 01 03 0 3f 42 - [/codeblock] - [b]Example of splitting a string using a RegEx:[/b] - [codeblock] - var regex = RegEx.new() - regex.compile("\\S+") # Negated whitespace character class. - var results = [] - for result in regex.search_all("One Two \n\tThree"): - results.push_back(result.get_string()) - # The `results` array now contains "One", "Two", "Three". - [/codeblock] - [b]Note:[/b] Pandemonium's regex implementation is based on the [url=https://www.pcre.org/]PCRE2[/url] library. You can view the full pattern reference [url=https://www.pcre.org/current/doc/html/pcre2pattern.html]here[/url]. - [b]Tip:[/b] You can use [url=https://regexr.com/]Regexr[/url] to test regular expressions online. - - - - - - - - This method resets the state of the object, as if it was freshly created. Namely, it unassigns the regular expression of this object. - - - - - - - Compiles and assign the search pattern to use. Returns [constant OK] if the compilation is successful. If an error is encountered, details are printed to standard output and an error is returned. - - - - - - Returns the number of capturing groups in compiled pattern. - - - - - - Returns an array of names of named capturing groups in the compiled pattern. They are ordered by appearance. - - - - - - Returns the original search pattern that was compiled. - - - - - - Returns whether this object has a valid search pattern assigned. - - - - - - - - - Searches the text for the compiled pattern. Returns a [RegExMatch] container of the first matching result if found, otherwise [code]null[/code]. - The region to search within can be specified with [code]offset[/code] and [code]end[/code]. This is useful when searching for another match in the same [code]subject[/code] by calling this method again after a previous success. Setting these parameters differs from passing over a shortened string. For example, the start anchor [code]^[/code] is not affected by [code]offset[/code], and the character before [code]offset[/code] will be checked for the word boundary [code]\b[/code]. - - - - - - - - - Searches the text for the compiled pattern. Returns an array of [RegExMatch] containers for each non-overlapping result. If no results were found, an empty array is returned instead. - The region to search within can be specified with [code]offset[/code] and [code]end[/code]. This is useful when searching for another match in the same [code]subject[/code] by calling this method again after a previous success. Setting these parameters differs from passing over a shortened string. For example, the start anchor [code]^[/code] is not affected by [code]offset[/code], and the character before [code]offset[/code] will be checked for the word boundary [code]\b[/code]. - - - - - - - - - - - Searches the text for the compiled pattern and replaces it with the specified string. Escapes and backreferences such as [code]$1[/code] and [code]$name[/code] are expanded and resolved. By default, only the first instance is replaced, but it can be changed for all instances (global replacement). - The region to search within can be specified with [code]offset[/code] and [code]end[/code]. This is useful when searching for another match in the same [code]subject[/code] by calling this method again after a previous success. Setting these parameters differs from passing over a shortened string. For example, the start anchor [code]^[/code] is not affected by [code]offset[/code], and the character before [code]offset[/code] will be checked for the word boundary [code]\b[/code]. - - - - - - diff --git a/modules/regex/doc_classes/RegExMatch.xml b/modules/regex/doc_classes/RegExMatch.xml deleted file mode 100644 index 1f23095..0000000 --- a/modules/regex/doc_classes/RegExMatch.xml +++ /dev/null @@ -1,56 +0,0 @@ - - - - Contains the results of a [RegEx] search. - - - Contains the results of a single [RegEx] match returned by [method RegEx.search] and [method RegEx.search_all]. It can be used to find the position and range of the match and its capturing groups, and it can extract its substring for you. - - - - - - - - - Returns the end position of the match within the source string. The end position of capturing groups can be retrieved by providing its group number as an integer or its string name (if it's a named group). The default value of 0 refers to the whole pattern. - Returns -1 if the group did not match or doesn't exist. - - - - - - Returns the number of capturing groups. - - - - - - - Returns the starting position of the match within the source string. The starting position of capturing groups can be retrieved by providing its group number as an integer or its string name (if it's a named group). The default value of 0 refers to the whole pattern. - Returns -1 if the group did not match or doesn't exist. - - - - - - - Returns the substring of the match from the source string. Capturing groups can be retrieved by providing its group number as an integer or its string name (if it's a named group). The default value of 0 refers to the whole pattern. - Returns an empty string if the group did not match or doesn't exist. - - - - - - A dictionary of named groups and its corresponding group number. Only groups that were matched are included. If multiple groups have the same name, that name would refer to the first matching one. - - - An [Array] of the match and its capturing groups. - - - The source string used with the search pattern to find this matching result. - - - - - diff --git a/modules/regex/pcre2/AUTHORS b/modules/regex/pcre2/AUTHORS deleted file mode 100644 index 11ef898..0000000 --- a/modules/regex/pcre2/AUTHORS +++ /dev/null @@ -1,36 +0,0 @@ -THE MAIN PCRE2 LIBRARY CODE ---------------------------- - -Written by: Philip Hazel -Email local part: Philip.Hazel -Email domain: gmail.com - -Retired from University of Cambridge Computing Service, -Cambridge, England. - -Copyright (c) 1997-2022 University of Cambridge -All rights reserved - - -PCRE2 JUST-IN-TIME COMPILATION SUPPORT --------------------------------------- - -Written by: Zoltan Herczeg -Email local part: hzmester -Emain domain: freemail.hu - -Copyright(c) 2010-2022 Zoltan Herczeg -All rights reserved. - - -STACK-LESS JUST-IN-TIME COMPILER --------------------------------- - -Written by: Zoltan Herczeg -Email local part: hzmester -Emain domain: freemail.hu - -Copyright(c) 2009-2022 Zoltan Herczeg -All rights reserved. - -#### diff --git a/modules/regex/pcre2/LICENCE b/modules/regex/pcre2/LICENCE deleted file mode 100644 index 2f3cd5c..0000000 --- a/modules/regex/pcre2/LICENCE +++ /dev/null @@ -1,94 +0,0 @@ -PCRE2 LICENCE -------------- - -PCRE2 is a library of functions to support regular expressions whose syntax -and semantics are as close as possible to those of the Perl 5 language. - -Releases 10.00 and above of PCRE2 are distributed under the terms of the "BSD" -licence, as specified below, with one exemption for certain binary -redistributions. The documentation for PCRE2, supplied in the "doc" directory, -is distributed under the same terms as the software itself. The data in the -testdata directory is not copyrighted and is in the public domain. - -The basic library functions are written in C and are freestanding. Also -included in the distribution is a just-in-time compiler that can be used to -optimize pattern matching. This is an optional feature that can be omitted when -the library is built. - - -THE BASIC LIBRARY FUNCTIONS ---------------------------- - -Written by: Philip Hazel -Email local part: Philip.Hazel -Email domain: gmail.com - -Retired from University of Cambridge Computing Service, -Cambridge, England. - -Copyright (c) 1997-2022 University of Cambridge -All rights reserved. - - -PCRE2 JUST-IN-TIME COMPILATION SUPPORT --------------------------------------- - -Written by: Zoltan Herczeg -Email local part: hzmester -Email domain: freemail.hu - -Copyright(c) 2010-2022 Zoltan Herczeg -All rights reserved. - - -STACK-LESS JUST-IN-TIME COMPILER --------------------------------- - -Written by: Zoltan Herczeg -Email local part: hzmester -Email domain: freemail.hu - -Copyright(c) 2009-2022 Zoltan Herczeg -All rights reserved. - - -THE "BSD" LICENCE ------------------ - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notices, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright - notices, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - * Neither the name of the University of Cambridge nor the names of any - contributors may be used to endorse or promote products derived from this - software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 OWNER 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. - - -EXEMPTION FOR BINARY LIBRARY-LIKE PACKAGES ------------------------------------------- - -The second condition in the BSD licence (covering binary redistributions) does -not apply all the way down a chain of software. If binary package A includes -PCRE2, it must respect the condition, but if package B is software that -includes package A, the condition is not imposed on package B unless it uses -PCRE2 independently. - -End diff --git a/modules/regex/pcre2/patches/sljit-macos11-conditional.patch b/modules/regex/pcre2/patches/sljit-macos11-conditional.patch deleted file mode 100644 index def1207..0000000 --- a/modules/regex/pcre2/patches/sljit-macos11-conditional.patch +++ /dev/null @@ -1,31 +0,0 @@ -From de8fc816bc6698ab97316ed954e133e7e5098262 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Carlo=20Marcelo=20Arenas=20Bel=C3=B3n?= -Date: Thu, 21 Apr 2022 21:01:12 -0700 -Subject: [PATCH] macos: somehow allow building with a target below 11.0 - -While building for macOS older than 11 in Apple Silicon makes no -sense, some build systems lack the flexibility to set a target per -architecture while aiming to support multi architecture binaries. - -Allow an option in those cases by using the slower runtime checks -if the toolchain allows it. - -Fixes: PCRE2Project/pcre2#109 ---- - sljit_src/sljitExecAllocator.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/sljit_src/sljitExecAllocator.c b/sljit_src/sljitExecAllocator.c -index 92d940dd..6359848c 100644 ---- a/sljit_src/sljitExecAllocator.c -+++ b/sljit_src/sljitExecAllocator.c -@@ -152,6 +152,9 @@ static SLJIT_INLINE void apple_update_wx_flags(sljit_s32 enable_exec) - { - #if MAC_OS_X_VERSION_MIN_REQUIRED >= 110000 - pthread_jit_write_protect_np(enable_exec); -+#elif defined(__clang__) -+ if (__builtin_available(macOS 11.0, *)) -+ pthread_jit_write_protect_np(enable_exec); - #else - #error "Must target Big Sur or newer" - #endif /* BigSur */ diff --git a/modules/regex/pcre2/src/config.h b/modules/regex/pcre2/src/config.h deleted file mode 100644 index 5548d18..0000000 --- a/modules/regex/pcre2/src/config.h +++ /dev/null @@ -1,457 +0,0 @@ -/* src/config.h. Generated from config.h.in by configure. */ -/* 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. */ -/* #undef HAVE_BCOPY */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_BZLIB_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_DIRENT_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_DLFCN_H */ - -/* 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. */ -/* #undef HAVE_INTTYPES_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LIMITS_H */ - -/* Define to 1 if you have the `memfd_create' function. */ -/* #undef HAVE_MEMFD_CREATE */ - -/* Define to 1 if you have the `memmove' function. */ -/* #undef HAVE_MEMMOVE */ - -/* 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. */ -/* #undef HAVE_PTHREAD */ - -/* 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. */ -/* #undef HAVE_REALPATH */ - -/* Define to 1 if you have the `secure_getenv' function. */ -/* #undef HAVE_SECURE_GETENV */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_STDINT_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_STDIO_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_STDLIB_H */ - -/* Define to 1 if you have the `strerror' function. */ -/* #undef HAVE_STRERROR */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_STRINGS_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_STRING_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_STAT_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_TYPES_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_WAIT_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_UNISTD_H */ - -/* Define to 1 if the compiler supports simple visibility declarations. */ -/* #undef HAVE_VISIBILITY */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_WCHAR_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_WINDOWS_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_ZLIB_H */ - -/* 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). */ -#ifndef HEAP_LIMIT -#define HEAP_LIMIT 20000000 -#endif - -/* 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. */ -#ifndef LINK_SIZE -#define LINK_SIZE 2 -#endif - -/* Define to the sub-directory where libtool stores uninstalled libraries. */ -/* This is ignored unless you are using libtool. */ -#ifndef LT_OBJDIR -#define LT_OBJDIR ".libs/" -#endif - -/* 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 for ever to determine that they do not match. The default is set very - large so that it does not accidentally catch legitimate cases. */ -#ifndef MATCH_LIMIT -#define MATCH_LIMIT 10000000 -#endif - -/* 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. */ -#ifndef MATCH_LIMIT_DEPTH -#define MATCH_LIMIT_DEPTH MATCH_LIMIT -#endif - -/* 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. */ -#ifndef MAX_NAME_COUNT -#define MAX_NAME_COUNT 10000 -#endif - -/* 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. */ -#ifndef MAX_NAME_SIZE -#define MAX_NAME_SIZE 32 -#endif - -/* 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). */ -#ifndef NEWLINE_DEFAULT -#define NEWLINE_DEFAULT 2 -#endif - -/* 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.42" - -/* 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.42" - -/* The value of PARENS_NEST_LIMIT specifies the maximum depth of nested - parentheses (of any kind) in a pattern. This limits the amount of system - stack that is used while compiling a pattern. */ -#ifndef PARENS_NEST_LIMIT -#define PARENS_NEST_LIMIT 250 -#endif - -/* The value of 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. */ -#ifndef PCRE2GREP_BUFSIZE -#define PCRE2GREP_BUFSIZE 20480 -#endif - -/* 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. */ -#ifndef PCRE2GREP_MAX_BUFSIZE -#define PCRE2GREP_MAX_BUFSIZE 1048576 -#endif - -/* Define to any value to include debugging code. */ -/* #undef PCRE2_DEBUG */ - -/* 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 - "extern" is used for a C compiler and "extern C" for a C++ compiler. - This macro apears at the start of every exported function that is part - of the external API. It does not appear on functions that are "external" - in the C sense, but which are internal to the library. */ -/* #undef 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 C90 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. */ -/* #undef STDC_HEADERS */ - -/* 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. */ -/* #undef SUPPORT_LIBBZ2 */ - -/* 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. */ -/* #undef SUPPORT_LIBZ */ - -/* 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. */ -/* #undef SUPPORT_PCRE2_8 */ - -/* 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 3, Interix. */ -#ifndef _ALL_SOURCE -# define _ALL_SOURCE 1 -#endif -/* Enable general extensions on macOS. */ -#ifndef _DARWIN_C_SOURCE -# define _DARWIN_C_SOURCE 1 -#endif -/* Enable general extensions on Solaris. */ -#ifndef __EXTENSIONS__ -# define __EXTENSIONS__ 1 -#endif -/* Enable GNU extensions on systems that have them. */ -#ifndef _GNU_SOURCE -# define _GNU_SOURCE 1 -#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 -# define _HPUX_ALT_XOPEN_SOCKET_API 1 -#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 -# define _NETBSD_SOURCE 1 -#endif -/* Enable OpenBSD compatibility extensions on NetBSD. - Oddly enough, this does nothing on OpenBSD. */ -#ifndef _OPENBSD_SOURCE -# define _OPENBSD_SOURCE 1 -#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 -# define _POSIX_PTHREAD_SEMANTICS 1 -#endif -/* Enable extensions specified by ISO/IEC TS 18661-5:2014. */ -#ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__ -# define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1 -#endif -/* Enable extensions specified by ISO/IEC TS 18661-1:2014. */ -#ifndef __STDC_WANT_IEC_60559_BFP_EXT__ -# define __STDC_WANT_IEC_60559_BFP_EXT__ 1 -#endif -/* Enable extensions specified by ISO/IEC TS 18661-2:2015. */ -#ifndef __STDC_WANT_IEC_60559_DFP_EXT__ -# define __STDC_WANT_IEC_60559_DFP_EXT__ 1 -#endif -/* Enable extensions specified by ISO/IEC TS 18661-4:2015. */ -#ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__ -# define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1 -#endif -/* Enable extensions specified by ISO/IEC TS 18661-3:2015. */ -#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__ -# define __STDC_WANT_IEC_60559_TYPES_EXT__ 1 -#endif -/* Enable extensions specified by ISO/IEC TR 24731-2:2010. */ -#ifndef __STDC_WANT_LIB_EXT2__ -# define __STDC_WANT_LIB_EXT2__ 1 -#endif -/* Enable extensions specified by ISO/IEC 24747:2009. */ -#ifndef __STDC_WANT_MATH_SPEC_FUNCS__ -# define __STDC_WANT_MATH_SPEC_FUNCS__ 1 -#endif -/* Enable extensions on HP NonStop. */ -#ifndef _TANDEM_SOURCE -# define _TANDEM_SOURCE 1 -#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 */ -#define VERSION "10.42" - -/* Number of bits in a file offset, on hosts where this is settable. */ -/* #undef _FILE_OFFSET_BITS */ - -/* Define for large files, on AIX-style hosts. */ -/* #undef _LARGE_FILES */ - -/* 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 to `unsigned int' if does not define. */ -/* #undef size_t */ diff --git a/modules/regex/pcre2/src/pcre2.h b/modules/regex/pcre2/src/pcre2.h deleted file mode 100644 index 1cbecd0..0000000 --- a/modules/regex/pcre2/src/pcre2.h +++ /dev/null @@ -1,993 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* This is the public header file for the PCRE library, second API, to be -#included by applications that call PCRE2 functions. - - Copyright (c) 2016-2021 University of Cambridge - ------------------------------------------------------------------------------ -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 OWNER 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. ------------------------------------------------------------------------------ -*/ - -#ifndef PCRE2_H_IDEMPOTENT_GUARD -#define PCRE2_H_IDEMPOTENT_GUARD - -/* The current PCRE version information. */ - -#define PCRE2_MAJOR 10 -#define PCRE2_MINOR 42 -#define PCRE2_PRERELEASE -#define PCRE2_DATE 2022-12-11 - -/* 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 -export setting is defined in pcre2_internal.h, which includes this file. So we -don't change existing definitions of PCRE2_EXP_DECL. */ - -#if defined(_WIN32) && !defined(PCRE2_STATIC) -# ifndef PCRE2_EXP_DECL -# define PCRE2_EXP_DECL extern __declspec(dllimport) -# endif -#endif - -/* By default, we use the standard "extern" declarations. */ - -#ifndef PCRE2_EXP_DECL -# ifdef __cplusplus -# define PCRE2_EXP_DECL extern "C" -# else -# define PCRE2_EXP_DECL extern -# endif -#endif - -/* When compiling with the MSVC compiler, it is sometimes necessary to include -a "calling convention" before exported function names. (This is secondhand -information; I know nothing about MSVC myself). For example, something like - - void __cdecl function(....) - -might be needed. In order so make this easy, all the exported functions have -PCRE2_CALL_CONVENTION just before their names. It is rarely needed; if not -set, we ensure here that it has no effect. */ - -#ifndef PCRE2_CALL_CONVENTION -#define PCRE2_CALL_CONVENTION -#endif - -/* Have to include limits.h, stdlib.h, and inttypes.h to ensure that size_t and -uint8_t, UCHAR_MAX, etc are defined. Some systems that do have inttypes.h do -not have stdint.h, which is why we use inttypes.h, which according to the C -standard is a superset of stdint.h. If inttypes.h is not available the build -will break and the relevant values must be provided by some other means. */ - -#include -#include -#include - -/* Allow for C++ users compiling this directly. */ - -#ifdef __cplusplus -extern "C" { -#endif - -/* The following option bits can be passed to pcre2_compile(), pcre2_match(), -or pcre2_dfa_match(). PCRE2_NO_UTF_CHECK affects only the function to which it -is passed. Put these bits at the most significant end of the options word so -others can be added next to them */ - -#define PCRE2_ANCHORED 0x80000000u -#define PCRE2_NO_UTF_CHECK 0x40000000u -#define PCRE2_ENDANCHORED 0x20000000u - -/* The following option bits can be passed only to pcre2_compile(). However, -they may affect compilation, JIT compilation, and/or interpretive execution. -The following tags indicate which: - -C alters what is compiled by pcre2_compile() -J alters what is compiled by pcre2_jit_compile() -M is inspected during pcre2_match() execution -D is inspected during pcre2_dfa_match() execution -*/ - -#define PCRE2_ALLOW_EMPTY_CLASS 0x00000001u /* C */ -#define PCRE2_ALT_BSUX 0x00000002u /* C */ -#define PCRE2_AUTO_CALLOUT 0x00000004u /* C */ -#define PCRE2_CASELESS 0x00000008u /* C */ -#define PCRE2_DOLLAR_ENDONLY 0x00000010u /* J M D */ -#define PCRE2_DOTALL 0x00000020u /* C */ -#define PCRE2_DUPNAMES 0x00000040u /* C */ -#define PCRE2_EXTENDED 0x00000080u /* C */ -#define PCRE2_FIRSTLINE 0x00000100u /* J M D */ -#define PCRE2_MATCH_UNSET_BACKREF 0x00000200u /* C J M */ -#define PCRE2_MULTILINE 0x00000400u /* C */ -#define PCRE2_NEVER_UCP 0x00000800u /* C */ -#define PCRE2_NEVER_UTF 0x00001000u /* C */ -#define PCRE2_NO_AUTO_CAPTURE 0x00002000u /* C */ -#define PCRE2_NO_AUTO_POSSESS 0x00004000u /* C */ -#define PCRE2_NO_DOTSTAR_ANCHOR 0x00008000u /* C */ -#define PCRE2_NO_START_OPTIMIZE 0x00010000u /* J M D */ -#define PCRE2_UCP 0x00020000u /* C J M D */ -#define PCRE2_UNGREEDY 0x00040000u /* C */ -#define PCRE2_UTF 0x00080000u /* C J M D */ -#define PCRE2_NEVER_BACKSLASH_C 0x00100000u /* C */ -#define PCRE2_ALT_CIRCUMFLEX 0x00200000u /* J M D */ -#define PCRE2_ALT_VERBNAMES 0x00400000u /* C */ -#define PCRE2_USE_OFFSET_LIMIT 0x00800000u /* J M D */ -#define PCRE2_EXTENDED_MORE 0x01000000u /* C */ -#define PCRE2_LITERAL 0x02000000u /* C */ -#define PCRE2_MATCH_INVALID_UTF 0x04000000u /* J M D */ - -/* An additional compile options word is available in the compile context. */ - -#define PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES 0x00000001u /* C */ -#define PCRE2_EXTRA_BAD_ESCAPE_IS_LITERAL 0x00000002u /* C */ -#define PCRE2_EXTRA_MATCH_WORD 0x00000004u /* C */ -#define PCRE2_EXTRA_MATCH_LINE 0x00000008u /* C */ -#define PCRE2_EXTRA_ESCAPED_CR_IS_LF 0x00000010u /* C */ -#define PCRE2_EXTRA_ALT_BSUX 0x00000020u /* C */ -#define PCRE2_EXTRA_ALLOW_LOOKAROUND_BSK 0x00000040u /* C */ - -/* These are for pcre2_jit_compile(). */ - -#define PCRE2_JIT_COMPLETE 0x00000001u /* For full matching */ -#define PCRE2_JIT_PARTIAL_SOFT 0x00000002u -#define PCRE2_JIT_PARTIAL_HARD 0x00000004u -#define PCRE2_JIT_INVALID_UTF 0x00000100u - -/* These are for pcre2_match(), pcre2_dfa_match(), pcre2_jit_match(), and -pcre2_substitute(). Some are allowed only for one of the functions, and in -these cases it is noted below. Note that PCRE2_ANCHORED, PCRE2_ENDANCHORED and -PCRE2_NO_UTF_CHECK can also be passed to these functions (though -pcre2_jit_match() ignores the latter since it bypasses all sanity checks). */ - -#define PCRE2_NOTBOL 0x00000001u -#define PCRE2_NOTEOL 0x00000002u -#define PCRE2_NOTEMPTY 0x00000004u /* ) These two must be kept */ -#define PCRE2_NOTEMPTY_ATSTART 0x00000008u /* ) adjacent to each other. */ -#define PCRE2_PARTIAL_SOFT 0x00000010u -#define PCRE2_PARTIAL_HARD 0x00000020u -#define PCRE2_DFA_RESTART 0x00000040u /* pcre2_dfa_match() only */ -#define PCRE2_DFA_SHORTEST 0x00000080u /* pcre2_dfa_match() only */ -#define PCRE2_SUBSTITUTE_GLOBAL 0x00000100u /* pcre2_substitute() only */ -#define PCRE2_SUBSTITUTE_EXTENDED 0x00000200u /* pcre2_substitute() only */ -#define PCRE2_SUBSTITUTE_UNSET_EMPTY 0x00000400u /* pcre2_substitute() only */ -#define PCRE2_SUBSTITUTE_UNKNOWN_UNSET 0x00000800u /* pcre2_substitute() only */ -#define PCRE2_SUBSTITUTE_OVERFLOW_LENGTH 0x00001000u /* pcre2_substitute() only */ -#define PCRE2_NO_JIT 0x00002000u /* Not for pcre2_dfa_match() */ -#define PCRE2_COPY_MATCHED_SUBJECT 0x00004000u -#define PCRE2_SUBSTITUTE_LITERAL 0x00008000u /* pcre2_substitute() only */ -#define PCRE2_SUBSTITUTE_MATCHED 0x00010000u /* pcre2_substitute() only */ -#define PCRE2_SUBSTITUTE_REPLACEMENT_ONLY 0x00020000u /* pcre2_substitute() only */ - -/* Options for pcre2_pattern_convert(). */ - -#define PCRE2_CONVERT_UTF 0x00000001u -#define PCRE2_CONVERT_NO_UTF_CHECK 0x00000002u -#define PCRE2_CONVERT_POSIX_BASIC 0x00000004u -#define PCRE2_CONVERT_POSIX_EXTENDED 0x00000008u -#define PCRE2_CONVERT_GLOB 0x00000010u -#define PCRE2_CONVERT_GLOB_NO_WILD_SEPARATOR 0x00000030u -#define PCRE2_CONVERT_GLOB_NO_STARSTAR 0x00000050u - -/* Newline and \R settings, for use in compile contexts. The newline values -must be kept in step with values set in config.h and both sets must all be -greater than zero. */ - -#define PCRE2_NEWLINE_CR 1 -#define PCRE2_NEWLINE_LF 2 -#define PCRE2_NEWLINE_CRLF 3 -#define PCRE2_NEWLINE_ANY 4 -#define PCRE2_NEWLINE_ANYCRLF 5 -#define PCRE2_NEWLINE_NUL 6 - -#define PCRE2_BSR_UNICODE 1 -#define PCRE2_BSR_ANYCRLF 2 - -/* Error codes for pcre2_compile(). Some of these are also used by -pcre2_pattern_convert(). */ - -#define PCRE2_ERROR_END_BACKSLASH 101 -#define PCRE2_ERROR_END_BACKSLASH_C 102 -#define PCRE2_ERROR_UNKNOWN_ESCAPE 103 -#define PCRE2_ERROR_QUANTIFIER_OUT_OF_ORDER 104 -#define PCRE2_ERROR_QUANTIFIER_TOO_BIG 105 -#define PCRE2_ERROR_MISSING_SQUARE_BRACKET 106 -#define PCRE2_ERROR_ESCAPE_INVALID_IN_CLASS 107 -#define PCRE2_ERROR_CLASS_RANGE_ORDER 108 -#define PCRE2_ERROR_QUANTIFIER_INVALID 109 -#define PCRE2_ERROR_INTERNAL_UNEXPECTED_REPEAT 110 -#define PCRE2_ERROR_INVALID_AFTER_PARENS_QUERY 111 -#define PCRE2_ERROR_POSIX_CLASS_NOT_IN_CLASS 112 -#define PCRE2_ERROR_POSIX_NO_SUPPORT_COLLATING 113 -#define PCRE2_ERROR_MISSING_CLOSING_PARENTHESIS 114 -#define PCRE2_ERROR_BAD_SUBPATTERN_REFERENCE 115 -#define PCRE2_ERROR_NULL_PATTERN 116 -#define PCRE2_ERROR_BAD_OPTIONS 117 -#define PCRE2_ERROR_MISSING_COMMENT_CLOSING 118 -#define PCRE2_ERROR_PARENTHESES_NEST_TOO_DEEP 119 -#define PCRE2_ERROR_PATTERN_TOO_LARGE 120 -#define PCRE2_ERROR_HEAP_FAILED 121 -#define PCRE2_ERROR_UNMATCHED_CLOSING_PARENTHESIS 122 -#define PCRE2_ERROR_INTERNAL_CODE_OVERFLOW 123 -#define PCRE2_ERROR_MISSING_CONDITION_CLOSING 124 -#define PCRE2_ERROR_LOOKBEHIND_NOT_FIXED_LENGTH 125 -#define PCRE2_ERROR_ZERO_RELATIVE_REFERENCE 126 -#define PCRE2_ERROR_TOO_MANY_CONDITION_BRANCHES 127 -#define PCRE2_ERROR_CONDITION_ASSERTION_EXPECTED 128 -#define PCRE2_ERROR_BAD_RELATIVE_REFERENCE 129 -#define PCRE2_ERROR_UNKNOWN_POSIX_CLASS 130 -#define PCRE2_ERROR_INTERNAL_STUDY_ERROR 131 -#define PCRE2_ERROR_UNICODE_NOT_SUPPORTED 132 -#define PCRE2_ERROR_PARENTHESES_STACK_CHECK 133 -#define PCRE2_ERROR_CODE_POINT_TOO_BIG 134 -#define PCRE2_ERROR_LOOKBEHIND_TOO_COMPLICATED 135 -#define PCRE2_ERROR_LOOKBEHIND_INVALID_BACKSLASH_C 136 -#define PCRE2_ERROR_UNSUPPORTED_ESCAPE_SEQUENCE 137 -#define PCRE2_ERROR_CALLOUT_NUMBER_TOO_BIG 138 -#define PCRE2_ERROR_MISSING_CALLOUT_CLOSING 139 -#define PCRE2_ERROR_ESCAPE_INVALID_IN_VERB 140 -#define PCRE2_ERROR_UNRECOGNIZED_AFTER_QUERY_P 141 -#define PCRE2_ERROR_MISSING_NAME_TERMINATOR 142 -#define PCRE2_ERROR_DUPLICATE_SUBPATTERN_NAME 143 -#define PCRE2_ERROR_INVALID_SUBPATTERN_NAME 144 -#define PCRE2_ERROR_UNICODE_PROPERTIES_UNAVAILABLE 145 -#define PCRE2_ERROR_MALFORMED_UNICODE_PROPERTY 146 -#define PCRE2_ERROR_UNKNOWN_UNICODE_PROPERTY 147 -#define PCRE2_ERROR_SUBPATTERN_NAME_TOO_LONG 148 -#define PCRE2_ERROR_TOO_MANY_NAMED_SUBPATTERNS 149 -#define PCRE2_ERROR_CLASS_INVALID_RANGE 150 -#define PCRE2_ERROR_OCTAL_BYTE_TOO_BIG 151 -#define PCRE2_ERROR_INTERNAL_OVERRAN_WORKSPACE 152 -#define PCRE2_ERROR_INTERNAL_MISSING_SUBPATTERN 153 -#define PCRE2_ERROR_DEFINE_TOO_MANY_BRANCHES 154 -#define PCRE2_ERROR_BACKSLASH_O_MISSING_BRACE 155 -#define PCRE2_ERROR_INTERNAL_UNKNOWN_NEWLINE 156 -#define PCRE2_ERROR_BACKSLASH_G_SYNTAX 157 -#define PCRE2_ERROR_PARENS_QUERY_R_MISSING_CLOSING 158 -/* Error 159 is obsolete and should now never occur */ -#define PCRE2_ERROR_VERB_ARGUMENT_NOT_ALLOWED 159 -#define PCRE2_ERROR_VERB_UNKNOWN 160 -#define PCRE2_ERROR_SUBPATTERN_NUMBER_TOO_BIG 161 -#define PCRE2_ERROR_SUBPATTERN_NAME_EXPECTED 162 -#define PCRE2_ERROR_INTERNAL_PARSED_OVERFLOW 163 -#define PCRE2_ERROR_INVALID_OCTAL 164 -#define PCRE2_ERROR_SUBPATTERN_NAMES_MISMATCH 165 -#define PCRE2_ERROR_MARK_MISSING_ARGUMENT 166 -#define PCRE2_ERROR_INVALID_HEXADECIMAL 167 -#define PCRE2_ERROR_BACKSLASH_C_SYNTAX 168 -#define PCRE2_ERROR_BACKSLASH_K_SYNTAX 169 -#define PCRE2_ERROR_INTERNAL_BAD_CODE_LOOKBEHINDS 170 -#define PCRE2_ERROR_BACKSLASH_N_IN_CLASS 171 -#define PCRE2_ERROR_CALLOUT_STRING_TOO_LONG 172 -#define PCRE2_ERROR_UNICODE_DISALLOWED_CODE_POINT 173 -#define PCRE2_ERROR_UTF_IS_DISABLED 174 -#define PCRE2_ERROR_UCP_IS_DISABLED 175 -#define PCRE2_ERROR_VERB_NAME_TOO_LONG 176 -#define PCRE2_ERROR_BACKSLASH_U_CODE_POINT_TOO_BIG 177 -#define PCRE2_ERROR_MISSING_OCTAL_OR_HEX_DIGITS 178 -#define PCRE2_ERROR_VERSION_CONDITION_SYNTAX 179 -#define PCRE2_ERROR_INTERNAL_BAD_CODE_AUTO_POSSESS 180 -#define PCRE2_ERROR_CALLOUT_NO_STRING_DELIMITER 181 -#define PCRE2_ERROR_CALLOUT_BAD_STRING_DELIMITER 182 -#define PCRE2_ERROR_BACKSLASH_C_CALLER_DISABLED 183 -#define PCRE2_ERROR_QUERY_BARJX_NEST_TOO_DEEP 184 -#define PCRE2_ERROR_BACKSLASH_C_LIBRARY_DISABLED 185 -#define PCRE2_ERROR_PATTERN_TOO_COMPLICATED 186 -#define PCRE2_ERROR_LOOKBEHIND_TOO_LONG 187 -#define PCRE2_ERROR_PATTERN_STRING_TOO_LONG 188 -#define PCRE2_ERROR_INTERNAL_BAD_CODE 189 -#define PCRE2_ERROR_INTERNAL_BAD_CODE_IN_SKIP 190 -#define PCRE2_ERROR_NO_SURROGATES_IN_UTF16 191 -#define PCRE2_ERROR_BAD_LITERAL_OPTIONS 192 -#define PCRE2_ERROR_SUPPORTED_ONLY_IN_UNICODE 193 -#define PCRE2_ERROR_INVALID_HYPHEN_IN_OPTIONS 194 -#define PCRE2_ERROR_ALPHA_ASSERTION_UNKNOWN 195 -#define PCRE2_ERROR_SCRIPT_RUN_NOT_AVAILABLE 196 -#define PCRE2_ERROR_TOO_MANY_CAPTURES 197 -#define PCRE2_ERROR_CONDITION_ATOMIC_ASSERTION_EXPECTED 198 -#define PCRE2_ERROR_BACKSLASH_K_IN_LOOKAROUND 199 - - -/* "Expected" matching error codes: no match and partial match. */ - -#define PCRE2_ERROR_NOMATCH (-1) -#define PCRE2_ERROR_PARTIAL (-2) - -/* Error codes for UTF-8 validity checks */ - -#define PCRE2_ERROR_UTF8_ERR1 (-3) -#define PCRE2_ERROR_UTF8_ERR2 (-4) -#define PCRE2_ERROR_UTF8_ERR3 (-5) -#define PCRE2_ERROR_UTF8_ERR4 (-6) -#define PCRE2_ERROR_UTF8_ERR5 (-7) -#define PCRE2_ERROR_UTF8_ERR6 (-8) -#define PCRE2_ERROR_UTF8_ERR7 (-9) -#define PCRE2_ERROR_UTF8_ERR8 (-10) -#define PCRE2_ERROR_UTF8_ERR9 (-11) -#define PCRE2_ERROR_UTF8_ERR10 (-12) -#define PCRE2_ERROR_UTF8_ERR11 (-13) -#define PCRE2_ERROR_UTF8_ERR12 (-14) -#define PCRE2_ERROR_UTF8_ERR13 (-15) -#define PCRE2_ERROR_UTF8_ERR14 (-16) -#define PCRE2_ERROR_UTF8_ERR15 (-17) -#define PCRE2_ERROR_UTF8_ERR16 (-18) -#define PCRE2_ERROR_UTF8_ERR17 (-19) -#define PCRE2_ERROR_UTF8_ERR18 (-20) -#define PCRE2_ERROR_UTF8_ERR19 (-21) -#define PCRE2_ERROR_UTF8_ERR20 (-22) -#define PCRE2_ERROR_UTF8_ERR21 (-23) - -/* Error codes for UTF-16 validity checks */ - -#define PCRE2_ERROR_UTF16_ERR1 (-24) -#define PCRE2_ERROR_UTF16_ERR2 (-25) -#define PCRE2_ERROR_UTF16_ERR3 (-26) - -/* Error codes for UTF-32 validity checks */ - -#define PCRE2_ERROR_UTF32_ERR1 (-27) -#define PCRE2_ERROR_UTF32_ERR2 (-28) - -/* Miscellaneous error codes for pcre2[_dfa]_match(), substring extraction -functions, context functions, and serializing functions. They are in numerical -order. Originally they were in alphabetical order too, but now that PCRE2 is -released, the numbers must not be changed. */ - -#define PCRE2_ERROR_BADDATA (-29) -#define PCRE2_ERROR_MIXEDTABLES (-30) /* Name was changed */ -#define PCRE2_ERROR_BADMAGIC (-31) -#define PCRE2_ERROR_BADMODE (-32) -#define PCRE2_ERROR_BADOFFSET (-33) -#define PCRE2_ERROR_BADOPTION (-34) -#define PCRE2_ERROR_BADREPLACEMENT (-35) -#define PCRE2_ERROR_BADUTFOFFSET (-36) -#define PCRE2_ERROR_CALLOUT (-37) /* Never used by PCRE2 itself */ -#define PCRE2_ERROR_DFA_BADRESTART (-38) -#define PCRE2_ERROR_DFA_RECURSE (-39) -#define PCRE2_ERROR_DFA_UCOND (-40) -#define PCRE2_ERROR_DFA_UFUNC (-41) -#define PCRE2_ERROR_DFA_UITEM (-42) -#define PCRE2_ERROR_DFA_WSSIZE (-43) -#define PCRE2_ERROR_INTERNAL (-44) -#define PCRE2_ERROR_JIT_BADOPTION (-45) -#define PCRE2_ERROR_JIT_STACKLIMIT (-46) -#define PCRE2_ERROR_MATCHLIMIT (-47) -#define PCRE2_ERROR_NOMEMORY (-48) -#define PCRE2_ERROR_NOSUBSTRING (-49) -#define PCRE2_ERROR_NOUNIQUESUBSTRING (-50) -#define PCRE2_ERROR_NULL (-51) -#define PCRE2_ERROR_RECURSELOOP (-52) -#define PCRE2_ERROR_DEPTHLIMIT (-53) -#define PCRE2_ERROR_RECURSIONLIMIT (-53) /* Obsolete synonym */ -#define PCRE2_ERROR_UNAVAILABLE (-54) -#define PCRE2_ERROR_UNSET (-55) -#define PCRE2_ERROR_BADOFFSETLIMIT (-56) -#define PCRE2_ERROR_BADREPESCAPE (-57) -#define PCRE2_ERROR_REPMISSINGBRACE (-58) -#define PCRE2_ERROR_BADSUBSTITUTION (-59) -#define PCRE2_ERROR_BADSUBSPATTERN (-60) -#define PCRE2_ERROR_TOOMANYREPLACE (-61) -#define PCRE2_ERROR_BADSERIALIZEDDATA (-62) -#define PCRE2_ERROR_HEAPLIMIT (-63) -#define PCRE2_ERROR_CONVERT_SYNTAX (-64) -#define PCRE2_ERROR_INTERNAL_DUPMATCH (-65) -#define PCRE2_ERROR_DFA_UINVALID_UTF (-66) - - -/* Request types for pcre2_pattern_info() */ - -#define PCRE2_INFO_ALLOPTIONS 0 -#define PCRE2_INFO_ARGOPTIONS 1 -#define PCRE2_INFO_BACKREFMAX 2 -#define PCRE2_INFO_BSR 3 -#define PCRE2_INFO_CAPTURECOUNT 4 -#define PCRE2_INFO_FIRSTCODEUNIT 5 -#define PCRE2_INFO_FIRSTCODETYPE 6 -#define PCRE2_INFO_FIRSTBITMAP 7 -#define PCRE2_INFO_HASCRORLF 8 -#define PCRE2_INFO_JCHANGED 9 -#define PCRE2_INFO_JITSIZE 10 -#define PCRE2_INFO_LASTCODEUNIT 11 -#define PCRE2_INFO_LASTCODETYPE 12 -#define PCRE2_INFO_MATCHEMPTY 13 -#define PCRE2_INFO_MATCHLIMIT 14 -#define PCRE2_INFO_MAXLOOKBEHIND 15 -#define PCRE2_INFO_MINLENGTH 16 -#define PCRE2_INFO_NAMECOUNT 17 -#define PCRE2_INFO_NAMEENTRYSIZE 18 -#define PCRE2_INFO_NAMETABLE 19 -#define PCRE2_INFO_NEWLINE 20 -#define PCRE2_INFO_DEPTHLIMIT 21 -#define PCRE2_INFO_RECURSIONLIMIT 21 /* Obsolete synonym */ -#define PCRE2_INFO_SIZE 22 -#define PCRE2_INFO_HASBACKSLASHC 23 -#define PCRE2_INFO_FRAMESIZE 24 -#define PCRE2_INFO_HEAPLIMIT 25 -#define PCRE2_INFO_EXTRAOPTIONS 26 - -/* Request types for pcre2_config(). */ - -#define PCRE2_CONFIG_BSR 0 -#define PCRE2_CONFIG_JIT 1 -#define PCRE2_CONFIG_JITTARGET 2 -#define PCRE2_CONFIG_LINKSIZE 3 -#define PCRE2_CONFIG_MATCHLIMIT 4 -#define PCRE2_CONFIG_NEWLINE 5 -#define PCRE2_CONFIG_PARENSLIMIT 6 -#define PCRE2_CONFIG_DEPTHLIMIT 7 -#define PCRE2_CONFIG_RECURSIONLIMIT 7 /* Obsolete synonym */ -#define PCRE2_CONFIG_STACKRECURSE 8 /* Obsolete */ -#define PCRE2_CONFIG_UNICODE 9 -#define PCRE2_CONFIG_UNICODE_VERSION 10 -#define PCRE2_CONFIG_VERSION 11 -#define PCRE2_CONFIG_HEAPLIMIT 12 -#define PCRE2_CONFIG_NEVER_BACKSLASH_C 13 -#define PCRE2_CONFIG_COMPILED_WIDTHS 14 -#define PCRE2_CONFIG_TABLES_LENGTH 15 - - -/* Types for code units in patterns and subject strings. */ - -typedef uint8_t PCRE2_UCHAR8; -typedef uint16_t PCRE2_UCHAR16; -typedef uint32_t PCRE2_UCHAR32; - -typedef const PCRE2_UCHAR8 *PCRE2_SPTR8; -typedef const PCRE2_UCHAR16 *PCRE2_SPTR16; -typedef const PCRE2_UCHAR32 *PCRE2_SPTR32; - -/* The PCRE2_SIZE type is used for all string lengths and offsets in PCRE2, -including pattern offsets for errors and subject offsets after a match. We -define special values to indicate zero-terminated strings and unset offsets in -the offset vector (ovector). */ - -#define PCRE2_SIZE size_t -#define PCRE2_SIZE_MAX SIZE_MAX -#define PCRE2_ZERO_TERMINATED (~(PCRE2_SIZE)0) -#define PCRE2_UNSET (~(PCRE2_SIZE)0) - -/* Generic types for opaque structures and JIT callback functions. These -declarations are defined in a macro that is expanded for each width later. */ - -#define PCRE2_TYPES_LIST \ -struct pcre2_real_general_context; \ -typedef struct pcre2_real_general_context pcre2_general_context; \ -\ -struct pcre2_real_compile_context; \ -typedef struct pcre2_real_compile_context pcre2_compile_context; \ -\ -struct pcre2_real_match_context; \ -typedef struct pcre2_real_match_context pcre2_match_context; \ -\ -struct pcre2_real_convert_context; \ -typedef struct pcre2_real_convert_context pcre2_convert_context; \ -\ -struct pcre2_real_code; \ -typedef struct pcre2_real_code pcre2_code; \ -\ -struct pcre2_real_match_data; \ -typedef struct pcre2_real_match_data pcre2_match_data; \ -\ -struct pcre2_real_jit_stack; \ -typedef struct pcre2_real_jit_stack pcre2_jit_stack; \ -\ -typedef pcre2_jit_stack *(*pcre2_jit_callback)(void *); - - -/* The structures for passing out data via callout functions. We use structures -so that new fields can be added on the end in future versions, without changing -the API of the function, thereby allowing old clients to work without -modification. Define the generic versions in a macro; the width-specific -versions are generated from this macro below. */ - -/* Flags for the callout_flags field. These are cleared after a callout. */ - -#define PCRE2_CALLOUT_STARTMATCH 0x00000001u /* Set for each bumpalong */ -#define PCRE2_CALLOUT_BACKTRACK 0x00000002u /* Set after a backtrack */ - -#define PCRE2_STRUCTURE_LIST \ -typedef struct pcre2_callout_block { \ - uint32_t version; /* Identifies version of block */ \ - /* ------------------------ Version 0 ------------------------------- */ \ - uint32_t callout_number; /* Number compiled into pattern */ \ - uint32_t capture_top; /* Max current capture */ \ - uint32_t capture_last; /* Most recently closed capture */ \ - PCRE2_SIZE *offset_vector; /* The offset vector */ \ - PCRE2_SPTR mark; /* Pointer to current mark or NULL */ \ - PCRE2_SPTR subject; /* The subject being matched */ \ - PCRE2_SIZE subject_length; /* The length of the subject */ \ - PCRE2_SIZE start_match; /* Offset to start of this match attempt */ \ - PCRE2_SIZE current_position; /* Where we currently are in the subject */ \ - PCRE2_SIZE pattern_position; /* Offset to next item in the pattern */ \ - PCRE2_SIZE next_item_length; /* Length of next item in the pattern */ \ - /* ------------------- Added for Version 1 -------------------------- */ \ - PCRE2_SIZE callout_string_offset; /* Offset to string within pattern */ \ - PCRE2_SIZE callout_string_length; /* Length of string compiled into pattern */ \ - PCRE2_SPTR callout_string; /* String compiled into pattern */ \ - /* ------------------- Added for Version 2 -------------------------- */ \ - uint32_t callout_flags; /* See above for list */ \ - /* ------------------------------------------------------------------ */ \ -} pcre2_callout_block; \ -\ -typedef struct pcre2_callout_enumerate_block { \ - uint32_t version; /* Identifies version of block */ \ - /* ------------------------ Version 0 ------------------------------- */ \ - PCRE2_SIZE pattern_position; /* Offset to next item in the pattern */ \ - PCRE2_SIZE next_item_length; /* Length of next item in the pattern */ \ - uint32_t callout_number; /* Number compiled into pattern */ \ - PCRE2_SIZE callout_string_offset; /* Offset to string within pattern */ \ - PCRE2_SIZE callout_string_length; /* Length of string compiled into pattern */ \ - PCRE2_SPTR callout_string; /* String compiled into pattern */ \ - /* ------------------------------------------------------------------ */ \ -} pcre2_callout_enumerate_block; \ -\ -typedef struct pcre2_substitute_callout_block { \ - uint32_t version; /* Identifies version of block */ \ - /* ------------------------ Version 0 ------------------------------- */ \ - PCRE2_SPTR input; /* Pointer to input subject string */ \ - PCRE2_SPTR output; /* Pointer to output buffer */ \ - PCRE2_SIZE output_offsets[2]; /* Changed portion of the output */ \ - PCRE2_SIZE *ovector; /* Pointer to current ovector */ \ - uint32_t oveccount; /* Count of pairs set in ovector */ \ - uint32_t subscount; /* Substitution number */ \ - /* ------------------------------------------------------------------ */ \ -} pcre2_substitute_callout_block; - - -/* List the generic forms of all other functions in macros, which will be -expanded for each width below. Start with functions that give general -information. */ - -#define PCRE2_GENERAL_INFO_FUNCTIONS \ -PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION pcre2_config(uint32_t, void *); - - -/* Functions for manipulating contexts. */ - -#define PCRE2_GENERAL_CONTEXT_FUNCTIONS \ -PCRE2_EXP_DECL pcre2_general_context *PCRE2_CALL_CONVENTION \ - pcre2_general_context_copy(pcre2_general_context *); \ -PCRE2_EXP_DECL pcre2_general_context *PCRE2_CALL_CONVENTION \ - pcre2_general_context_create(void *(*)(PCRE2_SIZE, void *), \ - void (*)(void *, void *), void *); \ -PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \ - pcre2_general_context_free(pcre2_general_context *); - -#define PCRE2_COMPILE_CONTEXT_FUNCTIONS \ -PCRE2_EXP_DECL pcre2_compile_context *PCRE2_CALL_CONVENTION \ - pcre2_compile_context_copy(pcre2_compile_context *); \ -PCRE2_EXP_DECL pcre2_compile_context *PCRE2_CALL_CONVENTION \ - pcre2_compile_context_create(pcre2_general_context *);\ -PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \ - pcre2_compile_context_free(pcre2_compile_context *); \ -PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ - pcre2_set_bsr(pcre2_compile_context *, uint32_t); \ -PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ - pcre2_set_character_tables(pcre2_compile_context *, const uint8_t *); \ -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_newline(pcre2_compile_context *, uint32_t); \ -PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ - pcre2_set_parens_nest_limit(pcre2_compile_context *, uint32_t); \ -PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ - pcre2_set_compile_recursion_guard(pcre2_compile_context *, \ - int (*)(uint32_t, void *), void *); - -#define PCRE2_MATCH_CONTEXT_FUNCTIONS \ -PCRE2_EXP_DECL pcre2_match_context *PCRE2_CALL_CONVENTION \ - pcre2_match_context_copy(pcre2_match_context *); \ -PCRE2_EXP_DECL pcre2_match_context *PCRE2_CALL_CONVENTION \ - pcre2_match_context_create(pcre2_general_context *); \ -PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \ - pcre2_match_context_free(pcre2_match_context *); \ -PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ - pcre2_set_callout(pcre2_match_context *, \ - int (*)(pcre2_callout_block *, void *), void *); \ -PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ - pcre2_set_substitute_callout(pcre2_match_context *, \ - int (*)(pcre2_substitute_callout_block *, void *), void *); \ -PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ - pcre2_set_depth_limit(pcre2_match_context *, uint32_t); \ -PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ - pcre2_set_heap_limit(pcre2_match_context *, uint32_t); \ -PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ - pcre2_set_match_limit(pcre2_match_context *, uint32_t); \ -PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ - pcre2_set_offset_limit(pcre2_match_context *, PCRE2_SIZE); \ -PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ - pcre2_set_recursion_limit(pcre2_match_context *, uint32_t); \ -PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ - pcre2_set_recursion_memory_management(pcre2_match_context *, \ - void *(*)(PCRE2_SIZE, void *), void (*)(void *, void *), void *); - -#define PCRE2_CONVERT_CONTEXT_FUNCTIONS \ -PCRE2_EXP_DECL pcre2_convert_context *PCRE2_CALL_CONVENTION \ - pcre2_convert_context_copy(pcre2_convert_context *); \ -PCRE2_EXP_DECL pcre2_convert_context *PCRE2_CALL_CONVENTION \ - pcre2_convert_context_create(pcre2_general_context *); \ -PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \ - pcre2_convert_context_free(pcre2_convert_context *); \ -PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ - pcre2_set_glob_escape(pcre2_convert_context *, uint32_t); \ -PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ - pcre2_set_glob_separator(pcre2_convert_context *, uint32_t); - - -/* Functions concerned with compiling a pattern to PCRE internal code. */ - -#define PCRE2_COMPILE_FUNCTIONS \ -PCRE2_EXP_DECL pcre2_code *PCRE2_CALL_CONVENTION \ - pcre2_compile(PCRE2_SPTR, PCRE2_SIZE, uint32_t, int *, PCRE2_SIZE *, \ - pcre2_compile_context *); \ -PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \ - pcre2_code_free(pcre2_code *); \ -PCRE2_EXP_DECL pcre2_code *PCRE2_CALL_CONVENTION \ - pcre2_code_copy(const pcre2_code *); \ -PCRE2_EXP_DECL pcre2_code *PCRE2_CALL_CONVENTION \ - pcre2_code_copy_with_tables(const pcre2_code *); - - -/* Functions that give information about a compiled pattern. */ - -#define PCRE2_PATTERN_INFO_FUNCTIONS \ -PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ - pcre2_pattern_info(const pcre2_code *, uint32_t, void *); \ -PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ - pcre2_callout_enumerate(const pcre2_code *, \ - int (*)(pcre2_callout_enumerate_block *, void *), void *); - - -/* Functions for running a match and inspecting the result. */ - -#define PCRE2_MATCH_FUNCTIONS \ -PCRE2_EXP_DECL pcre2_match_data *PCRE2_CALL_CONVENTION \ - pcre2_match_data_create(uint32_t, pcre2_general_context *); \ -PCRE2_EXP_DECL pcre2_match_data *PCRE2_CALL_CONVENTION \ - pcre2_match_data_create_from_pattern(const pcre2_code *, \ - pcre2_general_context *); \ -PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ - pcre2_dfa_match(const pcre2_code *, PCRE2_SPTR, PCRE2_SIZE, PCRE2_SIZE, \ - uint32_t, pcre2_match_data *, pcre2_match_context *, int *, PCRE2_SIZE); \ -PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ - pcre2_match(const pcre2_code *, PCRE2_SPTR, PCRE2_SIZE, PCRE2_SIZE, \ - uint32_t, pcre2_match_data *, pcre2_match_context *); \ -PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \ - pcre2_match_data_free(pcre2_match_data *); \ -PCRE2_EXP_DECL PCRE2_SPTR PCRE2_CALL_CONVENTION \ - pcre2_get_mark(pcre2_match_data *); \ -PCRE2_EXP_DECL PCRE2_SIZE PCRE2_CALL_CONVENTION \ - pcre2_get_match_data_size(pcre2_match_data *); \ -PCRE2_EXP_DECL uint32_t PCRE2_CALL_CONVENTION \ - pcre2_get_ovector_count(pcre2_match_data *); \ -PCRE2_EXP_DECL PCRE2_SIZE *PCRE2_CALL_CONVENTION \ - pcre2_get_ovector_pointer(pcre2_match_data *); \ -PCRE2_EXP_DECL PCRE2_SIZE PCRE2_CALL_CONVENTION \ - pcre2_get_startchar(pcre2_match_data *); - - -/* Convenience functions for handling matched substrings. */ - -#define PCRE2_SUBSTRING_FUNCTIONS \ -PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ - pcre2_substring_copy_byname(pcre2_match_data *, PCRE2_SPTR, PCRE2_UCHAR *, \ - PCRE2_SIZE *); \ -PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ - pcre2_substring_copy_bynumber(pcre2_match_data *, uint32_t, PCRE2_UCHAR *, \ - PCRE2_SIZE *); \ -PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \ - pcre2_substring_free(PCRE2_UCHAR *); \ -PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ - pcre2_substring_get_byname(pcre2_match_data *, PCRE2_SPTR, PCRE2_UCHAR **, \ - PCRE2_SIZE *); \ -PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ - pcre2_substring_get_bynumber(pcre2_match_data *, uint32_t, PCRE2_UCHAR **, \ - PCRE2_SIZE *); \ -PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ - pcre2_substring_length_byname(pcre2_match_data *, PCRE2_SPTR, PCRE2_SIZE *); \ -PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ - pcre2_substring_length_bynumber(pcre2_match_data *, uint32_t, PCRE2_SIZE *); \ -PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ - pcre2_substring_nametable_scan(const pcre2_code *, PCRE2_SPTR, PCRE2_SPTR *, \ - PCRE2_SPTR *); \ -PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ - pcre2_substring_number_from_name(const pcre2_code *, PCRE2_SPTR); \ -PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \ - pcre2_substring_list_free(PCRE2_SPTR *); \ -PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ - pcre2_substring_list_get(pcre2_match_data *, PCRE2_UCHAR ***, PCRE2_SIZE **); - -/* Functions for serializing / deserializing compiled patterns. */ - -#define PCRE2_SERIALIZE_FUNCTIONS \ -PCRE2_EXP_DECL int32_t PCRE2_CALL_CONVENTION \ - pcre2_serialize_encode(const pcre2_code **, int32_t, uint8_t **, \ - PCRE2_SIZE *, pcre2_general_context *); \ -PCRE2_EXP_DECL int32_t PCRE2_CALL_CONVENTION \ - pcre2_serialize_decode(pcre2_code **, int32_t, const uint8_t *, \ - pcre2_general_context *); \ -PCRE2_EXP_DECL int32_t PCRE2_CALL_CONVENTION \ - pcre2_serialize_get_number_of_codes(const uint8_t *); \ -PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \ - pcre2_serialize_free(uint8_t *); - - -/* Convenience function for match + substitute. */ - -#define PCRE2_SUBSTITUTE_FUNCTION \ -PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ - pcre2_substitute(const pcre2_code *, PCRE2_SPTR, PCRE2_SIZE, PCRE2_SIZE, \ - uint32_t, pcre2_match_data *, pcre2_match_context *, PCRE2_SPTR, \ - PCRE2_SIZE, PCRE2_UCHAR *, PCRE2_SIZE *); - - -/* Functions for converting pattern source strings. */ - -#define PCRE2_CONVERT_FUNCTIONS \ -PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ - pcre2_pattern_convert(PCRE2_SPTR, PCRE2_SIZE, uint32_t, PCRE2_UCHAR **, \ - PCRE2_SIZE *, pcre2_convert_context *); \ -PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \ - pcre2_converted_pattern_free(PCRE2_UCHAR *); - - -/* Functions for JIT processing */ - -#define PCRE2_JIT_FUNCTIONS \ -PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ - pcre2_jit_compile(pcre2_code *, uint32_t); \ -PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ - pcre2_jit_match(const pcre2_code *, PCRE2_SPTR, PCRE2_SIZE, PCRE2_SIZE, \ - uint32_t, pcre2_match_data *, pcre2_match_context *); \ -PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \ - pcre2_jit_free_unused_memory(pcre2_general_context *); \ -PCRE2_EXP_DECL pcre2_jit_stack *PCRE2_CALL_CONVENTION \ - pcre2_jit_stack_create(PCRE2_SIZE, PCRE2_SIZE, pcre2_general_context *); \ -PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \ - pcre2_jit_stack_assign(pcre2_match_context *, pcre2_jit_callback, void *); \ -PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \ - pcre2_jit_stack_free(pcre2_jit_stack *); - - -/* Other miscellaneous functions. */ - -#define PCRE2_OTHER_FUNCTIONS \ -PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \ - pcre2_get_error_message(int, PCRE2_UCHAR *, PCRE2_SIZE); \ -PCRE2_EXP_DECL const uint8_t *PCRE2_CALL_CONVENTION \ - pcre2_maketables(pcre2_general_context *); \ -PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \ - pcre2_maketables_free(pcre2_general_context *, const uint8_t *); - -/* Define macros that generate width-specific names from generic versions. The -three-level macro scheme is necessary to get the macros expanded when we want -them to be. First we get the width from PCRE2_LOCAL_WIDTH, which is used for -generating three versions of everything below. After that, PCRE2_SUFFIX will be -re-defined to use PCRE2_CODE_UNIT_WIDTH, for use when macros such as -pcre2_compile are called by application code. */ - -#define PCRE2_JOIN(a,b) a ## b -#define PCRE2_GLUE(a,b) PCRE2_JOIN(a,b) -#define PCRE2_SUFFIX(a) PCRE2_GLUE(a,PCRE2_LOCAL_WIDTH) - - -/* Data types */ - -#define PCRE2_UCHAR PCRE2_SUFFIX(PCRE2_UCHAR) -#define PCRE2_SPTR PCRE2_SUFFIX(PCRE2_SPTR) - -#define pcre2_code PCRE2_SUFFIX(pcre2_code_) -#define pcre2_jit_callback PCRE2_SUFFIX(pcre2_jit_callback_) -#define pcre2_jit_stack PCRE2_SUFFIX(pcre2_jit_stack_) - -#define pcre2_real_code PCRE2_SUFFIX(pcre2_real_code_) -#define pcre2_real_general_context PCRE2_SUFFIX(pcre2_real_general_context_) -#define pcre2_real_compile_context PCRE2_SUFFIX(pcre2_real_compile_context_) -#define pcre2_real_convert_context PCRE2_SUFFIX(pcre2_real_convert_context_) -#define pcre2_real_match_context PCRE2_SUFFIX(pcre2_real_match_context_) -#define pcre2_real_jit_stack PCRE2_SUFFIX(pcre2_real_jit_stack_) -#define pcre2_real_match_data PCRE2_SUFFIX(pcre2_real_match_data_) - - -/* Data blocks */ - -#define pcre2_callout_block PCRE2_SUFFIX(pcre2_callout_block_) -#define pcre2_callout_enumerate_block PCRE2_SUFFIX(pcre2_callout_enumerate_block_) -#define pcre2_substitute_callout_block PCRE2_SUFFIX(pcre2_substitute_callout_block_) -#define pcre2_general_context PCRE2_SUFFIX(pcre2_general_context_) -#define pcre2_compile_context PCRE2_SUFFIX(pcre2_compile_context_) -#define pcre2_convert_context PCRE2_SUFFIX(pcre2_convert_context_) -#define pcre2_match_context PCRE2_SUFFIX(pcre2_match_context_) -#define pcre2_match_data PCRE2_SUFFIX(pcre2_match_data_) - - -/* Functions: the complete list in alphabetical order */ - -#define pcre2_callout_enumerate PCRE2_SUFFIX(pcre2_callout_enumerate_) -#define pcre2_code_copy PCRE2_SUFFIX(pcre2_code_copy_) -#define pcre2_code_copy_with_tables PCRE2_SUFFIX(pcre2_code_copy_with_tables_) -#define pcre2_code_free PCRE2_SUFFIX(pcre2_code_free_) -#define pcre2_compile PCRE2_SUFFIX(pcre2_compile_) -#define pcre2_compile_context_copy PCRE2_SUFFIX(pcre2_compile_context_copy_) -#define pcre2_compile_context_create PCRE2_SUFFIX(pcre2_compile_context_create_) -#define pcre2_compile_context_free PCRE2_SUFFIX(pcre2_compile_context_free_) -#define pcre2_config PCRE2_SUFFIX(pcre2_config_) -#define pcre2_convert_context_copy PCRE2_SUFFIX(pcre2_convert_context_copy_) -#define pcre2_convert_context_create PCRE2_SUFFIX(pcre2_convert_context_create_) -#define pcre2_convert_context_free PCRE2_SUFFIX(pcre2_convert_context_free_) -#define pcre2_converted_pattern_free PCRE2_SUFFIX(pcre2_converted_pattern_free_) -#define pcre2_dfa_match PCRE2_SUFFIX(pcre2_dfa_match_) -#define pcre2_general_context_copy PCRE2_SUFFIX(pcre2_general_context_copy_) -#define pcre2_general_context_create PCRE2_SUFFIX(pcre2_general_context_create_) -#define pcre2_general_context_free PCRE2_SUFFIX(pcre2_general_context_free_) -#define pcre2_get_error_message PCRE2_SUFFIX(pcre2_get_error_message_) -#define pcre2_get_mark PCRE2_SUFFIX(pcre2_get_mark_) -#define pcre2_get_match_data_size PCRE2_SUFFIX(pcre2_get_match_data_size_) -#define pcre2_get_ovector_pointer PCRE2_SUFFIX(pcre2_get_ovector_pointer_) -#define pcre2_get_ovector_count PCRE2_SUFFIX(pcre2_get_ovector_count_) -#define pcre2_get_startchar PCRE2_SUFFIX(pcre2_get_startchar_) -#define pcre2_jit_compile PCRE2_SUFFIX(pcre2_jit_compile_) -#define pcre2_jit_match PCRE2_SUFFIX(pcre2_jit_match_) -#define pcre2_jit_free_unused_memory PCRE2_SUFFIX(pcre2_jit_free_unused_memory_) -#define pcre2_jit_stack_assign PCRE2_SUFFIX(pcre2_jit_stack_assign_) -#define pcre2_jit_stack_create PCRE2_SUFFIX(pcre2_jit_stack_create_) -#define pcre2_jit_stack_free PCRE2_SUFFIX(pcre2_jit_stack_free_) -#define pcre2_maketables PCRE2_SUFFIX(pcre2_maketables_) -#define pcre2_maketables_free PCRE2_SUFFIX(pcre2_maketables_free_) -#define pcre2_match PCRE2_SUFFIX(pcre2_match_) -#define pcre2_match_context_copy PCRE2_SUFFIX(pcre2_match_context_copy_) -#define pcre2_match_context_create PCRE2_SUFFIX(pcre2_match_context_create_) -#define pcre2_match_context_free PCRE2_SUFFIX(pcre2_match_context_free_) -#define pcre2_match_data_create PCRE2_SUFFIX(pcre2_match_data_create_) -#define pcre2_match_data_create_from_pattern PCRE2_SUFFIX(pcre2_match_data_create_from_pattern_) -#define pcre2_match_data_free PCRE2_SUFFIX(pcre2_match_data_free_) -#define pcre2_pattern_convert PCRE2_SUFFIX(pcre2_pattern_convert_) -#define pcre2_pattern_info PCRE2_SUFFIX(pcre2_pattern_info_) -#define pcre2_serialize_decode PCRE2_SUFFIX(pcre2_serialize_decode_) -#define pcre2_serialize_encode PCRE2_SUFFIX(pcre2_serialize_encode_) -#define pcre2_serialize_free PCRE2_SUFFIX(pcre2_serialize_free_) -#define pcre2_serialize_get_number_of_codes PCRE2_SUFFIX(pcre2_serialize_get_number_of_codes_) -#define pcre2_set_bsr PCRE2_SUFFIX(pcre2_set_bsr_) -#define pcre2_set_callout PCRE2_SUFFIX(pcre2_set_callout_) -#define pcre2_set_character_tables PCRE2_SUFFIX(pcre2_set_character_tables_) -#define pcre2_set_compile_extra_options PCRE2_SUFFIX(pcre2_set_compile_extra_options_) -#define pcre2_set_compile_recursion_guard PCRE2_SUFFIX(pcre2_set_compile_recursion_guard_) -#define pcre2_set_depth_limit PCRE2_SUFFIX(pcre2_set_depth_limit_) -#define pcre2_set_glob_escape PCRE2_SUFFIX(pcre2_set_glob_escape_) -#define pcre2_set_glob_separator PCRE2_SUFFIX(pcre2_set_glob_separator_) -#define pcre2_set_heap_limit PCRE2_SUFFIX(pcre2_set_heap_limit_) -#define pcre2_set_match_limit PCRE2_SUFFIX(pcre2_set_match_limit_) -#define pcre2_set_max_pattern_length PCRE2_SUFFIX(pcre2_set_max_pattern_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_) -#define pcre2_set_substitute_callout PCRE2_SUFFIX(pcre2_set_substitute_callout_) -#define pcre2_substitute PCRE2_SUFFIX(pcre2_substitute_) -#define pcre2_substring_copy_byname PCRE2_SUFFIX(pcre2_substring_copy_byname_) -#define pcre2_substring_copy_bynumber PCRE2_SUFFIX(pcre2_substring_copy_bynumber_) -#define pcre2_substring_free PCRE2_SUFFIX(pcre2_substring_free_) -#define pcre2_substring_get_byname PCRE2_SUFFIX(pcre2_substring_get_byname_) -#define pcre2_substring_get_bynumber PCRE2_SUFFIX(pcre2_substring_get_bynumber_) -#define pcre2_substring_length_byname PCRE2_SUFFIX(pcre2_substring_length_byname_) -#define pcre2_substring_length_bynumber PCRE2_SUFFIX(pcre2_substring_length_bynumber_) -#define pcre2_substring_list_get PCRE2_SUFFIX(pcre2_substring_list_get_) -#define pcre2_substring_list_free PCRE2_SUFFIX(pcre2_substring_list_free_) -#define pcre2_substring_nametable_scan PCRE2_SUFFIX(pcre2_substring_nametable_scan_) -#define pcre2_substring_number_from_name PCRE2_SUFFIX(pcre2_substring_number_from_name_) - -/* Keep this old function name for backwards compatibility */ -#define pcre2_set_recursion_limit PCRE2_SUFFIX(pcre2_set_recursion_limit_) - -/* Keep this obsolete function for backwards compatibility: it is now a noop. */ -#define pcre2_set_recursion_memory_management PCRE2_SUFFIX(pcre2_set_recursion_memory_management_) - -/* Now generate all three sets of width-specific structures and function -prototypes. */ - -#define PCRE2_TYPES_STRUCTURES_AND_FUNCTIONS \ -PCRE2_TYPES_LIST \ -PCRE2_STRUCTURE_LIST \ -PCRE2_GENERAL_INFO_FUNCTIONS \ -PCRE2_GENERAL_CONTEXT_FUNCTIONS \ -PCRE2_COMPILE_CONTEXT_FUNCTIONS \ -PCRE2_CONVERT_CONTEXT_FUNCTIONS \ -PCRE2_CONVERT_FUNCTIONS \ -PCRE2_MATCH_CONTEXT_FUNCTIONS \ -PCRE2_COMPILE_FUNCTIONS \ -PCRE2_PATTERN_INFO_FUNCTIONS \ -PCRE2_MATCH_FUNCTIONS \ -PCRE2_SUBSTRING_FUNCTIONS \ -PCRE2_SERIALIZE_FUNCTIONS \ -PCRE2_SUBSTITUTE_FUNCTION \ -PCRE2_JIT_FUNCTIONS \ -PCRE2_OTHER_FUNCTIONS - -#define PCRE2_LOCAL_WIDTH 8 -PCRE2_TYPES_STRUCTURES_AND_FUNCTIONS -#undef PCRE2_LOCAL_WIDTH - -#define PCRE2_LOCAL_WIDTH 16 -PCRE2_TYPES_STRUCTURES_AND_FUNCTIONS -#undef PCRE2_LOCAL_WIDTH - -#define PCRE2_LOCAL_WIDTH 32 -PCRE2_TYPES_STRUCTURES_AND_FUNCTIONS -#undef PCRE2_LOCAL_WIDTH - -/* Undefine the list macros; they are no longer needed. */ - -#undef PCRE2_TYPES_LIST -#undef PCRE2_STRUCTURE_LIST -#undef PCRE2_GENERAL_INFO_FUNCTIONS -#undef PCRE2_GENERAL_CONTEXT_FUNCTIONS -#undef PCRE2_COMPILE_CONTEXT_FUNCTIONS -#undef PCRE2_CONVERT_CONTEXT_FUNCTIONS -#undef PCRE2_MATCH_CONTEXT_FUNCTIONS -#undef PCRE2_COMPILE_FUNCTIONS -#undef PCRE2_PATTERN_INFO_FUNCTIONS -#undef PCRE2_MATCH_FUNCTIONS -#undef PCRE2_SUBSTRING_FUNCTIONS -#undef PCRE2_SERIALIZE_FUNCTIONS -#undef PCRE2_SUBSTITUTE_FUNCTION -#undef PCRE2_JIT_FUNCTIONS -#undef PCRE2_OTHER_FUNCTIONS -#undef PCRE2_TYPES_STRUCTURES_AND_FUNCTIONS - -/* PCRE2_CODE_UNIT_WIDTH must be defined. If it is 8, 16, or 32, redefine -PCRE2_SUFFIX to use it. If it is 0, undefine the other macros and make -PCRE2_SUFFIX a no-op. Otherwise, generate an error. */ - -#undef PCRE2_SUFFIX -#ifndef PCRE2_CODE_UNIT_WIDTH -#error PCRE2_CODE_UNIT_WIDTH must be defined before including pcre2.h. -#error Use 8, 16, or 32; or 0 for a multi-width application. -#else /* PCRE2_CODE_UNIT_WIDTH is defined */ -#if PCRE2_CODE_UNIT_WIDTH == 8 || \ - PCRE2_CODE_UNIT_WIDTH == 16 || \ - PCRE2_CODE_UNIT_WIDTH == 32 -#define PCRE2_SUFFIX(a) PCRE2_GLUE(a, PCRE2_CODE_UNIT_WIDTH) -#elif PCRE2_CODE_UNIT_WIDTH == 0 -#undef PCRE2_JOIN -#undef PCRE2_GLUE -#define PCRE2_SUFFIX(a) a -#else -#error PCRE2_CODE_UNIT_WIDTH must be 0, 8, 16, or 32. -#endif -#endif /* PCRE2_CODE_UNIT_WIDTH is defined */ - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* PCRE2_H_IDEMPOTENT_GUARD */ - -/* End of pcre2.h */ diff --git a/modules/regex/pcre2/src/pcre2_auto_possess.c b/modules/regex/pcre2/src/pcre2_auto_possess.c deleted file mode 100644 index 419fd49..0000000 --- a/modules/regex/pcre2/src/pcre2_auto_possess.c +++ /dev/null @@ -1,1365 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -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-2022 University of Cambridge - ------------------------------------------------------------------------------ -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 OWNER 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. ------------------------------------------------------------------------------ -*/ - -/* This module contains functions that scan a compiled pattern and change -repeats into possessive repeats where possible. */ - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - - -#include "pcre2_internal.h" - - -/************************************************* -* Tables for auto-possessification * -*************************************************/ - -/* This table is used to check whether auto-possessification is possible -between adjacent character-type opcodes. The left-hand (repeated) opcode is -used to select the row, and the right-hand opcode is use to select the column. -A value of 1 means that auto-possessification is OK. For example, the second -value in the first row means that \D+\d can be turned into \D++\d. - -The Unicode property types (\P and \p) have to be present to fill out the table -because of what their opcode values are, but the table values should always be -zero because property types are handled separately in the code. The last four -columns apply to items that cannot be repeated, so there is no need to have -rows for them. Note that OP_DIGIT etc. are generated only when PCRE_UCP is -*not* set. When it is set, \d etc. are converted into OP_(NOT_)PROP codes. */ - -#define APTROWS (LAST_AUTOTAB_LEFT_OP - FIRST_AUTOTAB_OP + 1) -#define APTCOLS (LAST_AUTOTAB_RIGHT_OP - FIRST_AUTOTAB_OP + 1) - -static const uint8_t autoposstab[APTROWS][APTCOLS] = { -/* \D \d \S \s \W \w . .+ \C \P \p \R \H \h \V \v \X \Z \z $ $M */ - { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, /* \D */ - { 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1 }, /* \d */ - { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1 }, /* \S */ - { 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, /* \s */ - { 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, /* \W */ - { 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1 }, /* \w */ - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, /* . */ - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, /* .+ */ - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, /* \C */ - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* \P */ - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* \p */ - { 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0 }, /* \R */ - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0 }, /* \H */ - { 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0 }, /* \h */ - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0 }, /* \V */ - { 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0 }, /* \v */ - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 } /* \X */ -}; - -#ifdef SUPPORT_UNICODE -/* This table is used to check whether auto-possessification is possible -between adjacent Unicode property opcodes (OP_PROP and OP_NOTPROP). The -left-hand (repeated) opcode is used to select the row, and the right-hand -opcode is used to select the column. The values are as follows: - - 0 Always return FALSE (never auto-possessify) - 1 Character groups are distinct (possessify if both are OP_PROP) - 2 Check character categories in the same group (general or particular) - 3 TRUE if the two opcodes are not the same (PROP vs NOTPROP) - - 4 Check left general category vs right particular category - 5 Check right general category vs left particular category - - 6 Left alphanum vs right general category - 7 Left space vs right general category - 8 Left word vs right general category - - 9 Right alphanum vs left general category - 10 Right space vs left general category - 11 Right word vs left general category - - 12 Left alphanum vs right particular category - 13 Left space vs right particular category - 14 Left word vs right particular category - - 15 Right alphanum vs left particular category - 16 Right space vs left particular category - 17 Right word vs left particular category -*/ - -static const uint8_t propposstab[PT_TABSIZE][PT_TABSIZE] = { -/* ANY LAMP GC PC SC SCX ALNUM SPACE PXSPACE WORD CLIST UCNC BIDICL BOOL */ - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* PT_ANY */ - { 0, 3, 0, 0, 0, 0, 3, 1, 1, 0, 0, 0, 0, 0 }, /* PT_LAMP */ - { 0, 0, 2, 4, 0, 0, 9, 10, 10, 11, 0, 0, 0, 0 }, /* PT_GC */ - { 0, 0, 5, 2, 0, 0, 15, 16, 16, 17, 0, 0, 0, 0 }, /* PT_PC */ - { 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0 }, /* PT_SC */ - { 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0 }, /* PT_SCX */ - { 0, 3, 6, 12, 0, 0, 3, 1, 1, 0, 0, 0, 0, 0 }, /* PT_ALNUM */ - { 0, 1, 7, 13, 0, 0, 1, 3, 3, 1, 0, 0, 0, 0 }, /* PT_SPACE */ - { 0, 1, 7, 13, 0, 0, 1, 3, 3, 1, 0, 0, 0, 0 }, /* PT_PXSPACE */ - { 0, 0, 8, 14, 0, 0, 0, 1, 1, 3, 0, 0, 0, 0 }, /* PT_WORD */ - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* PT_CLIST */ - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0 }, /* PT_UCNC */ - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* PT_BIDICL */ - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } /* PT_BOOL */ -}; - -/* This table is used to check whether auto-possessification is possible -between adjacent Unicode property opcodes (OP_PROP and OP_NOTPROP) when one -specifies a general category and the other specifies a particular category. The -row is selected by the general category and the column by the particular -category. The value is 1 if the particular category is not part of the general -category. */ - -static const uint8_t catposstab[7][30] = { -/* Cc Cf Cn Co Cs Ll Lm Lo Lt Lu Mc Me Mn Nd Nl No Pc Pd Pe Pf Pi Po Ps Sc Sk Sm So Zl Zp Zs */ - { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* C */ - { 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* L */ - { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* M */ - { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* N */ - { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1 }, /* P */ - { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1 }, /* S */ - { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 } /* Z */ -}; - -/* This table is used when checking ALNUM, (PX)SPACE, SPACE, and WORD against -a general or particular category. The properties in each row are those -that apply to the character set in question. Duplication means that a little -unnecessary work is done when checking, but this keeps things much simpler -because they can all use the same code. For more details see the comment where -this table is used. - -Note: SPACE and PXSPACE used to be different because Perl excluded VT from -"space", but from Perl 5.18 it's included, so both categories are treated the -same here. */ - -static const uint8_t posspropstab[3][4] = { - { ucp_L, ucp_N, ucp_N, ucp_Nl }, /* ALNUM, 3rd and 4th values redundant */ - { ucp_Z, ucp_Z, ucp_C, ucp_Cc }, /* SPACE and PXSPACE, 2nd value redundant */ - { ucp_L, ucp_N, ucp_P, ucp_Po } /* WORD */ -}; -#endif /* SUPPORT_UNICODE */ - - - -#ifdef SUPPORT_UNICODE -/************************************************* -* Check a character and a property * -*************************************************/ - -/* This function is called by compare_opcodes() when a property item is -adjacent to a fixed character. - -Arguments: - c the character - ptype the property type - pdata the data for the type - negated TRUE if it's a negated property (\P or \p{^) - -Returns: TRUE if auto-possessifying is OK -*/ - -static BOOL -check_char_prop(uint32_t c, unsigned int ptype, unsigned int pdata, - BOOL negated) -{ -BOOL ok; -const uint32_t *p; -const ucd_record *prop = GET_UCD(c); - -switch(ptype) - { - case PT_LAMP: - return (prop->chartype == ucp_Lu || - prop->chartype == ucp_Ll || - prop->chartype == ucp_Lt) == negated; - - case PT_GC: - return (pdata == PRIV(ucp_gentype)[prop->chartype]) == negated; - - case PT_PC: - return (pdata == prop->chartype) == negated; - - case PT_SC: - return (pdata == prop->script) == negated; - - case PT_SCX: - ok = (pdata == prop->script - || MAPBIT(PRIV(ucd_script_sets) + UCD_SCRIPTX_PROP(prop), pdata) != 0); - return ok == negated; - - /* These are specials */ - - case PT_ALNUM: - return (PRIV(ucp_gentype)[prop->chartype] == ucp_L || - PRIV(ucp_gentype)[prop->chartype] == ucp_N) == negated; - - /* Perl space used to exclude VT, but from Perl 5.18 it is included, which - means that Perl space and POSIX space are now identical. PCRE was changed - at release 8.34. */ - - case PT_SPACE: /* Perl space */ - case PT_PXSPACE: /* POSIX space */ - switch(c) - { - HSPACE_CASES: - VSPACE_CASES: - return negated; - - default: - return (PRIV(ucp_gentype)[prop->chartype] == ucp_Z) == negated; - } - break; /* Control never reaches here */ - - case PT_WORD: - return (PRIV(ucp_gentype)[prop->chartype] == ucp_L || - PRIV(ucp_gentype)[prop->chartype] == ucp_N || - c == CHAR_UNDERSCORE) == negated; - - case PT_CLIST: - p = PRIV(ucd_caseless_sets) + prop->caseset; - for (;;) - { - if (c < *p) return !negated; - if (c == *p++) return negated; - } - break; /* Control never reaches here */ - - /* Haven't yet thought these through. */ - - case PT_BIDICL: - return FALSE; - - case PT_BOOL: - return FALSE; - } - -return FALSE; -} -#endif /* SUPPORT_UNICODE */ - - - -/************************************************* -* Base opcode of repeated opcodes * -*************************************************/ - -/* Returns the base opcode for repeated single character type opcodes. If the -opcode is not a repeated character type, it returns with the original value. - -Arguments: c opcode -Returns: base opcode for the type -*/ - -static PCRE2_UCHAR -get_repeat_base(PCRE2_UCHAR c) -{ -return (c > OP_TYPEPOSUPTO)? c : - (c >= OP_TYPESTAR)? OP_TYPESTAR : - (c >= OP_NOTSTARI)? OP_NOTSTARI : - (c >= OP_NOTSTAR)? OP_NOTSTAR : - (c >= OP_STARI)? OP_STARI : - OP_STAR; -} - - -/************************************************* -* Fill the character property list * -*************************************************/ - -/* Checks whether the code points to an opcode that can take part in auto- -possessification, and if so, fills a list with its properties. - -Arguments: - code points to start of expression - utf TRUE if in UTF mode - ucp TRUE if in UCP mode - fcc points to the case-flipping table - list points to output list - list[0] will be filled with the opcode - list[1] will be non-zero if this opcode - can match an empty character string - list[2..7] depends on the opcode - -Returns: points to the start of the next opcode if *code is accepted - NULL if *code is not accepted -*/ - -static PCRE2_SPTR -get_chr_property_list(PCRE2_SPTR code, BOOL utf, BOOL ucp, const uint8_t *fcc, - uint32_t *list) -{ -PCRE2_UCHAR c = *code; -PCRE2_UCHAR base; -PCRE2_SPTR end; -uint32_t chr; - -#ifdef SUPPORT_UNICODE -uint32_t *clist_dest; -const uint32_t *clist_src; -#else -(void)utf; /* Suppress "unused parameter" compiler warnings */ -(void)ucp; -#endif - -list[0] = c; -list[1] = FALSE; -code++; - -if (c >= OP_STAR && c <= OP_TYPEPOSUPTO) - { - base = get_repeat_base(c); - c -= (base - OP_STAR); - - if (c == OP_UPTO || c == OP_MINUPTO || c == OP_EXACT || c == OP_POSUPTO) - code += IMM2_SIZE; - - list[1] = (c != OP_PLUS && c != OP_MINPLUS && c != OP_EXACT && - c != OP_POSPLUS); - - switch(base) - { - case OP_STAR: - list[0] = OP_CHAR; - break; - - case OP_STARI: - list[0] = OP_CHARI; - break; - - case OP_NOTSTAR: - list[0] = OP_NOT; - break; - - case OP_NOTSTARI: - list[0] = OP_NOTI; - break; - - case OP_TYPESTAR: - list[0] = *code; - code++; - break; - } - c = list[0]; - } - -switch(c) - { - case OP_NOT_DIGIT: - case OP_DIGIT: - case OP_NOT_WHITESPACE: - case OP_WHITESPACE: - case OP_NOT_WORDCHAR: - case OP_WORDCHAR: - case OP_ANY: - case OP_ALLANY: - case OP_ANYNL: - case OP_NOT_HSPACE: - case OP_HSPACE: - case OP_NOT_VSPACE: - case OP_VSPACE: - case OP_EXTUNI: - case OP_EODN: - case OP_EOD: - case OP_DOLL: - case OP_DOLLM: - return code; - - case OP_CHAR: - case OP_NOT: - GETCHARINCTEST(chr, code); - list[2] = chr; - list[3] = NOTACHAR; - return code; - - case OP_CHARI: - case OP_NOTI: - list[0] = (c == OP_CHARI) ? OP_CHAR : OP_NOT; - GETCHARINCTEST(chr, code); - list[2] = chr; - -#ifdef SUPPORT_UNICODE - if (chr < 128 || (chr < 256 && !utf && !ucp)) - list[3] = fcc[chr]; - else - list[3] = UCD_OTHERCASE(chr); -#elif defined SUPPORT_WIDE_CHARS - list[3] = (chr < 256) ? fcc[chr] : chr; -#else - list[3] = fcc[chr]; -#endif - - /* The othercase might be the same value. */ - - if (chr == list[3]) - list[3] = NOTACHAR; - else - list[4] = NOTACHAR; - return code; - -#ifdef SUPPORT_UNICODE - case OP_PROP: - case OP_NOTPROP: - if (code[0] != PT_CLIST) - { - list[2] = code[0]; - list[3] = code[1]; - return code + 2; - } - - /* Convert only if we have enough space. */ - - clist_src = PRIV(ucd_caseless_sets) + code[1]; - clist_dest = list + 2; - code += 2; - - do { - if (clist_dest >= list + 8) - { - /* Early return if there is not enough space. This should never - happen, since all clists are shorter than 5 character now. */ - list[2] = code[0]; - list[3] = code[1]; - return code; - } - *clist_dest++ = *clist_src; - } - while(*clist_src++ != NOTACHAR); - - /* All characters are stored. The terminating NOTACHAR is copied from the - clist itself. */ - - list[0] = (c == OP_PROP) ? OP_CHAR : OP_NOT; - return code; -#endif - - case OP_NCLASS: - case OP_CLASS: -#ifdef SUPPORT_WIDE_CHARS - case OP_XCLASS: - if (c == OP_XCLASS) - end = code + GET(code, 0) - 1; - else -#endif - end = code + 32 / sizeof(PCRE2_UCHAR); - - switch(*end) - { - case OP_CRSTAR: - case OP_CRMINSTAR: - case OP_CRQUERY: - case OP_CRMINQUERY: - case OP_CRPOSSTAR: - case OP_CRPOSQUERY: - list[1] = TRUE; - end++; - break; - - case OP_CRPLUS: - case OP_CRMINPLUS: - case OP_CRPOSPLUS: - end++; - break; - - case OP_CRRANGE: - case OP_CRMINRANGE: - case OP_CRPOSRANGE: - list[1] = (GET2(end, 1) == 0); - end += 1 + 2 * IMM2_SIZE; - break; - } - list[2] = (uint32_t)(end - code); - return end; - } - -return NULL; /* Opcode not accepted */ -} - - - -/************************************************* -* Scan further character sets for match * -*************************************************/ - -/* Checks whether the base and the current opcode have a common character, in -which case the base cannot be possessified. - -Arguments: - code points to the byte code - utf TRUE in UTF mode - ucp TRUE in UCP mode - cb compile data block - base_list the data list of the base opcode - base_end the end of the base opcode - rec_limit points to recursion depth counter - -Returns: TRUE if the auto-possessification is possible -*/ - -static BOOL -compare_opcodes(PCRE2_SPTR code, BOOL utf, BOOL ucp, const compile_block *cb, - const uint32_t *base_list, PCRE2_SPTR base_end, int *rec_limit) -{ -PCRE2_UCHAR c; -uint32_t list[8]; -const uint32_t *chr_ptr; -const uint32_t *ochr_ptr; -const uint32_t *list_ptr; -PCRE2_SPTR next_code; -#ifdef SUPPORT_WIDE_CHARS -PCRE2_SPTR xclass_flags; -#endif -const uint8_t *class_bitset; -const uint8_t *set1, *set2, *set_end; -uint32_t chr; -BOOL accepted, invert_bits; -BOOL entered_a_group = FALSE; - -if (--(*rec_limit) <= 0) return FALSE; /* Recursion has gone too deep */ - -/* Note: the base_list[1] contains whether the current opcode has a greedy -(represented by a non-zero value) quantifier. This is a different from -other character type lists, which store here that the character iterator -matches to an empty string (also represented by a non-zero value). */ - -for(;;) - { - /* All operations move the code pointer forward. - Therefore infinite recursions are not possible. */ - - c = *code; - - /* Skip over callouts */ - - if (c == OP_CALLOUT) - { - code += PRIV(OP_lengths)[c]; - continue; - } - - if (c == OP_CALLOUT_STR) - { - code += GET(code, 1 + 2*LINK_SIZE); - continue; - } - - /* At the end of a branch, skip to the end of the group. */ - - if (c == OP_ALT) - { - do code += GET(code, 1); while (*code == OP_ALT); - c = *code; - } - - /* Inspect the next opcode. */ - - switch(c) - { - /* We can always possessify a greedy iterator at the end of the pattern, - which is reached after skipping over the final OP_KET. A non-greedy - iterator must never be possessified. */ - - case OP_END: - return base_list[1] != 0; - - /* When an iterator is at the end of certain kinds of group we can inspect - what follows the group by skipping over the closing ket. Note that this - does not apply to OP_KETRMAX or OP_KETRMIN because what follows any given - iteration is variable (could be another iteration or could be the next - item). As these two opcodes are not listed in the next switch, they will - end up as the next code to inspect, and return FALSE by virtue of being - unsupported. */ - - case OP_KET: - case OP_KETRPOS: - /* The non-greedy case cannot be converted to a possessive form. */ - - if (base_list[1] == 0) return FALSE; - - /* If the bracket is capturing it might be referenced by an OP_RECURSE - so its last iterator can never be possessified if the pattern contains - recursions. (This could be improved by keeping a list of group numbers that - are called by recursion.) */ - - switch(*(code - GET(code, 1))) - { - case OP_CBRA: - case OP_SCBRA: - case OP_CBRAPOS: - case OP_SCBRAPOS: - if (cb->had_recurse) return FALSE; - break; - - /* A script run might have to backtrack if the iterated item can match - characters from more than one script. So give up unless repeating an - explicit character. */ - - case OP_SCRIPT_RUN: - if (base_list[0] != OP_CHAR && base_list[0] != OP_CHARI) - return FALSE; - break; - - /* Atomic sub-patterns and assertions can always auto-possessify their - last iterator. However, if the group was entered as a result of checking - a previous iterator, this is not possible. */ - - case OP_ASSERT: - case OP_ASSERT_NOT: - case OP_ASSERTBACK: - case OP_ASSERTBACK_NOT: - case OP_ONCE: - return !entered_a_group; - - /* Non-atomic assertions - don't possessify last iterator. This needs - more thought. */ - - case OP_ASSERT_NA: - case OP_ASSERTBACK_NA: - return FALSE; - } - - /* Skip over the bracket and inspect what comes next. */ - - code += PRIV(OP_lengths)[c]; - continue; - - /* Handle cases where the next item is a group. */ - - case OP_ONCE: - case OP_BRA: - case OP_CBRA: - next_code = code + GET(code, 1); - code += PRIV(OP_lengths)[c]; - - /* Check each branch. We have to recurse a level for all but the last - branch. */ - - while (*next_code == OP_ALT) - { - if (!compare_opcodes(code, utf, ucp, cb, base_list, base_end, rec_limit)) - return FALSE; - code = next_code + 1 + LINK_SIZE; - next_code += GET(next_code, 1); - } - - entered_a_group = TRUE; - continue; - - case OP_BRAZERO: - case OP_BRAMINZERO: - - next_code = code + 1; - if (*next_code != OP_BRA && *next_code != OP_CBRA && - *next_code != OP_ONCE) return FALSE; - - do next_code += GET(next_code, 1); while (*next_code == OP_ALT); - - /* The bracket content will be checked by the OP_BRA/OP_CBRA case above. */ - - next_code += 1 + LINK_SIZE; - if (!compare_opcodes(next_code, utf, ucp, cb, base_list, base_end, - rec_limit)) - return FALSE; - - code += PRIV(OP_lengths)[c]; - continue; - - /* The next opcode does not need special handling; fall through and use it - to see if the base can be possessified. */ - - default: - break; - } - - /* We now have the next appropriate opcode to compare with the base. Check - for a supported opcode, and load its properties. */ - - code = get_chr_property_list(code, utf, ucp, cb->fcc, list); - if (code == NULL) return FALSE; /* Unsupported */ - - /* If either opcode is a small character list, set pointers for comparing - characters from that list with another list, or with a property. */ - - if (base_list[0] == OP_CHAR) - { - chr_ptr = base_list + 2; - list_ptr = list; - } - else if (list[0] == OP_CHAR) - { - chr_ptr = list + 2; - list_ptr = base_list; - } - - /* Character bitsets can also be compared to certain opcodes. */ - - else if (base_list[0] == OP_CLASS || list[0] == OP_CLASS -#if PCRE2_CODE_UNIT_WIDTH == 8 - /* In 8 bit, non-UTF mode, OP_CLASS and OP_NCLASS are the same. */ - || (!utf && (base_list[0] == OP_NCLASS || list[0] == OP_NCLASS)) -#endif - ) - { -#if PCRE2_CODE_UNIT_WIDTH == 8 - if (base_list[0] == OP_CLASS || (!utf && base_list[0] == OP_NCLASS)) -#else - if (base_list[0] == OP_CLASS) -#endif - { - set1 = (uint8_t *)(base_end - base_list[2]); - list_ptr = list; - } - else - { - set1 = (uint8_t *)(code - list[2]); - list_ptr = base_list; - } - - invert_bits = FALSE; - switch(list_ptr[0]) - { - case OP_CLASS: - case OP_NCLASS: - set2 = (uint8_t *) - ((list_ptr == list ? code : base_end) - list_ptr[2]); - break; - -#ifdef SUPPORT_WIDE_CHARS - case OP_XCLASS: - xclass_flags = (list_ptr == list ? code : base_end) - list_ptr[2] + LINK_SIZE; - if ((*xclass_flags & XCL_HASPROP) != 0) return FALSE; - if ((*xclass_flags & XCL_MAP) == 0) - { - /* No bits are set for characters < 256. */ - if (list[1] == 0) return (*xclass_flags & XCL_NOT) == 0; - /* Might be an empty repeat. */ - continue; - } - set2 = (uint8_t *)(xclass_flags + 1); - break; -#endif - - case OP_NOT_DIGIT: - invert_bits = TRUE; - /* Fall through */ - case OP_DIGIT: - set2 = (uint8_t *)(cb->cbits + cbit_digit); - break; - - case OP_NOT_WHITESPACE: - invert_bits = TRUE; - /* Fall through */ - case OP_WHITESPACE: - set2 = (uint8_t *)(cb->cbits + cbit_space); - break; - - case OP_NOT_WORDCHAR: - invert_bits = TRUE; - /* Fall through */ - case OP_WORDCHAR: - set2 = (uint8_t *)(cb->cbits + cbit_word); - break; - - default: - return FALSE; - } - - /* Because the bit sets are unaligned bytes, we need to perform byte - comparison here. */ - - set_end = set1 + 32; - if (invert_bits) - { - do - { - if ((*set1++ & ~(*set2++)) != 0) return FALSE; - } - while (set1 < set_end); - } - else - { - do - { - if ((*set1++ & *set2++) != 0) return FALSE; - } - while (set1 < set_end); - } - - if (list[1] == 0) return TRUE; - /* Might be an empty repeat. */ - continue; - } - - /* Some property combinations also acceptable. Unicode property opcodes are - processed specially; the rest can be handled with a lookup table. */ - - else - { - uint32_t leftop, rightop; - - leftop = base_list[0]; - rightop = list[0]; - -#ifdef SUPPORT_UNICODE - accepted = FALSE; /* Always set in non-unicode case. */ - if (leftop == OP_PROP || leftop == OP_NOTPROP) - { - if (rightop == OP_EOD) - accepted = TRUE; - else if (rightop == OP_PROP || rightop == OP_NOTPROP) - { - int n; - const uint8_t *p; - BOOL same = leftop == rightop; - BOOL lisprop = leftop == OP_PROP; - BOOL risprop = rightop == OP_PROP; - BOOL bothprop = lisprop && risprop; - - /* There's a table that specifies how each combination is to be - processed: - 0 Always return FALSE (never auto-possessify) - 1 Character groups are distinct (possessify if both are OP_PROP) - 2 Check character categories in the same group (general or particular) - 3 Return TRUE if the two opcodes are not the same - ... see comments below - */ - - n = propposstab[base_list[2]][list[2]]; - switch(n) - { - case 0: break; - case 1: accepted = bothprop; break; - case 2: accepted = (base_list[3] == list[3]) != same; break; - case 3: accepted = !same; break; - - case 4: /* Left general category, right particular category */ - accepted = risprop && catposstab[base_list[3]][list[3]] == same; - break; - - case 5: /* Right general category, left particular category */ - accepted = lisprop && catposstab[list[3]][base_list[3]] == same; - break; - - /* This code is logically tricky. Think hard before fiddling with it. - The posspropstab table has four entries per row. Each row relates to - one of PCRE's special properties such as ALNUM or SPACE or WORD. - Only WORD actually needs all four entries, but using repeats for the - others means they can all use the same code below. - - The first two entries in each row are Unicode general categories, and - apply always, because all the characters they include are part of the - PCRE character set. The third and fourth entries are a general and a - particular category, respectively, that include one or more relevant - characters. One or the other is used, depending on whether the check - is for a general or a particular category. However, in both cases the - category contains more characters than the specials that are defined - for the property being tested against. Therefore, it cannot be used - in a NOTPROP case. - - Example: the row for WORD contains ucp_L, ucp_N, ucp_P, ucp_Po. - Underscore is covered by ucp_P or ucp_Po. */ - - case 6: /* Left alphanum vs right general category */ - case 7: /* Left space vs right general category */ - case 8: /* Left word vs right general category */ - p = posspropstab[n-6]; - accepted = risprop && lisprop == - (list[3] != p[0] && - list[3] != p[1] && - (list[3] != p[2] || !lisprop)); - break; - - case 9: /* Right alphanum vs left general category */ - case 10: /* Right space vs left general category */ - case 11: /* Right word vs left general category */ - p = posspropstab[n-9]; - accepted = lisprop && risprop == - (base_list[3] != p[0] && - base_list[3] != p[1] && - (base_list[3] != p[2] || !risprop)); - break; - - case 12: /* Left alphanum vs right particular category */ - case 13: /* Left space vs right particular category */ - case 14: /* Left word vs right particular category */ - p = posspropstab[n-12]; - accepted = risprop && lisprop == - (catposstab[p[0]][list[3]] && - catposstab[p[1]][list[3]] && - (list[3] != p[3] || !lisprop)); - break; - - case 15: /* Right alphanum vs left particular category */ - case 16: /* Right space vs left particular category */ - case 17: /* Right word vs left particular category */ - p = posspropstab[n-15]; - accepted = lisprop && risprop == - (catposstab[p[0]][base_list[3]] && - catposstab[p[1]][base_list[3]] && - (base_list[3] != p[3] || !risprop)); - break; - } - } - } - - else -#endif /* SUPPORT_UNICODE */ - - accepted = leftop >= FIRST_AUTOTAB_OP && leftop <= LAST_AUTOTAB_LEFT_OP && - rightop >= FIRST_AUTOTAB_OP && rightop <= LAST_AUTOTAB_RIGHT_OP && - autoposstab[leftop - FIRST_AUTOTAB_OP][rightop - FIRST_AUTOTAB_OP]; - - if (!accepted) return FALSE; - - if (list[1] == 0) return TRUE; - /* Might be an empty repeat. */ - continue; - } - - /* Control reaches here only if one of the items is a small character list. - All characters are checked against the other side. */ - - do - { - chr = *chr_ptr; - - switch(list_ptr[0]) - { - case OP_CHAR: - ochr_ptr = list_ptr + 2; - do - { - if (chr == *ochr_ptr) return FALSE; - ochr_ptr++; - } - while(*ochr_ptr != NOTACHAR); - break; - - case OP_NOT: - ochr_ptr = list_ptr + 2; - do - { - if (chr == *ochr_ptr) - break; - ochr_ptr++; - } - while(*ochr_ptr != NOTACHAR); - if (*ochr_ptr == NOTACHAR) return FALSE; /* Not found */ - break; - - /* Note that OP_DIGIT etc. are generated only when PCRE2_UCP is *not* - set. When it is set, \d etc. are converted into OP_(NOT_)PROP codes. */ - - case OP_DIGIT: - if (chr < 256 && (cb->ctypes[chr] & ctype_digit) != 0) return FALSE; - break; - - case OP_NOT_DIGIT: - if (chr > 255 || (cb->ctypes[chr] & ctype_digit) == 0) return FALSE; - break; - - case OP_WHITESPACE: - if (chr < 256 && (cb->ctypes[chr] & ctype_space) != 0) return FALSE; - break; - - case OP_NOT_WHITESPACE: - if (chr > 255 || (cb->ctypes[chr] & ctype_space) == 0) return FALSE; - break; - - case OP_WORDCHAR: - if (chr < 255 && (cb->ctypes[chr] & ctype_word) != 0) return FALSE; - break; - - case OP_NOT_WORDCHAR: - if (chr > 255 || (cb->ctypes[chr] & ctype_word) == 0) return FALSE; - break; - - case OP_HSPACE: - switch(chr) - { - HSPACE_CASES: return FALSE; - default: break; - } - break; - - case OP_NOT_HSPACE: - switch(chr) - { - HSPACE_CASES: break; - default: return FALSE; - } - break; - - case OP_ANYNL: - case OP_VSPACE: - switch(chr) - { - VSPACE_CASES: return FALSE; - default: break; - } - break; - - case OP_NOT_VSPACE: - switch(chr) - { - VSPACE_CASES: break; - default: return FALSE; - } - break; - - case OP_DOLL: - case OP_EODN: - switch (chr) - { - case CHAR_CR: - case CHAR_LF: - case CHAR_VT: - case CHAR_FF: - case CHAR_NEL: -#ifndef EBCDIC - case 0x2028: - case 0x2029: -#endif /* Not EBCDIC */ - return FALSE; - } - break; - - case OP_EOD: /* Can always possessify before \z */ - break; - -#ifdef SUPPORT_UNICODE - case OP_PROP: - case OP_NOTPROP: - if (!check_char_prop(chr, list_ptr[2], list_ptr[3], - list_ptr[0] == OP_NOTPROP)) - return FALSE; - break; -#endif - - case OP_NCLASS: - if (chr > 255) return FALSE; - /* Fall through */ - - case OP_CLASS: - if (chr > 255) break; - class_bitset = (uint8_t *) - ((list_ptr == list ? code : base_end) - list_ptr[2]); - if ((class_bitset[chr >> 3] & (1u << (chr & 7))) != 0) return FALSE; - break; - -#ifdef SUPPORT_WIDE_CHARS - case OP_XCLASS: - if (PRIV(xclass)(chr, (list_ptr == list ? code : base_end) - - list_ptr[2] + LINK_SIZE, utf)) return FALSE; - break; -#endif - - default: - return FALSE; - } - - chr_ptr++; - } - while(*chr_ptr != NOTACHAR); - - /* At least one character must be matched from this opcode. */ - - if (list[1] == 0) return TRUE; - } - -/* Control never reaches here. There used to be a fail-save return FALSE; here, -but some compilers complain about an unreachable statement. */ -} - - - -/************************************************* -* Scan compiled regex for auto-possession * -*************************************************/ - -/* Replaces single character iterations with their possessive alternatives -if appropriate. This function modifies the compiled opcode! Hitting a -non-existent opcode may indicate a bug in PCRE2, but it can also be caused if a -bad UTF string was compiled with PCRE2_NO_UTF_CHECK. The rec_limit catches -overly complicated or large patterns. In these cases, the check just stops, -leaving the remainder of the pattern unpossessified. - -Arguments: - code points to start of the byte code - cb compile data block - -Returns: 0 for success - -1 if a non-existant opcode is encountered -*/ - -int -PRIV(auto_possessify)(PCRE2_UCHAR *code, const compile_block *cb) -{ -PCRE2_UCHAR c; -PCRE2_SPTR end; -PCRE2_UCHAR *repeat_opcode; -uint32_t list[8]; -int rec_limit = 1000; /* Was 10,000 but clang+ASAN uses a lot of stack. */ -BOOL utf = (cb->external_options & PCRE2_UTF) != 0; -BOOL ucp = (cb->external_options & PCRE2_UCP) != 0; - -for (;;) - { - c = *code; - - if (c >= OP_TABLE_LENGTH) return -1; /* Something gone wrong */ - - if (c >= OP_STAR && c <= OP_TYPEPOSUPTO) - { - c -= get_repeat_base(c) - OP_STAR; - end = (c <= OP_MINUPTO) ? - get_chr_property_list(code, utf, ucp, cb->fcc, list) : NULL; - list[1] = c == OP_STAR || c == OP_PLUS || c == OP_QUERY || c == OP_UPTO; - - if (end != NULL && compare_opcodes(end, utf, ucp, cb, list, end, - &rec_limit)) - { - switch(c) - { - case OP_STAR: - *code += OP_POSSTAR - OP_STAR; - break; - - case OP_MINSTAR: - *code += OP_POSSTAR - OP_MINSTAR; - break; - - case OP_PLUS: - *code += OP_POSPLUS - OP_PLUS; - break; - - case OP_MINPLUS: - *code += OP_POSPLUS - OP_MINPLUS; - break; - - case OP_QUERY: - *code += OP_POSQUERY - OP_QUERY; - break; - - case OP_MINQUERY: - *code += OP_POSQUERY - OP_MINQUERY; - break; - - case OP_UPTO: - *code += OP_POSUPTO - OP_UPTO; - break; - - case OP_MINUPTO: - *code += OP_POSUPTO - OP_MINUPTO; - break; - } - } - c = *code; - } - else if (c == OP_CLASS || c == OP_NCLASS || c == OP_XCLASS) - { -#ifdef SUPPORT_WIDE_CHARS - if (c == OP_XCLASS) - repeat_opcode = code + GET(code, 1); - else -#endif - repeat_opcode = code + 1 + (32 / sizeof(PCRE2_UCHAR)); - - c = *repeat_opcode; - if (c >= OP_CRSTAR && c <= OP_CRMINRANGE) - { - /* The return from get_chr_property_list() will never be NULL when - *code (aka c) is one of the three class opcodes. However, gcc with - -fanalyzer notes that a NULL return is possible, and grumbles. Hence we - put in a check. */ - - end = get_chr_property_list(code, utf, ucp, cb->fcc, list); - list[1] = (c & 1) == 0; - - if (end != NULL && - compare_opcodes(end, utf, ucp, cb, list, end, &rec_limit)) - { - switch (c) - { - case OP_CRSTAR: - case OP_CRMINSTAR: - *repeat_opcode = OP_CRPOSSTAR; - break; - - case OP_CRPLUS: - case OP_CRMINPLUS: - *repeat_opcode = OP_CRPOSPLUS; - break; - - case OP_CRQUERY: - case OP_CRMINQUERY: - *repeat_opcode = OP_CRPOSQUERY; - break; - - case OP_CRRANGE: - case OP_CRMINRANGE: - *repeat_opcode = OP_CRPOSRANGE; - break; - } - } - } - c = *code; - } - - switch(c) - { - case OP_END: - return 0; - - case OP_TYPESTAR: - case OP_TYPEMINSTAR: - case OP_TYPEPLUS: - case OP_TYPEMINPLUS: - case OP_TYPEQUERY: - case OP_TYPEMINQUERY: - case OP_TYPEPOSSTAR: - case OP_TYPEPOSPLUS: - case OP_TYPEPOSQUERY: - if (code[1] == OP_PROP || code[1] == OP_NOTPROP) code += 2; - break; - - case OP_TYPEUPTO: - case OP_TYPEMINUPTO: - case OP_TYPEEXACT: - case OP_TYPEPOSUPTO: - if (code[1 + IMM2_SIZE] == OP_PROP || code[1 + IMM2_SIZE] == OP_NOTPROP) - code += 2; - break; - - case OP_CALLOUT_STR: - code += GET(code, 1 + 2*LINK_SIZE); - break; - -#ifdef SUPPORT_WIDE_CHARS - case OP_XCLASS: - code += GET(code, 1); - break; -#endif - - case OP_MARK: - case OP_COMMIT_ARG: - case OP_PRUNE_ARG: - case OP_SKIP_ARG: - case OP_THEN_ARG: - code += code[1]; - break; - } - - /* Add in the fixed length from the table */ - - code += PRIV(OP_lengths)[c]; - - /* In UTF-8 and UTF-16 modes, opcodes that are followed by a character may be - followed by a multi-byte character. The length in the table is a minimum, so - we have to arrange to skip the extra code units. */ - -#ifdef MAYBE_UTF_MULTI - if (utf) switch(c) - { - case OP_CHAR: - case OP_CHARI: - case OP_NOT: - case OP_NOTI: - case OP_STAR: - case OP_MINSTAR: - case OP_PLUS: - case OP_MINPLUS: - case OP_QUERY: - case OP_MINQUERY: - case OP_UPTO: - case OP_MINUPTO: - case OP_EXACT: - case OP_POSSTAR: - case OP_POSPLUS: - case OP_POSQUERY: - case OP_POSUPTO: - case OP_STARI: - case OP_MINSTARI: - case OP_PLUSI: - case OP_MINPLUSI: - case OP_QUERYI: - case OP_MINQUERYI: - case OP_UPTOI: - case OP_MINUPTOI: - case OP_EXACTI: - case OP_POSSTARI: - case OP_POSPLUSI: - case OP_POSQUERYI: - case OP_POSUPTOI: - case OP_NOTSTAR: - case OP_NOTMINSTAR: - case OP_NOTPLUS: - case OP_NOTMINPLUS: - case OP_NOTQUERY: - case OP_NOTMINQUERY: - case OP_NOTUPTO: - case OP_NOTMINUPTO: - case OP_NOTEXACT: - case OP_NOTPOSSTAR: - case OP_NOTPOSPLUS: - case OP_NOTPOSQUERY: - case OP_NOTPOSUPTO: - case OP_NOTSTARI: - case OP_NOTMINSTARI: - case OP_NOTPLUSI: - case OP_NOTMINPLUSI: - case OP_NOTQUERYI: - case OP_NOTMINQUERYI: - case OP_NOTUPTOI: - case OP_NOTMINUPTOI: - case OP_NOTEXACTI: - case OP_NOTPOSSTARI: - case OP_NOTPOSPLUSI: - case OP_NOTPOSQUERYI: - case OP_NOTPOSUPTOI: - if (HAS_EXTRALEN(code[-1])) code += GET_EXTRALEN(code[-1]); - break; - } -#else - (void)(utf); /* Keep compiler happy by referencing function argument */ -#endif /* SUPPORT_WIDE_CHARS */ - } -} - -/* End of pcre2_auto_possess.c */ diff --git a/modules/regex/pcre2/src/pcre2_chartables.c b/modules/regex/pcre2/src/pcre2_chartables.c deleted file mode 100644 index 861914d..0000000 --- a/modules/regex/pcre2/src/pcre2_chartables.c +++ /dev/null @@ -1,202 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* This file was automatically written by the pcre2_dftables auxiliary -program. It contains character tables that are used when no external -tables are passed to PCRE2 by the application that calls it. The tables -are used only for characters whose code values are less than 256. */ - -/* This set of tables was written in the C locale. */ - -/* The pcre2_ftables program (which is distributed with PCRE2) can be used -to build alternative versions of this file. This is necessary if you are -running in an EBCDIC environment, or if you want to default to a different -encoding, for example ISO-8859-1. When pcre2_dftables is run, it creates -these tables in the "C" locale by default. This happens automatically if -PCRE2 is configured with --enable-rebuild-chartables. However, you can run -pcre2_dftables manually with the -L option to build tables using the LC_ALL -locale. */ - -/* The following #include is present because without it gcc 4.x may remove -the array definition from the final binary if PCRE2 is built into a static -library and dead code stripping is activated. This leads to link errors. -Pulling in the header ensures that the array gets flagged as "someone -outside this compilation unit might reference this" and so it will always -be supplied to the linker. */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "pcre2_internal.h" - -const uint8_t PRIV(default_tables)[] = { - -/* This table is a lower casing table. */ - - 0, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 61, 62, 63, - 64, 97, 98, 99,100,101,102,103, - 104,105,106,107,108,109,110,111, - 112,113,114,115,116,117,118,119, - 120,121,122, 91, 92, 93, 94, 95, - 96, 97, 98, 99,100,101,102,103, - 104,105,106,107,108,109,110,111, - 112,113,114,115,116,117,118,119, - 120,121,122,123,124,125,126,127, - 128,129,130,131,132,133,134,135, - 136,137,138,139,140,141,142,143, - 144,145,146,147,148,149,150,151, - 152,153,154,155,156,157,158,159, - 160,161,162,163,164,165,166,167, - 168,169,170,171,172,173,174,175, - 176,177,178,179,180,181,182,183, - 184,185,186,187,188,189,190,191, - 192,193,194,195,196,197,198,199, - 200,201,202,203,204,205,206,207, - 208,209,210,211,212,213,214,215, - 216,217,218,219,220,221,222,223, - 224,225,226,227,228,229,230,231, - 232,233,234,235,236,237,238,239, - 240,241,242,243,244,245,246,247, - 248,249,250,251,252,253,254,255, - -/* This table is a case flipping table. */ - - 0, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 61, 62, 63, - 64, 97, 98, 99,100,101,102,103, - 104,105,106,107,108,109,110,111, - 112,113,114,115,116,117,118,119, - 120,121,122, 91, 92, 93, 94, 95, - 96, 65, 66, 67, 68, 69, 70, 71, - 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90,123,124,125,126,127, - 128,129,130,131,132,133,134,135, - 136,137,138,139,140,141,142,143, - 144,145,146,147,148,149,150,151, - 152,153,154,155,156,157,158,159, - 160,161,162,163,164,165,166,167, - 168,169,170,171,172,173,174,175, - 176,177,178,179,180,181,182,183, - 184,185,186,187,188,189,190,191, - 192,193,194,195,196,197,198,199, - 200,201,202,203,204,205,206,207, - 208,209,210,211,212,213,214,215, - 216,217,218,219,220,221,222,223, - 224,225,226,227,228,229,230,231, - 232,233,234,235,236,237,238,239, - 240,241,242,243,244,245,246,247, - 248,249,250,251,252,253,254,255, - -/* This table contains bit maps for various character classes. Each map is 32 -bytes long and the bits run from the least significant end of each byte. The -classes that have their own maps are: space, xdigit, digit, upper, lower, word, -graph, print, punct, and cntrl. Other classes are built from combinations. */ - - 0x00,0x3e,0x00,0x00,0x01,0x00,0x00,0x00, /* space */ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03, /* xdigit */ - 0x7e,0x00,0x00,0x00,0x7e,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03, /* digit */ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* upper */ - 0xfe,0xff,0xff,0x07,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* lower */ - 0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0x07, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03, /* word */ - 0xfe,0xff,0xff,0x87,0xfe,0xff,0xff,0x07, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff, /* graph */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff, /* print */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 0x00,0x00,0x00,0x00,0xfe,0xff,0x00,0xfc, /* punct */ - 0x01,0x00,0x00,0xf8,0x01,0x00,0x00,0x78, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00, /* cntrl */ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - -/* This table identifies various classes of character by individual bits: - 0x01 white space character - 0x02 letter - 0x04 lower case letter - 0x08 decimal digit - 0x10 alphanumeric or '_' -*/ - - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0- 7 */ - 0x00,0x01,0x01,0x01,0x01,0x01,0x00,0x00, /* 8- 15 */ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 16- 23 */ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 24- 31 */ - 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* - ' */ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* ( - / */ - 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, /* 0 - 7 */ - 0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00, /* 8 - ? */ - 0x00,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* @ - G */ - 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* H - O */ - 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* P - W */ - 0x12,0x12,0x12,0x00,0x00,0x00,0x00,0x10, /* X - _ */ - 0x00,0x16,0x16,0x16,0x16,0x16,0x16,0x16, /* ` - g */ - 0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16, /* h - o */ - 0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16, /* p - w */ - 0x16,0x16,0x16,0x00,0x00,0x00,0x00,0x00, /* x -127 */ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 128-135 */ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 136-143 */ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 144-151 */ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 152-159 */ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 160-167 */ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 168-175 */ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 176-183 */ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 184-191 */ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 192-199 */ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 200-207 */ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 208-215 */ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 216-223 */ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 224-231 */ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 232-239 */ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 240-247 */ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};/* 248-255 */ - -/* End of pcre2_chartables.c */ diff --git a/modules/regex/pcre2/src/pcre2_compile.c b/modules/regex/pcre2/src/pcre2_compile.c deleted file mode 100644 index edf7e82..0000000 --- a/modules/regex/pcre2/src/pcre2_compile.c +++ /dev/null @@ -1,10631 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -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-2022 University of Cambridge - ------------------------------------------------------------------------------ -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 OWNER 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. ------------------------------------------------------------------------------ -*/ - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#define NLBLOCK cb /* Block containing newline information */ -#define PSSTART start_pattern /* Field containing processed string start */ -#define PSEND end_pattern /* Field containing processed string end */ - -#include "pcre2_internal.h" - -/* In rare error cases debugging might require calling pcre2_printint(). */ - -#if 0 -#ifdef EBCDIC -#define PRINTABLE(c) ((c) >= 64 && (c) < 255) -#else -#define PRINTABLE(c) ((c) >= 32 && (c) < 127) -#endif -#include "pcre2_printint.c" -#define DEBUG_CALL_PRINTINT -#endif - -/* Other debugging code can be enabled by these defines. */ - -/* #define DEBUG_SHOW_CAPTURES */ -/* #define DEBUG_SHOW_PARSED */ - -/* There are a few things that vary with different code unit sizes. Handle them -by defining macros in order to minimize #if usage. */ - -#if PCRE2_CODE_UNIT_WIDTH == 8 -#define STRING_UTFn_RIGHTPAR STRING_UTF8_RIGHTPAR, 5 -#define XDIGIT(c) xdigitab[c] - -#else /* Either 16-bit or 32-bit */ -#define XDIGIT(c) (MAX_255(c)? xdigitab[c] : 0xff) - -#if PCRE2_CODE_UNIT_WIDTH == 16 -#define STRING_UTFn_RIGHTPAR STRING_UTF16_RIGHTPAR, 6 - -#else /* 32-bit */ -#define STRING_UTFn_RIGHTPAR STRING_UTF32_RIGHTPAR, 6 -#endif -#endif - -/* Macros to store and retrieve a PCRE2_SIZE value in the parsed pattern, which -consists of uint32_t elements. Assume that if uint32_t can't hold it, two of -them will be able to (i.e. assume a 64-bit world). */ - -#if PCRE2_SIZE_MAX <= UINT32_MAX -#define PUTOFFSET(s,p) *p++ = s -#define GETOFFSET(s,p) s = *p++ -#define GETPLUSOFFSET(s,p) s = *(++p) -#define READPLUSOFFSET(s,p) s = p[1] -#define SKIPOFFSET(p) p++ -#define SIZEOFFSET 1 -#else -#define PUTOFFSET(s,p) \ - { *p++ = (uint32_t)(s >> 32); *p++ = (uint32_t)(s & 0xffffffff); } -#define GETOFFSET(s,p) \ - { s = ((PCRE2_SIZE)p[0] << 32) | (PCRE2_SIZE)p[1]; p += 2; } -#define GETPLUSOFFSET(s,p) \ - { s = ((PCRE2_SIZE)p[1] << 32) | (PCRE2_SIZE)p[2]; p += 2; } -#define READPLUSOFFSET(s,p) \ - { s = ((PCRE2_SIZE)p[1] << 32) | (PCRE2_SIZE)p[2]; } -#define SKIPOFFSET(p) p += 2 -#define SIZEOFFSET 2 -#endif - -/* Macros for manipulating elements of the parsed pattern vector. */ - -#define META_CODE(x) (x & 0xffff0000u) -#define META_DATA(x) (x & 0x0000ffffu) -#define META_DIFF(x,y) ((x-y)>>16) - -/* Function definitions to allow mutual recursion */ - -#ifdef SUPPORT_UNICODE -static unsigned int - add_list_to_class_internal(uint8_t *, PCRE2_UCHAR **, uint32_t, - compile_block *, const uint32_t *, unsigned int); -#endif - -static int - compile_regex(uint32_t, PCRE2_UCHAR **, uint32_t **, int *, uint32_t, - uint32_t *, uint32_t *, uint32_t *, uint32_t *, branch_chain *, - compile_block *, PCRE2_SIZE *); - -static int - get_branchlength(uint32_t **, int *, int *, parsed_recurse_check *, - compile_block *); - -static BOOL - set_lookbehind_lengths(uint32_t **, int *, int *, parsed_recurse_check *, - compile_block *); - -static int - check_lookbehinds(uint32_t *, uint32_t **, parsed_recurse_check *, - compile_block *, int *); - - -/************************************************* -* Code parameters and static tables * -*************************************************/ - -#define MAX_GROUP_NUMBER 65535u -#define MAX_REPEAT_COUNT 65535u -#define REPEAT_UNLIMITED (MAX_REPEAT_COUNT+1) - -/* COMPILE_WORK_SIZE specifies the size of stack workspace, which is used in -different ways in the different pattern scans. The parsing and group- -identifying pre-scan uses it to handle nesting, and needs it to be 16-bit -aligned for this. Having defined the size in code units, we set up -C16_WORK_SIZE as the number of elements in the 16-bit vector. - -During the first compiling phase, when determining how much memory is required, -the regex is partly compiled into this space, but the compiled parts are -discarded as soon as they can be, so that hopefully there will never be an -overrun. The code does, however, check for an overrun, which can occur for -pathological patterns. The size of the workspace depends on LINK_SIZE because -the length of compiled items varies with this. - -In the real compile phase, this workspace is not currently used. */ - -#define COMPILE_WORK_SIZE (3000*LINK_SIZE) /* Size in code units */ - -#define C16_WORK_SIZE \ - ((COMPILE_WORK_SIZE * sizeof(PCRE2_UCHAR))/sizeof(uint16_t)) - -/* A uint32_t vector is used for caching information about the size of -capturing groups, to improve performance. A default is created on the stack of -this size. */ - -#define GROUPINFO_DEFAULT_SIZE 256 - -/* The overrun tests check for a slightly smaller size so that they detect the -overrun before it actually does run off the end of the data block. */ - -#define WORK_SIZE_SAFETY_MARGIN (100) - -/* This value determines the size of the initial vector that is used for -remembering named groups during the pre-compile. It is allocated on the stack, -but if it is too small, it is expanded, in a similar way to the workspace. The -value is the number of slots in the list. */ - -#define NAMED_GROUP_LIST_SIZE 20 - -/* The pre-compiling pass over the pattern creates a parsed pattern in a vector -of uint32_t. For short patterns this lives on the stack, with this size. Heap -memory is used for longer patterns. */ - -#define PARSED_PATTERN_DEFAULT_SIZE 1024 - -/* Maximum length value to check against when making sure that the variable -that holds the compiled pattern length does not overflow. We make it a bit less -than INT_MAX to allow for adding in group terminating code units, so that we -don't have to check them every time. */ - -#define OFLOW_MAX (INT_MAX - 20) - -/* Code values for parsed patterns, which are stored in a vector of 32-bit -unsigned ints. Values less than META_END are literal data values. The coding -for identifying the item is in the top 16-bits, leaving 16 bits for the -additional data that some of them need. The META_CODE, META_DATA, and META_DIFF -macros are used to manipulate parsed pattern elements. - -NOTE: When these definitions are changed, the table of extra lengths for each -code (meta_extra_lengths, just below) must be updated to remain in step. */ - -#define META_END 0x80000000u /* End of pattern */ - -#define META_ALT 0x80010000u /* alternation */ -#define META_ATOMIC 0x80020000u /* atomic group */ -#define META_BACKREF 0x80030000u /* Back ref */ -#define META_BACKREF_BYNAME 0x80040000u /* \k'name' */ -#define META_BIGVALUE 0x80050000u /* Next is a literal > META_END */ -#define META_CALLOUT_NUMBER 0x80060000u /* (?C with numerical argument */ -#define META_CALLOUT_STRING 0x80070000u /* (?C with string argument */ -#define META_CAPTURE 0x80080000u /* Capturing parenthesis */ -#define META_CIRCUMFLEX 0x80090000u /* ^ metacharacter */ -#define META_CLASS 0x800a0000u /* start non-empty class */ -#define META_CLASS_EMPTY 0x800b0000u /* empty class */ -#define META_CLASS_EMPTY_NOT 0x800c0000u /* negative empty class */ -#define META_CLASS_END 0x800d0000u /* end of non-empty class */ -#define META_CLASS_NOT 0x800e0000u /* start non-empty negative class */ -#define META_COND_ASSERT 0x800f0000u /* (?(?assertion)... */ -#define META_COND_DEFINE 0x80100000u /* (?(DEFINE)... */ -#define META_COND_NAME 0x80110000u /* (?()... */ -#define META_COND_NUMBER 0x80120000u /* (?(digits)... */ -#define META_COND_RNAME 0x80130000u /* (?(R&name)... */ -#define META_COND_RNUMBER 0x80140000u /* (?(Rdigits)... */ -#define META_COND_VERSION 0x80150000u /* (?(VERSIONx.y)... */ -#define META_DOLLAR 0x80160000u /* $ metacharacter */ -#define META_DOT 0x80170000u /* . metacharacter */ -#define META_ESCAPE 0x80180000u /* \d and friends */ -#define META_KET 0x80190000u /* closing parenthesis */ -#define META_NOCAPTURE 0x801a0000u /* no capture parens */ -#define META_OPTIONS 0x801b0000u /* (?i) and friends */ -#define META_POSIX 0x801c0000u /* POSIX class item */ -#define META_POSIX_NEG 0x801d0000u /* negative POSIX class item */ -#define META_RANGE_ESCAPED 0x801e0000u /* range with at least one escape */ -#define META_RANGE_LITERAL 0x801f0000u /* range defined literally */ -#define META_RECURSE 0x80200000u /* Recursion */ -#define META_RECURSE_BYNAME 0x80210000u /* (?&name) */ -#define META_SCRIPT_RUN 0x80220000u /* (*script_run:...) */ - -/* These must be kept together to make it easy to check that an assertion -is present where expected in a conditional group. */ - -#define META_LOOKAHEAD 0x80230000u /* (?= */ -#define META_LOOKAHEADNOT 0x80240000u /* (?! */ -#define META_LOOKBEHIND 0x80250000u /* (?<= */ -#define META_LOOKBEHINDNOT 0x80260000u /* (?= 10 */ - 1+SIZEOFFSET, /* META_BACKREF_BYNAME */ - 1, /* META_BIGVALUE */ - 3, /* META_CALLOUT_NUMBER */ - 3+SIZEOFFSET, /* META_CALLOUT_STRING */ - 0, /* META_CAPTURE */ - 0, /* META_CIRCUMFLEX */ - 0, /* META_CLASS */ - 0, /* META_CLASS_EMPTY */ - 0, /* META_CLASS_EMPTY_NOT */ - 0, /* META_CLASS_END */ - 0, /* META_CLASS_NOT */ - 0, /* META_COND_ASSERT */ - SIZEOFFSET, /* META_COND_DEFINE */ - 1+SIZEOFFSET, /* META_COND_NAME */ - 1+SIZEOFFSET, /* META_COND_NUMBER */ - 1+SIZEOFFSET, /* META_COND_RNAME */ - 1+SIZEOFFSET, /* META_COND_RNUMBER */ - 3, /* META_COND_VERSION */ - 0, /* META_DOLLAR */ - 0, /* META_DOT */ - 0, /* META_ESCAPE - more for ESC_P, ESC_p, ESC_g, ESC_k */ - 0, /* META_KET */ - 0, /* META_NOCAPTURE */ - 1, /* META_OPTIONS */ - 1, /* META_POSIX */ - 1, /* META_POSIX_NEG */ - 0, /* META_RANGE_ESCAPED */ - 0, /* META_RANGE_LITERAL */ - SIZEOFFSET, /* META_RECURSE */ - 1+SIZEOFFSET, /* META_RECURSE_BYNAME */ - 0, /* META_SCRIPT_RUN */ - 0, /* META_LOOKAHEAD */ - 0, /* META_LOOKAHEADNOT */ - SIZEOFFSET, /* META_LOOKBEHIND */ - SIZEOFFSET, /* META_LOOKBEHINDNOT */ - 0, /* META_LOOKAHEAD_NA */ - SIZEOFFSET, /* META_LOOKBEHIND_NA */ - 1, /* META_MARK - plus the string length */ - 0, /* META_ACCEPT */ - 0, /* META_FAIL */ - 0, /* META_COMMIT */ - 1, /* META_COMMIT_ARG - plus the string length */ - 0, /* META_PRUNE */ - 1, /* META_PRUNE_ARG - plus the string length */ - 0, /* META_SKIP */ - 1, /* META_SKIP_ARG - plus the string length */ - 0, /* META_THEN */ - 1, /* META_THEN_ARG - plus the string length */ - 0, /* META_ASTERISK */ - 0, /* META_ASTERISK_PLUS */ - 0, /* META_ASTERISK_QUERY */ - 0, /* META_PLUS */ - 0, /* META_PLUS_PLUS */ - 0, /* META_PLUS_QUERY */ - 0, /* META_QUERY */ - 0, /* META_QUERY_PLUS */ - 0, /* META_QUERY_QUERY */ - 2, /* META_MINMAX */ - 2, /* META_MINMAX_PLUS */ - 2 /* META_MINMAX_QUERY */ -}; - -/* Types for skipping parts of a parsed pattern. */ - -enum { PSKIP_ALT, PSKIP_CLASS, PSKIP_KET }; - -/* Macro for setting individual bits in class bitmaps. It took some -experimenting to figure out how to stop gcc 5.3.0 from warning with --Wconversion. This version gets a warning: - - #define SETBIT(a,b) a[(b)/8] |= (uint8_t)(1u << ((b)&7)) - -Let's hope the apparently less efficient version isn't actually so bad if the -compiler is clever with identical subexpressions. */ - -#define SETBIT(a,b) a[(b)/8] = (uint8_t)(a[(b)/8] | (1u << ((b)&7))) - -/* Values and flags for the unsigned xxcuflags variables that accompany xxcu -variables, which are concerned with first and required code units. A value -greater than or equal to REQ_NONE means "no code unit set"; otherwise the -matching xxcu variable is set, and the low valued bits are relevant. */ - -#define REQ_UNSET 0xffffffffu /* Not yet found anything */ -#define REQ_NONE 0xfffffffeu /* Found not fixed character */ -#define REQ_CASELESS 0x00000001u /* Code unit in xxcu is caseless */ -#define REQ_VARY 0x00000002u /* Code unit is followed by non-literal */ - -/* These flags are used in the groupinfo vector. */ - -#define GI_SET_FIXED_LENGTH 0x80000000u -#define GI_NOT_FIXED_LENGTH 0x40000000u -#define GI_FIXED_LENGTH_MASK 0x0000ffffu - -/* This simple test for a decimal digit works for both ASCII/Unicode and EBCDIC -and is fast (a good compiler can turn it into a subtraction and unsigned -comparison). */ - -#define IS_DIGIT(x) ((x) >= CHAR_0 && (x) <= CHAR_9) - -/* Table to identify hex digits. The tables in chartables are dependent on the -locale, and may mark arbitrary characters as digits. We want to recognize only -0-9, a-z, and A-Z as hex digits, which is why we have a private table here. It -costs 256 bytes, but it is a lot faster than doing character value tests (at -least in some simple cases I timed), and in some applications one wants PCRE2 -to compile efficiently as well as match efficiently. The value in the table is -the binary hex digit value, or 0xff for non-hex digits. */ - -/* This is the "normal" case, for ASCII systems, and EBCDIC systems running in -UTF-8 mode. */ - -#ifndef EBCDIC -static const uint8_t xdigitab[] = - { - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 0- 7 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 8- 15 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 16- 23 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 24- 31 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* - ' */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* ( - / */ - 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, /* 0 - 7 */ - 0x08,0x09,0xff,0xff,0xff,0xff,0xff,0xff, /* 8 - ? */ - 0xff,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0xff, /* @ - G */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* H - O */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* P - W */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* X - _ */ - 0xff,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0xff, /* ` - g */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* h - o */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* p - w */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* x -127 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 128-135 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 136-143 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 144-151 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 152-159 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 160-167 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 168-175 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 176-183 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 184-191 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 192-199 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 2ff-207 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 208-215 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 216-223 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 224-231 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 232-239 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 240-247 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};/* 248-255 */ - -#else - -/* This is the "abnormal" case, for EBCDIC systems not running in UTF-8 mode. */ - -static const uint8_t xdigitab[] = - { - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 0- 7 0 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 8- 15 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 16- 23 10 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 24- 31 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 32- 39 20 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 40- 47 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 48- 55 30 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 56- 63 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* - 71 40 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 72- | */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* & - 87 50 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 88- 95 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* - -103 60 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 104- ? */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 112-119 70 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 120- " */ - 0xff,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0xff, /* 128- g 80 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* h -143 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 144- p 90 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* q -159 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 160- x A0 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* y -175 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* ^ -183 B0 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 184-191 */ - 0xff,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0xff, /* { - G C0 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* H -207 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* } - P D0 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* Q -223 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* \ - X E0 */ - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* Y -239 */ - 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, /* 0 - 7 F0 */ - 0x08,0x09,0xff,0xff,0xff,0xff,0xff,0xff};/* 8 -255 */ -#endif /* EBCDIC */ - - -/* Table for handling alphanumeric escaped characters. Positive returns are -simple data values; negative values are for special things like \d and so on. -Zero means further processing is needed (for things like \x), or the escape is -invalid. */ - -/* This is the "normal" table for ASCII systems or for EBCDIC systems running -in UTF-8 mode. It runs from '0' to 'z'. */ - -#ifndef EBCDIC -#define ESCAPES_FIRST CHAR_0 -#define ESCAPES_LAST CHAR_z -#define UPPER_CASE(c) (c-32) - -static const short int escapes[] = { - 0, 0, - 0, 0, - 0, 0, - 0, 0, - 0, 0, - CHAR_COLON, CHAR_SEMICOLON, - CHAR_LESS_THAN_SIGN, CHAR_EQUALS_SIGN, - CHAR_GREATER_THAN_SIGN, CHAR_QUESTION_MARK, - CHAR_COMMERCIAL_AT, -ESC_A, - -ESC_B, -ESC_C, - -ESC_D, -ESC_E, - 0, -ESC_G, - -ESC_H, 0, - 0, -ESC_K, - 0, 0, - -ESC_N, 0, - -ESC_P, -ESC_Q, - -ESC_R, -ESC_S, - 0, 0, - -ESC_V, -ESC_W, - -ESC_X, 0, - -ESC_Z, CHAR_LEFT_SQUARE_BRACKET, - CHAR_BACKSLASH, CHAR_RIGHT_SQUARE_BRACKET, - CHAR_CIRCUMFLEX_ACCENT, CHAR_UNDERSCORE, - CHAR_GRAVE_ACCENT, CHAR_BEL, - -ESC_b, 0, - -ESC_d, CHAR_ESC, - CHAR_FF, 0, - -ESC_h, 0, - 0, -ESC_k, - 0, 0, - CHAR_LF, 0, - -ESC_p, 0, - CHAR_CR, -ESC_s, - CHAR_HT, 0, - -ESC_v, -ESC_w, - 0, 0, - -ESC_z -}; - -#else - -/* This is the "abnormal" table for EBCDIC systems without UTF-8 support. -It runs from 'a' to '9'. For some minimal testing of EBCDIC features, the code -is sometimes compiled on an ASCII system. In this case, we must not use CHAR_a -because it is defined as 'a', which of course picks up the ASCII value. */ - -#if 'a' == 0x81 /* Check for a real EBCDIC environment */ -#define ESCAPES_FIRST CHAR_a -#define ESCAPES_LAST CHAR_9 -#define UPPER_CASE(c) (c+64) -#else /* Testing in an ASCII environment */ -#define ESCAPES_FIRST ((unsigned char)'\x81') /* EBCDIC 'a' */ -#define ESCAPES_LAST ((unsigned char)'\xf9') /* EBCDIC '9' */ -#define UPPER_CASE(c) (c-32) -#endif - -static const short int escapes[] = { -/* 80 */ CHAR_BEL, -ESC_b, 0, -ESC_d, CHAR_ESC, CHAR_FF, 0, -/* 88 */ -ESC_h, 0, 0, '{', 0, 0, 0, 0, -/* 90 */ 0, 0, -ESC_k, 0, 0, CHAR_LF, 0, -ESC_p, -/* 98 */ 0, CHAR_CR, 0, '}', 0, 0, 0, 0, -/* A0 */ 0, '~', -ESC_s, CHAR_HT, 0, -ESC_v, -ESC_w, 0, -/* A8 */ 0, -ESC_z, 0, 0, 0, '[', 0, 0, -/* B0 */ 0, 0, 0, 0, 0, 0, 0, 0, -/* B8 */ 0, 0, 0, 0, 0, ']', '=', '-', -/* C0 */ '{', -ESC_A, -ESC_B, -ESC_C, -ESC_D, -ESC_E, 0, -ESC_G, -/* C8 */ -ESC_H, 0, 0, 0, 0, 0, 0, 0, -/* D0 */ '}', 0, -ESC_K, 0, 0, -ESC_N, 0, -ESC_P, -/* D8 */ -ESC_Q, -ESC_R, 0, 0, 0, 0, 0, 0, -/* E0 */ '\\', 0, -ESC_S, 0, 0, -ESC_V, -ESC_W, -ESC_X, -/* E8 */ 0, -ESC_Z, 0, 0, 0, 0, 0, 0, -/* F0 */ 0, 0, 0, 0, 0, 0, 0, 0, -/* F8 */ 0, 0 -}; - -/* We also need a table of characters that may follow \c in an EBCDIC -environment for characters 0-31. */ - -static unsigned char ebcdic_escape_c[] = "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"; - -#endif /* EBCDIC */ - - -/* Table of special "verbs" like (*PRUNE). This is a short table, so it is -searched linearly. Put all the names into a single string, in order to reduce -the number of relocations when a shared library is dynamically linked. The -string is built from string macros so that it works in UTF-8 mode on EBCDIC -platforms. */ - -typedef struct verbitem { - unsigned int len; /* Length of verb name */ - uint32_t meta; /* Base META_ code */ - int has_arg; /* Argument requirement */ -} verbitem; - -static const char verbnames[] = - "\0" /* Empty name is a shorthand for MARK */ - STRING_MARK0 - STRING_ACCEPT0 - STRING_F0 - STRING_FAIL0 - STRING_COMMIT0 - STRING_PRUNE0 - STRING_SKIP0 - STRING_THEN; - -static const verbitem verbs[] = { - { 0, META_MARK, +1 }, /* > 0 => must have an argument */ - { 4, META_MARK, +1 }, - { 6, META_ACCEPT, -1 }, /* < 0 => Optional argument, convert to pre-MARK */ - { 1, META_FAIL, -1 }, - { 4, META_FAIL, -1 }, - { 6, META_COMMIT, 0 }, - { 5, META_PRUNE, 0 }, /* Optional argument; bump META code if found */ - { 4, META_SKIP, 0 }, - { 4, META_THEN, 0 } -}; - -static const int verbcount = sizeof(verbs)/sizeof(verbitem); - -/* Verb opcodes, indexed by their META code offset from META_MARK. */ - -static const uint32_t verbops[] = { - OP_MARK, OP_ACCEPT, OP_FAIL, OP_COMMIT, OP_COMMIT_ARG, OP_PRUNE, - OP_PRUNE_ARG, OP_SKIP, OP_SKIP_ARG, OP_THEN, OP_THEN_ARG }; - -/* Table of "alpha assertions" like (*pla:...), similar to the (*VERB) table. */ - -typedef struct alasitem { - unsigned int len; /* Length of name */ - uint32_t meta; /* Base META_ code */ -} alasitem; - -static const char alasnames[] = - STRING_pla0 - STRING_plb0 - STRING_napla0 - STRING_naplb0 - STRING_nla0 - STRING_nlb0 - STRING_positive_lookahead0 - STRING_positive_lookbehind0 - STRING_non_atomic_positive_lookahead0 - STRING_non_atomic_positive_lookbehind0 - STRING_negative_lookahead0 - STRING_negative_lookbehind0 - STRING_atomic0 - STRING_sr0 - STRING_asr0 - STRING_script_run0 - STRING_atomic_script_run; - -static const alasitem alasmeta[] = { - { 3, META_LOOKAHEAD }, - { 3, META_LOOKBEHIND }, - { 5, META_LOOKAHEAD_NA }, - { 5, META_LOOKBEHIND_NA }, - { 3, META_LOOKAHEADNOT }, - { 3, META_LOOKBEHINDNOT }, - { 18, META_LOOKAHEAD }, - { 19, META_LOOKBEHIND }, - { 29, META_LOOKAHEAD_NA }, - { 30, META_LOOKBEHIND_NA }, - { 18, META_LOOKAHEADNOT }, - { 19, META_LOOKBEHINDNOT }, - { 6, META_ATOMIC }, - { 2, META_SCRIPT_RUN }, /* sr = script run */ - { 3, META_ATOMIC_SCRIPT_RUN }, /* asr = atomic script run */ - { 10, META_SCRIPT_RUN }, /* script run */ - { 17, META_ATOMIC_SCRIPT_RUN } /* atomic script run */ -}; - -static const int alascount = sizeof(alasmeta)/sizeof(alasitem); - -/* Offsets from OP_STAR for case-independent and negative repeat opcodes. */ - -static uint32_t chartypeoffset[] = { - OP_STAR - OP_STAR, OP_STARI - OP_STAR, - OP_NOTSTAR - OP_STAR, OP_NOTSTARI - OP_STAR }; - -/* Tables of names of POSIX character classes and their lengths. The names are -now all in a single string, to reduce the number of relocations when a shared -library is dynamically loaded. The list of lengths is terminated by a zero -length entry. The first three must be alpha, lower, upper, as this is assumed -for handling case independence. The indices for graph, print, and punct are -needed, so identify them. */ - -static const char posix_names[] = - STRING_alpha0 STRING_lower0 STRING_upper0 STRING_alnum0 - STRING_ascii0 STRING_blank0 STRING_cntrl0 STRING_digit0 - STRING_graph0 STRING_print0 STRING_punct0 STRING_space0 - STRING_word0 STRING_xdigit; - -static const uint8_t posix_name_lengths[] = { - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 6, 0 }; - -#define PC_GRAPH 8 -#define PC_PRINT 9 -#define PC_PUNCT 10 - -/* Table of class bit maps for each POSIX class. Each class is formed from a -base map, with an optional addition or removal of another map. Then, for some -classes, there is some additional tweaking: for [:blank:] the vertical space -characters are removed, and for [:alpha:] and [:alnum:] the underscore -character is removed. The triples in the table consist of the base map offset, -second map offset or -1 if no second map, and a non-negative value for map -addition or a negative value for map subtraction (if there are two maps). The -absolute value of the third field has these meanings: 0 => no tweaking, 1 => -remove vertical space characters, 2 => remove underscore. */ - -static const int posix_class_maps[] = { - cbit_word, cbit_digit, -2, /* alpha */ - cbit_lower, -1, 0, /* lower */ - cbit_upper, -1, 0, /* upper */ - cbit_word, -1, 2, /* alnum - word without underscore */ - cbit_print, cbit_cntrl, 0, /* ascii */ - cbit_space, -1, 1, /* blank - a GNU extension */ - cbit_cntrl, -1, 0, /* cntrl */ - cbit_digit, -1, 0, /* digit */ - cbit_graph, -1, 0, /* graph */ - cbit_print, -1, 0, /* print */ - cbit_punct, -1, 0, /* punct */ - cbit_space, -1, 0, /* space */ - cbit_word, -1, 0, /* word - a Perl extension */ - cbit_xdigit,-1, 0 /* xdigit */ -}; - -#ifdef SUPPORT_UNICODE - -/* The POSIX class Unicode property substitutes that are used in UCP mode must -be in the order of the POSIX class names, defined above. */ - -static int posix_substitutes[] = { - PT_GC, ucp_L, /* alpha */ - PT_PC, ucp_Ll, /* lower */ - PT_PC, ucp_Lu, /* upper */ - PT_ALNUM, 0, /* alnum */ - -1, 0, /* ascii, treat as non-UCP */ - -1, 1, /* blank, treat as \h */ - PT_PC, ucp_Cc, /* cntrl */ - PT_PC, ucp_Nd, /* digit */ - PT_PXGRAPH, 0, /* graph */ - PT_PXPRINT, 0, /* print */ - PT_PXPUNCT, 0, /* punct */ - PT_PXSPACE, 0, /* space */ /* Xps is POSIX space, but from 8.34 */ - PT_WORD, 0, /* word */ /* Perl and POSIX space are the same */ - -1, 0 /* xdigit, treat as non-UCP */ -}; -#define POSIX_SUBSIZE (sizeof(posix_substitutes) / (2*sizeof(uint32_t))) -#endif /* SUPPORT_UNICODE */ - -/* Masks for checking option settings. When PCRE2_LITERAL is set, only a subset -are allowed. */ - -#define PUBLIC_LITERAL_COMPILE_OPTIONS \ - (PCRE2_ANCHORED|PCRE2_AUTO_CALLOUT|PCRE2_CASELESS|PCRE2_ENDANCHORED| \ - PCRE2_FIRSTLINE|PCRE2_LITERAL|PCRE2_MATCH_INVALID_UTF| \ - PCRE2_NO_START_OPTIMIZE|PCRE2_NO_UTF_CHECK|PCRE2_USE_OFFSET_LIMIT|PCRE2_UTF) - -#define PUBLIC_COMPILE_OPTIONS \ - (PUBLIC_LITERAL_COMPILE_OPTIONS| \ - PCRE2_ALLOW_EMPTY_CLASS|PCRE2_ALT_BSUX|PCRE2_ALT_CIRCUMFLEX| \ - PCRE2_ALT_VERBNAMES|PCRE2_DOLLAR_ENDONLY|PCRE2_DOTALL|PCRE2_DUPNAMES| \ - PCRE2_EXTENDED|PCRE2_EXTENDED_MORE|PCRE2_MATCH_UNSET_BACKREF| \ - PCRE2_MULTILINE|PCRE2_NEVER_BACKSLASH_C|PCRE2_NEVER_UCP| \ - PCRE2_NEVER_UTF|PCRE2_NO_AUTO_CAPTURE|PCRE2_NO_AUTO_POSSESS| \ - PCRE2_NO_DOTSTAR_ANCHOR|PCRE2_UCP|PCRE2_UNGREEDY) - -#define PUBLIC_LITERAL_COMPILE_EXTRA_OPTIONS \ - (PCRE2_EXTRA_MATCH_LINE|PCRE2_EXTRA_MATCH_WORD) - -#define PUBLIC_COMPILE_EXTRA_OPTIONS \ - (PUBLIC_LITERAL_COMPILE_EXTRA_OPTIONS| \ - PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES|PCRE2_EXTRA_BAD_ESCAPE_IS_LITERAL| \ - PCRE2_EXTRA_ESCAPED_CR_IS_LF|PCRE2_EXTRA_ALT_BSUX| \ - PCRE2_EXTRA_ALLOW_LOOKAROUND_BSK) - -/* Compile time error code numbers. They are given names so that they can more -easily be tracked. When a new number is added, the tables called eint1 and -eint2 in pcre2posix.c may need to be updated, and a new error text must be -added to compile_error_texts in pcre2_error.c. Also, the error codes in -pcre2.h.in must be updated - their values are exactly 100 greater than these -values. */ - -enum { ERR0 = COMPILE_ERROR_BASE, - ERR1, ERR2, ERR3, ERR4, ERR5, ERR6, ERR7, ERR8, ERR9, ERR10, - ERR11, ERR12, ERR13, ERR14, ERR15, ERR16, ERR17, ERR18, ERR19, ERR20, - ERR21, ERR22, ERR23, ERR24, ERR25, ERR26, ERR27, ERR28, ERR29, ERR30, - ERR31, ERR32, ERR33, ERR34, ERR35, ERR36, ERR37, ERR38, ERR39, ERR40, - ERR41, ERR42, ERR43, ERR44, ERR45, ERR46, ERR47, ERR48, ERR49, ERR50, - ERR51, ERR52, ERR53, ERR54, ERR55, ERR56, ERR57, ERR58, ERR59, ERR60, - ERR61, ERR62, ERR63, ERR64, ERR65, ERR66, ERR67, ERR68, ERR69, ERR70, - ERR71, ERR72, ERR73, ERR74, ERR75, ERR76, ERR77, ERR78, ERR79, ERR80, - ERR81, ERR82, ERR83, ERR84, ERR85, ERR86, ERR87, ERR88, ERR89, ERR90, - ERR91, ERR92, ERR93, ERR94, ERR95, ERR96, ERR97, ERR98, ERR99 }; - -/* 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 -compatibility, (*UTFn) is supported in the relevant libraries, but (*UTF) is -generic and always supported. */ - -enum { PSO_OPT, /* Value is an option bit */ - PSO_FLG, /* Value is a flag bit */ - PSO_NL, /* Value is a newline type */ - PSO_BSR, /* Value is a \R type */ - PSO_LIMH, /* Read integer value for heap limit */ - PSO_LIMM, /* Read integer value for match limit */ - PSO_LIMD }; /* Read integer value for depth limit */ - -typedef struct pso { - const uint8_t *name; - uint16_t length; - uint16_t type; - uint32_t value; -} pso; - -/* NB: STRING_UTFn_RIGHTPAR contains the length as well */ - -static pso pso_list[] = { - { (uint8_t *)STRING_UTFn_RIGHTPAR, PSO_OPT, PCRE2_UTF }, - { (uint8_t *)STRING_UTF_RIGHTPAR, 4, PSO_OPT, PCRE2_UTF }, - { (uint8_t *)STRING_UCP_RIGHTPAR, 4, PSO_OPT, PCRE2_UCP }, - { (uint8_t *)STRING_NOTEMPTY_RIGHTPAR, 9, PSO_FLG, PCRE2_NOTEMPTY_SET }, - { (uint8_t *)STRING_NOTEMPTY_ATSTART_RIGHTPAR, 17, PSO_FLG, PCRE2_NE_ATST_SET }, - { (uint8_t *)STRING_NO_AUTO_POSSESS_RIGHTPAR, 16, PSO_OPT, PCRE2_NO_AUTO_POSSESS }, - { (uint8_t *)STRING_NO_DOTSTAR_ANCHOR_RIGHTPAR, 18, PSO_OPT, PCRE2_NO_DOTSTAR_ANCHOR }, - { (uint8_t *)STRING_NO_JIT_RIGHTPAR, 7, PSO_FLG, PCRE2_NOJIT }, - { (uint8_t *)STRING_NO_START_OPT_RIGHTPAR, 13, PSO_OPT, PCRE2_NO_START_OPTIMIZE }, - { (uint8_t *)STRING_LIMIT_HEAP_EQ, 11, PSO_LIMH, 0 }, - { (uint8_t *)STRING_LIMIT_MATCH_EQ, 12, PSO_LIMM, 0 }, - { (uint8_t *)STRING_LIMIT_DEPTH_EQ, 12, PSO_LIMD, 0 }, - { (uint8_t *)STRING_LIMIT_RECURSION_EQ, 16, PSO_LIMD, 0 }, - { (uint8_t *)STRING_CR_RIGHTPAR, 3, PSO_NL, PCRE2_NEWLINE_CR }, - { (uint8_t *)STRING_LF_RIGHTPAR, 3, PSO_NL, PCRE2_NEWLINE_LF }, - { (uint8_t *)STRING_CRLF_RIGHTPAR, 5, PSO_NL, PCRE2_NEWLINE_CRLF }, - { (uint8_t *)STRING_ANY_RIGHTPAR, 4, PSO_NL, PCRE2_NEWLINE_ANY }, - { (uint8_t *)STRING_NUL_RIGHTPAR, 4, PSO_NL, PCRE2_NEWLINE_NUL }, - { (uint8_t *)STRING_ANYCRLF_RIGHTPAR, 8, PSO_NL, PCRE2_NEWLINE_ANYCRLF }, - { (uint8_t *)STRING_BSR_ANYCRLF_RIGHTPAR, 12, PSO_BSR, PCRE2_BSR_ANYCRLF }, - { (uint8_t *)STRING_BSR_UNICODE_RIGHTPAR, 12, PSO_BSR, PCRE2_BSR_UNICODE } -}; - -/* This table is used when converting repeating opcodes into possessified -versions as a result of an explicit possessive quantifier such as ++. A zero -value means there is no possessified version - in those cases the item in -question must be wrapped in ONCE brackets. The table is truncated at OP_CALLOUT -because all relevant opcodes are less than that. */ - -static const uint8_t opcode_possessify[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0 - 15 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16 - 31 */ - - 0, /* NOTI */ - OP_POSSTAR, 0, /* STAR, MINSTAR */ - OP_POSPLUS, 0, /* PLUS, MINPLUS */ - OP_POSQUERY, 0, /* QUERY, MINQUERY */ - OP_POSUPTO, 0, /* UPTO, MINUPTO */ - 0, /* EXACT */ - 0, 0, 0, 0, /* POS{STAR,PLUS,QUERY,UPTO} */ - - OP_POSSTARI, 0, /* STARI, MINSTARI */ - OP_POSPLUSI, 0, /* PLUSI, MINPLUSI */ - OP_POSQUERYI, 0, /* QUERYI, MINQUERYI */ - OP_POSUPTOI, 0, /* UPTOI, MINUPTOI */ - 0, /* EXACTI */ - 0, 0, 0, 0, /* POS{STARI,PLUSI,QUERYI,UPTOI} */ - - OP_NOTPOSSTAR, 0, /* NOTSTAR, NOTMINSTAR */ - OP_NOTPOSPLUS, 0, /* NOTPLUS, NOTMINPLUS */ - OP_NOTPOSQUERY, 0, /* NOTQUERY, NOTMINQUERY */ - OP_NOTPOSUPTO, 0, /* NOTUPTO, NOTMINUPTO */ - 0, /* NOTEXACT */ - 0, 0, 0, 0, /* NOTPOS{STAR,PLUS,QUERY,UPTO} */ - - OP_NOTPOSSTARI, 0, /* NOTSTARI, NOTMINSTARI */ - OP_NOTPOSPLUSI, 0, /* NOTPLUSI, NOTMINPLUSI */ - OP_NOTPOSQUERYI, 0, /* NOTQUERYI, NOTMINQUERYI */ - OP_NOTPOSUPTOI, 0, /* NOTUPTOI, NOTMINUPTOI */ - 0, /* NOTEXACTI */ - 0, 0, 0, 0, /* NOTPOS{STARI,PLUSI,QUERYI,UPTOI} */ - - OP_TYPEPOSSTAR, 0, /* TYPESTAR, TYPEMINSTAR */ - OP_TYPEPOSPLUS, 0, /* TYPEPLUS, TYPEMINPLUS */ - OP_TYPEPOSQUERY, 0, /* TYPEQUERY, TYPEMINQUERY */ - OP_TYPEPOSUPTO, 0, /* TYPEUPTO, TYPEMINUPTO */ - 0, /* TYPEEXACT */ - 0, 0, 0, 0, /* TYPEPOS{STAR,PLUS,QUERY,UPTO} */ - - OP_CRPOSSTAR, 0, /* CRSTAR, CRMINSTAR */ - OP_CRPOSPLUS, 0, /* CRPLUS, CRMINPLUS */ - OP_CRPOSQUERY, 0, /* CRQUERY, CRMINQUERY */ - OP_CRPOSRANGE, 0, /* CRRANGE, CRMINRANGE */ - 0, 0, 0, 0, /* CRPOS{STAR,PLUS,QUERY,RANGE} */ - - 0, 0, 0, /* CLASS, NCLASS, XCLASS */ - 0, 0, /* REF, REFI */ - 0, 0, /* DNREF, DNREFI */ - 0, 0 /* RECURSE, CALLOUT */ -}; - - -#ifdef DEBUG_SHOW_PARSED -/************************************************* -* Show the parsed pattern for debugging * -*************************************************/ - -/* For debugging the pre-scan, this code, which outputs the parsed data vector, -can be enabled. */ - -static void show_parsed(compile_block *cb) -{ -uint32_t *pptr = cb->parsed_pattern; - -for (;;) - { - int max, min; - PCRE2_SIZE offset; - uint32_t i; - uint32_t length; - uint32_t meta_arg = META_DATA(*pptr); - - fprintf(stderr, "+++ %02d %.8x ", (int)(pptr - cb->parsed_pattern), *pptr); - - if (*pptr < META_END) - { - if (*pptr > 32 && *pptr < 128) fprintf(stderr, "%c", *pptr); - pptr++; - } - - else switch (META_CODE(*pptr++)) - { - default: - fprintf(stderr, "**** OOPS - unknown META value - giving up ****\n"); - return; - - case META_END: - fprintf(stderr, "META_END\n"); - return; - - case META_CAPTURE: - fprintf(stderr, "META_CAPTURE %d", meta_arg); - break; - - case META_RECURSE: - GETOFFSET(offset, pptr); - fprintf(stderr, "META_RECURSE %d %zd", meta_arg, offset); - break; - - case META_BACKREF: - if (meta_arg < 10) - offset = cb->small_ref_offset[meta_arg]; - else - GETOFFSET(offset, pptr); - fprintf(stderr, "META_BACKREF %d %zd", meta_arg, offset); - break; - - case META_ESCAPE: - if (meta_arg == ESC_P || meta_arg == ESC_p) - { - uint32_t ptype = *pptr >> 16; - uint32_t pvalue = *pptr++ & 0xffff; - fprintf(stderr, "META \\%c %d %d", (meta_arg == ESC_P)? 'P':'p', - ptype, pvalue); - } - else - { - uint32_t cc; - /* There's just one escape we might have here that isn't negated in the - escapes table. */ - if (meta_arg == ESC_g) cc = CHAR_g; - else for (cc = ESCAPES_FIRST; cc <= ESCAPES_LAST; cc++) - { - if (meta_arg == (uint32_t)(-escapes[cc - ESCAPES_FIRST])) break; - } - if (cc > ESCAPES_LAST) cc = CHAR_QUESTION_MARK; - fprintf(stderr, "META \\%c", cc); - } - break; - - case META_MINMAX: - min = *pptr++; - max = *pptr++; - if (max != REPEAT_UNLIMITED) - fprintf(stderr, "META {%d,%d}", min, max); - else - fprintf(stderr, "META {%d,}", min); - break; - - case META_MINMAX_QUERY: - min = *pptr++; - max = *pptr++; - if (max != REPEAT_UNLIMITED) - fprintf(stderr, "META {%d,%d}?", min, max); - else - fprintf(stderr, "META {%d,}?", min); - break; - - case META_MINMAX_PLUS: - min = *pptr++; - max = *pptr++; - if (max != REPEAT_UNLIMITED) - fprintf(stderr, "META {%d,%d}+", min, max); - else - fprintf(stderr, "META {%d,}+", min); - break; - - case META_BIGVALUE: fprintf(stderr, "META_BIGVALUE %.8x", *pptr++); break; - case META_CIRCUMFLEX: fprintf(stderr, "META_CIRCUMFLEX"); break; - case META_COND_ASSERT: fprintf(stderr, "META_COND_ASSERT"); break; - case META_DOLLAR: fprintf(stderr, "META_DOLLAR"); break; - case META_DOT: fprintf(stderr, "META_DOT"); break; - case META_ASTERISK: fprintf(stderr, "META *"); break; - case META_ASTERISK_QUERY: fprintf(stderr, "META *?"); break; - case META_ASTERISK_PLUS: fprintf(stderr, "META *+"); break; - case META_PLUS: fprintf(stderr, "META +"); break; - case META_PLUS_QUERY: fprintf(stderr, "META +?"); break; - case META_PLUS_PLUS: fprintf(stderr, "META ++"); break; - case META_QUERY: fprintf(stderr, "META ?"); break; - case META_QUERY_QUERY: fprintf(stderr, "META ??"); break; - case META_QUERY_PLUS: fprintf(stderr, "META ?+"); break; - - case META_ATOMIC: fprintf(stderr, "META (?>"); break; - case META_NOCAPTURE: fprintf(stderr, "META (?:"); break; - case META_LOOKAHEAD: fprintf(stderr, "META (?="); break; - case META_LOOKAHEADNOT: fprintf(stderr, "META (?!"); break; - case META_LOOKAHEAD_NA: fprintf(stderr, "META (*napla:"); break; - case META_SCRIPT_RUN: fprintf(stderr, "META (*sr:"); break; - case META_KET: fprintf(stderr, "META )"); break; - case META_ALT: fprintf(stderr, "META | %d", meta_arg); break; - - case META_CLASS: fprintf(stderr, "META ["); break; - case META_CLASS_NOT: fprintf(stderr, "META [^"); break; - case META_CLASS_END: fprintf(stderr, "META ]"); break; - case META_CLASS_EMPTY: fprintf(stderr, "META []"); break; - case META_CLASS_EMPTY_NOT: fprintf(stderr, "META [^]"); break; - - case META_RANGE_LITERAL: fprintf(stderr, "META - (literal)"); break; - case META_RANGE_ESCAPED: fprintf(stderr, "META - (escaped)"); break; - - case META_POSIX: fprintf(stderr, "META_POSIX %d", *pptr++); break; - case META_POSIX_NEG: fprintf(stderr, "META_POSIX_NEG %d", *pptr++); break; - - case META_ACCEPT: fprintf(stderr, "META (*ACCEPT)"); break; - case META_FAIL: fprintf(stderr, "META (*FAIL)"); break; - case META_COMMIT: fprintf(stderr, "META (*COMMIT)"); break; - case META_PRUNE: fprintf(stderr, "META (*PRUNE)"); break; - case META_SKIP: fprintf(stderr, "META (*SKIP)"); break; - case META_THEN: fprintf(stderr, "META (*THEN)"); break; - - case META_OPTIONS: fprintf(stderr, "META_OPTIONS 0x%02x", *pptr++); break; - - case META_LOOKBEHIND: - fprintf(stderr, "META (?<= %d offset=", meta_arg); - GETOFFSET(offset, pptr); - fprintf(stderr, "%zd", offset); - break; - - case META_LOOKBEHIND_NA: - fprintf(stderr, "META (*naplb: %d offset=", meta_arg); - GETOFFSET(offset, pptr); - fprintf(stderr, "%zd", offset); - break; - - case META_LOOKBEHINDNOT: - fprintf(stderr, "META (?="); - fprintf(stderr, "%d.", *pptr++); - fprintf(stderr, "%d)", *pptr++); - break; - - case META_COND_NAME: - fprintf(stderr, "META (?() length=%d offset=", *pptr++); - GETOFFSET(offset, pptr); - fprintf(stderr, "%zd", offset); - break; - - case META_COND_RNAME: - fprintf(stderr, "META (?(R&name) length=%d offset=", *pptr++); - GETOFFSET(offset, pptr); - fprintf(stderr, "%zd", offset); - break; - - /* This is kept as a name, because it might be. */ - - case META_COND_RNUMBER: - fprintf(stderr, "META (?(Rnumber) length=%d offset=", *pptr++); - GETOFFSET(offset, pptr); - fprintf(stderr, "%zd", offset); - break; - - case META_MARK: - fprintf(stderr, "META (*MARK:"); - goto SHOWARG; - - case META_COMMIT_ARG: - fprintf(stderr, "META (*COMMIT:"); - goto SHOWARG; - - case META_PRUNE_ARG: - fprintf(stderr, "META (*PRUNE:"); - goto SHOWARG; - - case META_SKIP_ARG: - fprintf(stderr, "META (*SKIP:"); - goto SHOWARG; - - case META_THEN_ARG: - fprintf(stderr, "META (*THEN:"); - SHOWARG: - length = *pptr++; - for (i = 0; i < length; i++) - { - uint32_t cc = *pptr++; - if (cc > 32 && cc < 128) fprintf(stderr, "%c", cc); - else fprintf(stderr, "\\x{%x}", cc); - } - fprintf(stderr, ") length=%u", length); - break; - } - fprintf(stderr, "\n"); - } -return; -} -#endif /* DEBUG_SHOW_PARSED */ - - - -/************************************************* -* Copy compiled code * -*************************************************/ - -/* Compiled JIT code cannot be copied, so the new compiled block has no -associated JIT data. */ - -PCRE2_EXP_DEFN pcre2_code * PCRE2_CALL_CONVENTION -pcre2_code_copy(const pcre2_code *code) -{ -PCRE2_SIZE* ref_count; -pcre2_code *newcode; - -if (code == NULL) return NULL; -newcode = code->memctl.malloc(code->blocksize, code->memctl.memory_data); -if (newcode == NULL) return NULL; -memcpy(newcode, code, code->blocksize); -newcode->executable_jit = NULL; - -/* If the code is one that has been deserialized, increment the reference count -in the decoded tables. */ - -if ((code->flags & PCRE2_DEREF_TABLES) != 0) - { - ref_count = (PCRE2_SIZE *)(code->tables + TABLES_LENGTH); - (*ref_count)++; - } - -return newcode; -} - - - -/************************************************* -* Copy compiled code and character tables * -*************************************************/ - -/* Compiled JIT code cannot be copied, so the new compiled block has no -associated JIT data. This version of code_copy also makes a separate copy of -the character tables. */ - -PCRE2_EXP_DEFN pcre2_code * PCRE2_CALL_CONVENTION -pcre2_code_copy_with_tables(const pcre2_code *code) -{ -PCRE2_SIZE* ref_count; -pcre2_code *newcode; -uint8_t *newtables; - -if (code == NULL) return NULL; -newcode = code->memctl.malloc(code->blocksize, code->memctl.memory_data); -if (newcode == NULL) return NULL; -memcpy(newcode, code, code->blocksize); -newcode->executable_jit = NULL; - -newtables = code->memctl.malloc(TABLES_LENGTH + sizeof(PCRE2_SIZE), - code->memctl.memory_data); -if (newtables == NULL) - { - code->memctl.free((void *)newcode, code->memctl.memory_data); - return NULL; - } -memcpy(newtables, code->tables, TABLES_LENGTH); -ref_count = (PCRE2_SIZE *)(newtables + TABLES_LENGTH); -*ref_count = 1; - -newcode->tables = newtables; -newcode->flags |= PCRE2_DEREF_TABLES; -return newcode; -} - - - -/************************************************* -* Free compiled code * -*************************************************/ - -PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION -pcre2_code_free(pcre2_code *code) -{ -PCRE2_SIZE* ref_count; - -if (code != NULL) - { -#ifdef SUPPORT_JIT - if (code->executable_jit != NULL) - PRIV(jit_free)(code->executable_jit, &code->memctl); -#endif - - if ((code->flags & PCRE2_DEREF_TABLES) != 0) - { - /* Decoded tables belong to the codes after deserialization, and they must - be freed when there are no more references to them. The *ref_count should - always be > 0. */ - - ref_count = (PCRE2_SIZE *)(code->tables + TABLES_LENGTH); - if (*ref_count > 0) - { - (*ref_count)--; - if (*ref_count == 0) - code->memctl.free((void *)code->tables, code->memctl.memory_data); - } - } - - code->memctl.free(code, code->memctl.memory_data); - } -} - - - -/************************************************* -* Read a number, possibly signed * -*************************************************/ - -/* This function is used to read numbers in the pattern. The initial pointer -must be the sign or first digit of the number. When relative values (introduced -by + or -) are allowed, they are relative group numbers, and the result must be -greater than zero. - -Arguments: - ptrptr points to the character pointer variable - ptrend points to the end of the input string - allow_sign if < 0, sign not allowed; if >= 0, sign is relative to this - max_value the largest number allowed - max_error the error to give for an over-large number - intptr where to put the result - errcodeptr where to put an error code - -Returns: TRUE - a number was read - FALSE - errorcode == 0 => no number was found - errorcode != 0 => an error occurred -*/ - -static BOOL -read_number(PCRE2_SPTR *ptrptr, PCRE2_SPTR ptrend, int32_t allow_sign, - uint32_t max_value, uint32_t max_error, int *intptr, int *errorcodeptr) -{ -int sign = 0; -uint32_t n = 0; -PCRE2_SPTR ptr = *ptrptr; -BOOL yield = FALSE; - -*errorcodeptr = 0; - -if (allow_sign >= 0 && ptr < ptrend) - { - if (*ptr == CHAR_PLUS) - { - sign = +1; - max_value -= allow_sign; - ptr++; - } - else if (*ptr == CHAR_MINUS) - { - sign = -1; - ptr++; - } - } - -if (ptr >= ptrend || !IS_DIGIT(*ptr)) return FALSE; -while (ptr < ptrend && IS_DIGIT(*ptr)) - { - n = n * 10 + *ptr++ - CHAR_0; - if (n > max_value) - { - *errorcodeptr = max_error; - goto EXIT; - } - } - -if (allow_sign >= 0 && sign != 0) - { - if (n == 0) - { - *errorcodeptr = ERR26; /* +0 and -0 are not allowed */ - goto EXIT; - } - - if (sign > 0) n += allow_sign; - else if ((int)n > allow_sign) - { - *errorcodeptr = ERR15; /* Non-existent subpattern */ - goto EXIT; - } - else n = allow_sign + 1 - n; - } - -yield = TRUE; - -EXIT: -*intptr = n; -*ptrptr = ptr; -return yield; -} - - - -/************************************************* -* Read repeat counts * -*************************************************/ - -/* Read an item of the form {n,m} and return the values if non-NULL pointers -are supplied. Repeat counts must be less than 65536 (MAX_REPEAT_COUNT); a -larger value is used for "unlimited". We have to use signed arguments for -read_number() because it is capable of returning a signed value. - -Arguments: - ptrptr points to pointer to character after'{' - ptrend pointer to end of input - minp if not NULL, pointer to int for min - maxp if not NULL, pointer to int for max (-1 if no max) - returned as -1 if no max - errorcodeptr points to error code variable - -Returns: FALSE if not a repeat quantifier, errorcode set zero - FALSE on error, with errorcode set non-zero - TRUE on success, with pointer updated to point after '}' -*/ - -static BOOL -read_repeat_counts(PCRE2_SPTR *ptrptr, PCRE2_SPTR ptrend, uint32_t *minp, - uint32_t *maxp, int *errorcodeptr) -{ -PCRE2_SPTR p; -BOOL yield = FALSE; -BOOL had_comma = FALSE; -int32_t min = 0; -int32_t max = REPEAT_UNLIMITED; /* This value is larger than MAX_REPEAT_COUNT */ - -/* Check the syntax */ - -*errorcodeptr = 0; -for (p = *ptrptr;; p++) - { - uint32_t c; - if (p >= ptrend) return FALSE; - c = *p; - if (IS_DIGIT(c)) continue; - if (c == CHAR_RIGHT_CURLY_BRACKET) break; - if (c == CHAR_COMMA) - { - if (had_comma) return FALSE; - had_comma = TRUE; - } - else return FALSE; - } - -/* The only error from read_number() is for a number that is too big. */ - -p = *ptrptr; -if (!read_number(&p, ptrend, -1, MAX_REPEAT_COUNT, ERR5, &min, errorcodeptr)) - goto EXIT; - -if (*p == CHAR_RIGHT_CURLY_BRACKET) - { - p++; - max = min; - } -else - { - if (*(++p) != CHAR_RIGHT_CURLY_BRACKET) - { - if (!read_number(&p, ptrend, -1, MAX_REPEAT_COUNT, ERR5, &max, - errorcodeptr)) - goto EXIT; - if (max < min) - { - *errorcodeptr = ERR4; - goto EXIT; - } - } - p++; - } - -yield = TRUE; -if (minp != NULL) *minp = (uint32_t)min; -if (maxp != NULL) *maxp = (uint32_t)max; - -/* Update the pattern pointer */ - -EXIT: -*ptrptr = p; -return yield; -} - - - -/************************************************* -* Handle escapes * -*************************************************/ - -/* This function is called when a \ has been encountered. It either returns a -positive value for a simple escape such as \d, or 0 for a data character, which -is placed in chptr. A backreference to group n is returned as negative n. On -entry, ptr is pointing at the character after \. On exit, it points after the -final code unit of the escape sequence. - -This function is also called from pcre2_substitute() to handle escape sequences -in replacement strings. In this case, the cb argument is NULL, and in the case -of escapes that have further processing, only sequences that define a data -character are recognised. The isclass argument is not relevant; the options -argument is the final value of the compiled pattern's options. - -Arguments: - ptrptr points to the input position pointer - ptrend points to the end of the input - chptr points to a returned data character - errorcodeptr points to the errorcode variable (containing zero) - options the current options bits - isclass TRUE if inside a character class - cb compile data block or NULL when called from pcre2_substitute() - -Returns: zero => a data character - positive => a special escape sequence - negative => a numerical back reference - on error, errorcodeptr is set non-zero -*/ - -int -PRIV(check_escape)(PCRE2_SPTR *ptrptr, PCRE2_SPTR ptrend, uint32_t *chptr, - int *errorcodeptr, uint32_t options, uint32_t extra_options, BOOL isclass, - compile_block *cb) -{ -BOOL utf = (options & PCRE2_UTF) != 0; -PCRE2_SPTR ptr = *ptrptr; -uint32_t c, cc; -int escape = 0; -int i; - -/* If backslash is at the end of the string, it's an error. */ - -if (ptr >= ptrend) - { - *errorcodeptr = ERR1; - return 0; - } - -GETCHARINCTEST(c, ptr); /* Get character value, increment pointer */ -*errorcodeptr = 0; /* Be optimistic */ - -/* Non-alphanumerics are literals, so we just leave the value in c. An initial -value test saves a memory lookup for code points outside the alphanumeric -range. */ - -if (c < ESCAPES_FIRST || c > ESCAPES_LAST) {} /* Definitely literal */ - -/* Otherwise, do a table lookup. Non-zero values need little processing here. A -positive value is a literal value for something like \n. A negative value is -the negation of one of the ESC_ macros that is passed back for handling by the -calling function. Some extra checking is needed for \N because only \N{U+dddd} -is supported. If the value is zero, further processing is handled below. */ - -else if ((i = escapes[c - ESCAPES_FIRST]) != 0) - { - if (i > 0) - { - c = (uint32_t)i; - if (c == CHAR_CR && (extra_options & PCRE2_EXTRA_ESCAPED_CR_IS_LF) != 0) - c = CHAR_LF; - } - else /* Negative table entry */ - { - escape = -i; /* Else return a special escape */ - if (cb != NULL && (escape == ESC_P || escape == ESC_p || escape == ESC_X)) - cb->external_flags |= PCRE2_HASBKPORX; /* Note \P, \p, or \X */ - - /* Perl supports \N{name} for character names and \N{U+dddd} for numerical - Unicode code points, as well as plain \N for "not newline". PCRE does not - support \N{name}. However, it does support quantification such as \N{2,3}, - so if \N{ is not followed by U+dddd we check for a quantifier. */ - - if (escape == ESC_N && ptr < ptrend && *ptr == CHAR_LEFT_CURLY_BRACKET) - { - PCRE2_SPTR p = ptr + 1; - - /* \N{U+ can be handled by the \x{ code. However, this construction is - not valid in EBCDIC environments because it specifies a Unicode - character, not a codepoint in the local code. For example \N{U+0041} - must be "A" in all environments. Also, in Perl, \N{U+ forces Unicode - casing semantics for the entire pattern, so allow it only in UTF (i.e. - Unicode) mode. */ - - if (ptrend - p > 1 && *p == CHAR_U && p[1] == CHAR_PLUS) - { -#ifdef EBCDIC - *errorcodeptr = ERR93; -#else - if (utf) - { - ptr = p + 1; - escape = 0; /* Not a fancy escape after all */ - goto COME_FROM_NU; - } - else *errorcodeptr = ERR93; -#endif - } - - /* Give an error if what follows is not a quantifier, but don't override - an error set by the quantifier reader (e.g. number overflow). */ - - else - { - if (!read_repeat_counts(&p, ptrend, NULL, NULL, errorcodeptr) && - *errorcodeptr == 0) - *errorcodeptr = ERR37; - } - } - } - } - -/* Escapes that need further processing, including those that are unknown, have -a zero entry in the lookup table. When called from pcre2_substitute(), only \c, -\o, and \x are recognized (\u and \U can never appear as they are used for case -forcing). */ - -else - { - int s; - PCRE2_SPTR oldptr; - BOOL overflow; - BOOL alt_bsux = - ((options & PCRE2_ALT_BSUX) | (extra_options & PCRE2_EXTRA_ALT_BSUX)) != 0; - - /* Filter calls from pcre2_substitute(). */ - - if (cb == NULL) - { - if (c != CHAR_c && c != CHAR_o && c != CHAR_x) - { - *errorcodeptr = ERR3; - return 0; - } - alt_bsux = FALSE; /* Do not modify \x handling */ - } - - switch (c) - { - /* A number of Perl escapes are not handled by PCRE. We give an explicit - error. */ - - case CHAR_F: - case CHAR_l: - case CHAR_L: - *errorcodeptr = ERR37; - break; - - /* \u is unrecognized when neither PCRE2_ALT_BSUX nor PCRE2_EXTRA_ALT_BSUX - is set. Otherwise, \u must be followed by exactly four hex digits or, if - PCRE2_EXTRA_ALT_BSUX is set, by any number of hex digits in braces. - Otherwise it is a lowercase u letter. This gives some compatibility with - ECMAScript (aka JavaScript). */ - - case CHAR_u: - if (!alt_bsux) *errorcodeptr = ERR37; else - { - uint32_t xc; - - if (ptr >= ptrend) break; - if (*ptr == CHAR_LEFT_CURLY_BRACKET && - (extra_options & PCRE2_EXTRA_ALT_BSUX) != 0) - { - PCRE2_SPTR hptr = ptr + 1; - cc = 0; - - while (hptr < ptrend && (xc = XDIGIT(*hptr)) != 0xff) - { - if ((cc & 0xf0000000) != 0) /* Test for 32-bit overflow */ - { - *errorcodeptr = ERR77; - ptr = hptr; /* Show where */ - break; /* *hptr != } will cause another break below */ - } - cc = (cc << 4) | xc; - hptr++; - } - - if (hptr == ptr + 1 || /* No hex digits */ - hptr >= ptrend || /* Hit end of input */ - *hptr != CHAR_RIGHT_CURLY_BRACKET) /* No } terminator */ - break; /* Hex escape not recognized */ - - c = cc; /* Accept the code point */ - ptr = hptr + 1; - } - - else /* Must be exactly 4 hex digits */ - { - if (ptrend - ptr < 4) break; /* Less than 4 chars */ - if ((cc = XDIGIT(ptr[0])) == 0xff) break; /* Not a hex digit */ - if ((xc = XDIGIT(ptr[1])) == 0xff) break; /* Not a hex digit */ - cc = (cc << 4) | xc; - if ((xc = XDIGIT(ptr[2])) == 0xff) break; /* Not a hex digit */ - cc = (cc << 4) | xc; - if ((xc = XDIGIT(ptr[3])) == 0xff) break; /* Not a hex digit */ - c = (cc << 4) | xc; - ptr += 4; - } - - if (utf) - { - if (c > 0x10ffffU) *errorcodeptr = ERR77; - else - if (c >= 0xd800 && c <= 0xdfff && - (extra_options & PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES) == 0) - *errorcodeptr = ERR73; - } - else if (c > MAX_NON_UTF_CHAR) *errorcodeptr = ERR77; - } - break; - - /* \U is unrecognized unless PCRE2_ALT_BSUX or PCRE2_EXTRA_ALT_BSUX is set, - in which case it is an upper case letter. */ - - case CHAR_U: - if (!alt_bsux) *errorcodeptr = ERR37; - break; - - /* In a character class, \g is just a literal "g". Outside a character - class, \g must be followed by one of a number of specific things: - - (1) A number, either plain or braced. If positive, it is an absolute - backreference. If negative, it is a relative backreference. This is a Perl - 5.10 feature. - - (2) Perl 5.10 also supports \g{name} as a reference to a named group. This - is part of Perl's movement towards a unified syntax for back references. As - this is synonymous with \k{name}, we fudge it up by pretending it really - was \k{name}. - - (3) For Oniguruma compatibility we also support \g followed by a name or a - number either in angle brackets or in single quotes. However, these are - (possibly recursive) subroutine calls, _not_ backreferences. We return - the ESC_g code. - - Summary: Return a negative number for a numerical back reference, ESC_k for - a named back reference, and ESC_g for a named or numbered subroutine call. - */ - - case CHAR_g: - if (isclass) break; - - if (ptr >= ptrend) - { - *errorcodeptr = ERR57; - break; - } - - if (*ptr == CHAR_LESS_THAN_SIGN || *ptr == CHAR_APOSTROPHE) - { - escape = ESC_g; - break; - } - - /* If there is a brace delimiter, try to read a numerical reference. If - there isn't one, assume we have a name and treat it as \k. */ - - if (*ptr == CHAR_LEFT_CURLY_BRACKET) - { - PCRE2_SPTR p = ptr + 1; - if (!read_number(&p, ptrend, cb->bracount, MAX_GROUP_NUMBER, ERR61, &s, - errorcodeptr)) - { - if (*errorcodeptr == 0) escape = ESC_k; /* No number found */ - break; - } - if (p >= ptrend || *p != CHAR_RIGHT_CURLY_BRACKET) - { - *errorcodeptr = ERR57; - break; - } - ptr = p + 1; - } - - /* Read an undelimited number */ - - else - { - if (!read_number(&ptr, ptrend, cb->bracount, MAX_GROUP_NUMBER, ERR61, &s, - errorcodeptr)) - { - if (*errorcodeptr == 0) *errorcodeptr = ERR57; /* No number found */ - break; - } - } - - if (s <= 0) - { - *errorcodeptr = ERR15; - break; - } - - escape = -s; - break; - - /* The handling of escape sequences consisting of a string of digits - starting with one that is not zero is not straightforward. Perl has changed - over the years. Nowadays \g{} for backreferences and \o{} for octal are - recommended to avoid the ambiguities in the old syntax. - - Outside a character class, the digits are read as a decimal number. If the - number is less than 10, or if there are that many previous extracting left - brackets, it is a back reference. Otherwise, up to three octal digits are - read to form an escaped character code. Thus \123 is likely to be octal 123 - (cf \0123, which is octal 012 followed by the literal 3). - - Inside a character class, \ followed by a digit is always either a literal - 8 or 9 or an octal number. */ - - case CHAR_1: case CHAR_2: case CHAR_3: case CHAR_4: case CHAR_5: - case CHAR_6: case CHAR_7: case CHAR_8: case CHAR_9: - - if (!isclass) - { - oldptr = ptr; - ptr--; /* Back to the digit */ - - /* As we know we are at a digit, the only possible error from - read_number() is a number that is too large to be a group number. In this - case we fall through handle this as not a group reference. If we have - read a small enough number, check for a back reference. - - \1 to \9 are always back references. \8x and \9x are too; \1x to \7x - are octal escapes if there are not that many previous captures. */ - - if (read_number(&ptr, ptrend, -1, INT_MAX/10 - 1, 0, &s, errorcodeptr) && - (s < 10 || oldptr[-1] >= CHAR_8 || s <= (int)cb->bracount)) - { - if (s > (int)MAX_GROUP_NUMBER) *errorcodeptr = ERR61; - else escape = -s; /* Indicates a back reference */ - break; - } - - ptr = oldptr; /* Put the pointer back and fall through */ - } - - /* Handle a digit following \ when the number is not a back reference, or - we are within a character class. If the first digit is 8 or 9, Perl used to - generate a binary zero and then treat the digit as a following literal. At - least by Perl 5.18 this changed so as not to insert the binary zero. */ - - if (c >= CHAR_8) break; - - /* Fall through */ - - /* \0 always starts an octal number, but we may drop through to here with a - larger first octal digit. The original code used just to take the least - significant 8 bits of octal numbers (I think this is what early Perls used - to do). Nowadays we allow for larger numbers in UTF-8 mode and 16-bit mode, - but no more than 3 octal digits. */ - - case CHAR_0: - c -= CHAR_0; - while(i++ < 2 && ptr < ptrend && *ptr >= CHAR_0 && *ptr <= CHAR_7) - c = c * 8 + *ptr++ - CHAR_0; -#if PCRE2_CODE_UNIT_WIDTH == 8 - if (!utf && c > 0xff) *errorcodeptr = ERR51; -#endif - break; - - /* \o is a relatively new Perl feature, supporting a more general way of - specifying character codes in octal. The only supported form is \o{ddd}. */ - - case CHAR_o: - if (ptr >= ptrend || *ptr++ != CHAR_LEFT_CURLY_BRACKET) - { - ptr--; - *errorcodeptr = ERR55; - } - else if (ptr >= ptrend || *ptr == CHAR_RIGHT_CURLY_BRACKET) - *errorcodeptr = ERR78; - else - { - c = 0; - overflow = FALSE; - while (ptr < ptrend && *ptr >= CHAR_0 && *ptr <= CHAR_7) - { - cc = *ptr++; - if (c == 0 && cc == CHAR_0) continue; /* Leading zeroes */ -#if PCRE2_CODE_UNIT_WIDTH == 32 - if (c >= 0x20000000l) { overflow = TRUE; break; } -#endif - c = (c << 3) + (cc - CHAR_0); -#if PCRE2_CODE_UNIT_WIDTH == 8 - if (c > (utf ? 0x10ffffU : 0xffU)) { overflow = TRUE; break; } -#elif PCRE2_CODE_UNIT_WIDTH == 16 - if (c > (utf ? 0x10ffffU : 0xffffU)) { overflow = TRUE; break; } -#elif PCRE2_CODE_UNIT_WIDTH == 32 - if (utf && c > 0x10ffffU) { overflow = TRUE; break; } -#endif - } - if (overflow) - { - while (ptr < ptrend && *ptr >= CHAR_0 && *ptr <= CHAR_7) ptr++; - *errorcodeptr = ERR34; - } - else if (ptr < ptrend && *ptr++ == CHAR_RIGHT_CURLY_BRACKET) - { - if (utf && c >= 0xd800 && c <= 0xdfff && - (extra_options & PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES) == 0) - { - ptr--; - *errorcodeptr = ERR73; - } - } - else - { - ptr--; - *errorcodeptr = ERR64; - } - } - break; - - /* When PCRE2_ALT_BSUX or PCRE2_EXTRA_ALT_BSUX is set, \x must be followed - by two hexadecimal digits. Otherwise it is a lowercase x letter. */ - - case CHAR_x: - if (alt_bsux) - { - uint32_t xc; - if (ptrend - ptr < 2) break; /* Less than 2 characters */ - if ((cc = XDIGIT(ptr[0])) == 0xff) break; /* Not a hex digit */ - if ((xc = XDIGIT(ptr[1])) == 0xff) break; /* Not a hex digit */ - c = (cc << 4) | xc; - ptr += 2; - } - - /* Handle \x in Perl's style. \x{ddd} is a character code which can be - greater than 0xff in UTF-8 or non-8bit mode, but only if the ddd are hex - digits. If not, { used to be treated as a data character. However, Perl - seems to read hex digits up to the first non-such, and ignore the rest, so - that, for example \x{zz} matches a binary zero. This seems crazy, so PCRE - now gives an error. */ - - else - { - if (ptr < ptrend && *ptr == CHAR_LEFT_CURLY_BRACKET) - { -#ifndef EBCDIC - COME_FROM_NU: -#endif - if (++ptr >= ptrend || *ptr == CHAR_RIGHT_CURLY_BRACKET) - { - *errorcodeptr = ERR78; - break; - } - c = 0; - overflow = FALSE; - - while (ptr < ptrend && (cc = XDIGIT(*ptr)) != 0xff) - { - ptr++; - if (c == 0 && cc == 0) continue; /* Leading zeroes */ -#if PCRE2_CODE_UNIT_WIDTH == 32 - if (c >= 0x10000000l) { overflow = TRUE; break; } -#endif - c = (c << 4) | cc; - if ((utf && c > 0x10ffffU) || (!utf && c > MAX_NON_UTF_CHAR)) - { - overflow = TRUE; - break; - } - } - - if (overflow) - { - while (ptr < ptrend && XDIGIT(*ptr) != 0xff) ptr++; - *errorcodeptr = ERR34; - } - else if (ptr < ptrend && *ptr++ == CHAR_RIGHT_CURLY_BRACKET) - { - if (utf && c >= 0xd800 && c <= 0xdfff && - (extra_options & PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES) == 0) - { - ptr--; - *errorcodeptr = ERR73; - } - } - - /* If the sequence of hex digits does not end with '}', give an error. - We used just to recognize this construct and fall through to the normal - \x handling, but nowadays Perl gives an error, which seems much more - sensible, so we do too. */ - - else - { - ptr--; - *errorcodeptr = ERR67; - } - } /* End of \x{} processing */ - - /* Read a up to two hex digits after \x */ - - else - { - c = 0; - if (ptr >= ptrend || (cc = XDIGIT(*ptr)) == 0xff) break; /* Not a hex digit */ - ptr++; - c = cc; - if (ptr >= ptrend || (cc = XDIGIT(*ptr)) == 0xff) break; /* Not a hex digit */ - ptr++; - c = (c << 4) | cc; - } /* End of \xdd handling */ - } /* End of Perl-style \x handling */ - break; - - /* The handling of \c is different in ASCII and EBCDIC environments. In an - ASCII (or Unicode) environment, an error is given if the character - following \c is not a printable ASCII character. Otherwise, the following - character is upper-cased if it is a letter, and after that the 0x40 bit is - flipped. The result is the value of the escape. - - In an EBCDIC environment the handling of \c is compatible with the - specification in the perlebcdic document. The following character must be - a letter or one of small number of special characters. These provide a - means of defining the character values 0-31. - - For testing the EBCDIC handling of \c in an ASCII environment, recognize - the EBCDIC value of 'c' explicitly. */ - -#if defined EBCDIC && 'a' != 0x81 - case 0x83: -#else - case CHAR_c: -#endif - if (ptr >= ptrend) - { - *errorcodeptr = ERR2; - break; - } - c = *ptr; - if (c >= CHAR_a && c <= CHAR_z) c = UPPER_CASE(c); - - /* Handle \c in an ASCII/Unicode environment. */ - -#ifndef EBCDIC /* ASCII/UTF-8 coding */ - if (c < 32 || c > 126) /* Excludes all non-printable ASCII */ - { - *errorcodeptr = ERR68; - break; - } - c ^= 0x40; - - /* Handle \c in an EBCDIC environment. The special case \c? is converted to - 255 (0xff) or 95 (0x5f) if other characters suggest we are using the - POSIX-BC encoding. (This is the way Perl indicates that it handles \c?.) - The other valid sequences correspond to a list of specific characters. */ - -#else - if (c == CHAR_QUESTION_MARK) - c = ('\\' == 188 && '`' == 74)? 0x5f : 0xff; - else - { - for (i = 0; i < 32; i++) - { - if (c == ebcdic_escape_c[i]) break; - } - if (i < 32) c = i; else *errorcodeptr = ERR68; - } -#endif /* EBCDIC */ - - ptr++; - break; - - /* Any other alphanumeric following \ is an error. Perl gives an error only - if in warning mode, but PCRE doesn't have a warning mode. */ - - default: - *errorcodeptr = ERR3; - *ptrptr = ptr - 1; /* Point to the character at fault */ - return 0; - } - } - -/* Set the pointer to the next character before returning. */ - -*ptrptr = ptr; -*chptr = c; -return escape; -} - - - -#ifdef SUPPORT_UNICODE -/************************************************* -* Handle \P and \p * -*************************************************/ - -/* This function is called after \P or \p has been encountered, provided that -PCRE2 is compiled with support for UTF and Unicode properties. On entry, the -contents of ptrptr are pointing after the P or p. On exit, it is left pointing -after the final code unit of the escape sequence. - -Arguments: - ptrptr the pattern position pointer - negptr a boolean that is set TRUE for negation else FALSE - ptypeptr an unsigned int that is set to the type value - pdataptr an unsigned int that is set to the detailed property value - errorcodeptr the error code variable - cb the compile data - -Returns: TRUE if the type value was found, or FALSE for an invalid type -*/ - -static BOOL -get_ucp(PCRE2_SPTR *ptrptr, BOOL *negptr, uint16_t *ptypeptr, - uint16_t *pdataptr, int *errorcodeptr, compile_block *cb) -{ -PCRE2_UCHAR c; -PCRE2_SIZE i, bot, top; -PCRE2_SPTR ptr = *ptrptr; -PCRE2_UCHAR name[50]; -PCRE2_UCHAR *vptr = NULL; -uint16_t ptscript = PT_NOTSCRIPT; - -if (ptr >= cb->end_pattern) goto ERROR_RETURN; -c = *ptr++; -*negptr = FALSE; - -/* \P or \p can be followed by a name in {}, optionally preceded by ^ for -negation. */ - -if (c == CHAR_LEFT_CURLY_BRACKET) - { - if (ptr >= cb->end_pattern) goto ERROR_RETURN; - - if (*ptr == CHAR_CIRCUMFLEX_ACCENT) - { - *negptr = TRUE; - ptr++; - } - - for (i = 0; i < (int)(sizeof(name) / sizeof(PCRE2_UCHAR)) - 1; i++) - { - if (ptr >= cb->end_pattern) goto ERROR_RETURN; - c = *ptr++; - while (c == '_' || c == '-' || isspace(c)) - { - if (ptr >= cb->end_pattern) goto ERROR_RETURN; - c = *ptr++; - } - if (c == CHAR_NUL) goto ERROR_RETURN; - if (c == CHAR_RIGHT_CURLY_BRACKET) break; - name[i] = tolower(c); - if ((c == ':' || c == '=') && vptr == NULL) vptr = name + i; - } - - if (c != CHAR_RIGHT_CURLY_BRACKET) goto ERROR_RETURN; - name[i] = 0; - } - -/* If { doesn't follow \p or \P there is just one following character, which -must be an ASCII letter. */ - -else if (MAX_255(c) && (cb->ctypes[c] & ctype_letter) != 0) - { - name[0] = tolower(c); - name[1] = 0; - } -else goto ERROR_RETURN; - -*ptrptr = ptr; - -/* If the property contains ':' or '=' we have class name and value separately -specified. The following are supported: - - . Bidi_Class (synonym bc), for which the property names are "bidi". - . Script (synonym sc) for which the property name is the script name - . Script_Extensions (synonym scx), ditto - -As this is a small number, we currently just check the names directly. If this -grows, a sorted table and a switch will be neater. - -For both the script properties, set a PT_xxx value so that (1) they can be -distinguished and (2) invalid script names that happen to be the name of -another property can be diagnosed. */ - -if (vptr != NULL) - { - int offset = 0; - PCRE2_UCHAR sname[8]; - - *vptr = 0; /* Terminate property name */ - if (PRIV(strcmp_c8)(name, STRING_bidiclass) == 0 || - PRIV(strcmp_c8)(name, STRING_bc) == 0) - { - offset = 4; - sname[0] = CHAR_b; - sname[1] = CHAR_i; /* There is no strcpy_c8 function */ - sname[2] = CHAR_d; - sname[3] = CHAR_i; - } - - else if (PRIV(strcmp_c8)(name, STRING_script) == 0 || - PRIV(strcmp_c8)(name, STRING_sc) == 0) - ptscript = PT_SC; - - else if (PRIV(strcmp_c8)(name, STRING_scriptextensions) == 0 || - PRIV(strcmp_c8)(name, STRING_scx) == 0) - ptscript = PT_SCX; - - else - { - *errorcodeptr = ERR47; - return FALSE; - } - - /* Adjust the string in name[] as needed */ - - memmove(name + offset, vptr + 1, (name + i - vptr)*sizeof(PCRE2_UCHAR)); - if (offset != 0) memmove(name, sname, offset*sizeof(PCRE2_UCHAR)); - } - -/* Search for a recognized property using binary chop. */ - -bot = 0; -top = PRIV(utt_size); - -while (bot < top) - { - int r; - i = (bot + top) >> 1; - r = PRIV(strcmp_c8)(name, PRIV(utt_names) + PRIV(utt)[i].name_offset); - - /* When a matching property is found, some extra checking is needed when the - \p{xx:yy} syntax is used and xx is either sc or scx. */ - - if (r == 0) - { - *pdataptr = PRIV(utt)[i].value; - if (vptr == NULL || ptscript == PT_NOTSCRIPT) - { - *ptypeptr = PRIV(utt)[i].type; - return TRUE; - } - - switch (PRIV(utt)[i].type) - { - case PT_SC: - *ptypeptr = PT_SC; - return TRUE; - - case PT_SCX: - *ptypeptr = ptscript; - return TRUE; - } - - break; /* Non-script found */ - } - - if (r > 0) bot = i + 1; else top = i; - } - -*errorcodeptr = ERR47; /* Unrecognized property */ -return FALSE; - -ERROR_RETURN: /* Malformed \P or \p */ -*errorcodeptr = ERR46; -*ptrptr = ptr; -return FALSE; -} -#endif - - - -/************************************************* -* Check for POSIX class syntax * -*************************************************/ - -/* This function is called when the sequence "[:" or "[." or "[=" is -encountered in a character class. It checks whether this is followed by a -sequence of characters terminated by a matching ":]" or ".]" or "=]". If we -reach an unescaped ']' without the special preceding character, return FALSE. - -Originally, this function only recognized a sequence of letters between the -terminators, but it seems that Perl recognizes any sequence of characters, -though of course unknown POSIX names are subsequently rejected. Perl gives an -"Unknown POSIX class" error for [:f\oo:] for example, where previously PCRE -didn't consider this to be a POSIX class. Likewise for [:1234:]. - -The problem in trying to be exactly like Perl is in the handling of escapes. We -have to be sure that [abc[:x\]pqr] is *not* treated as containing a POSIX -class, but [abc[:x\]pqr:]] is (so that an error can be generated). The code -below handles the special cases \\ and \], but does not try to do any other -escape processing. This makes it different from Perl for cases such as -[:l\ower:] where Perl recognizes it as the POSIX class "lower" but PCRE does -not recognize "l\ower". This is a lesser evil than not diagnosing bad classes -when Perl does, I think. - -A user pointed out that PCRE was rejecting [:a[:digit:]] whereas Perl was not. -It seems that the appearance of a nested POSIX class supersedes an apparent -external class. For example, [:a[:digit:]b:] matches "a", "b", ":", or -a digit. This is handled by returning FALSE if the start of a new group with -the same terminator is encountered, since the next closing sequence must close -the nested group, not the outer one. - -In Perl, unescaped square brackets may also appear as part of class names. For -example, [:a[:abc]b:] gives unknown POSIX class "[:abc]b:]". However, for -[:a[:abc]b][b:] it gives unknown POSIX class "[:abc]b][b:]", which does not -seem right at all. PCRE does not allow closing square brackets in POSIX class -names. - -Arguments: - ptr pointer to the character after the initial [ (colon, dot, equals) - ptrend pointer to the end of the pattern - endptr where to return a pointer to the terminating ':', '.', or '=' - -Returns: TRUE or FALSE -*/ - -static BOOL -check_posix_syntax(PCRE2_SPTR ptr, PCRE2_SPTR ptrend, PCRE2_SPTR *endptr) -{ -PCRE2_UCHAR terminator; /* Don't combine these lines; the Solaris cc */ -terminator = *ptr++; /* compiler warns about "non-constant" initializer. */ - -for (; ptrend - ptr >= 2; ptr++) - { - if (*ptr == CHAR_BACKSLASH && - (ptr[1] == CHAR_RIGHT_SQUARE_BRACKET || ptr[1] == CHAR_BACKSLASH)) - ptr++; - - else if ((*ptr == CHAR_LEFT_SQUARE_BRACKET && ptr[1] == terminator) || - *ptr == CHAR_RIGHT_SQUARE_BRACKET) return FALSE; - - else if (*ptr == terminator && ptr[1] == CHAR_RIGHT_SQUARE_BRACKET) - { - *endptr = ptr; - return TRUE; - } - } - -return FALSE; -} - - - -/************************************************* -* Check POSIX class name * -*************************************************/ - -/* This function is called to check the name given in a POSIX-style class entry -such as [:alnum:]. - -Arguments: - ptr points to the first letter - len the length of the name - -Returns: a value representing the name, or -1 if unknown -*/ - -static int -check_posix_name(PCRE2_SPTR ptr, int len) -{ -const char *pn = posix_names; -int yield = 0; -while (posix_name_lengths[yield] != 0) - { - if (len == posix_name_lengths[yield] && - PRIV(strncmp_c8)(ptr, pn, (unsigned int)len) == 0) return yield; - pn += posix_name_lengths[yield] + 1; - yield++; - } -return -1; -} - - - -/************************************************* -* Read a subpattern or VERB name * -*************************************************/ - -/* This function is called from parse_regex() below whenever it needs to read -the name of a subpattern or a (*VERB) or an (*alpha_assertion). The initial -pointer must be to the character before the name. If that character is '*' we -are reading a verb or alpha assertion name. The pointer is updated to point -after the name, for a VERB or alpha assertion name, or after tha name's -terminator for a subpattern name. Returning both the offset and the name -pointer is redundant information, but some callers use one and some the other, -so it is simplest just to return both. - -Arguments: - ptrptr points to the character pointer variable - ptrend points to the end of the input string - utf true if the input is UTF-encoded - terminator the terminator of a subpattern name must be this - offsetptr where to put the offset from the start of the pattern - nameptr where to put a pointer to the name in the input - namelenptr where to put the length of the name - errcodeptr where to put an error code - cb pointer to the compile data block - -Returns: TRUE if a name was read - FALSE otherwise, with error code set -*/ - -static BOOL -read_name(PCRE2_SPTR *ptrptr, PCRE2_SPTR ptrend, BOOL utf, uint32_t terminator, - PCRE2_SIZE *offsetptr, PCRE2_SPTR *nameptr, uint32_t *namelenptr, - int *errorcodeptr, compile_block *cb) -{ -PCRE2_SPTR ptr = *ptrptr; -BOOL is_group = (*ptr != CHAR_ASTERISK); - -if (++ptr >= ptrend) /* No characters in name */ - { - *errorcodeptr = is_group? ERR62: /* Subpattern name expected */ - ERR60; /* Verb not recognized or malformed */ - goto FAILED; - } - -*nameptr = ptr; -*offsetptr = (PCRE2_SIZE)(ptr - cb->start_pattern); - -/* In UTF mode, a group name may contain letters and decimal digits as defined -by Unicode properties, and underscores, but must not start with a digit. */ - -#ifdef SUPPORT_UNICODE -if (utf && is_group) - { - uint32_t c, type; - - GETCHAR(c, ptr); - type = UCD_CHARTYPE(c); - - if (type == ucp_Nd) - { - *errorcodeptr = ERR44; - goto FAILED; - } - - for(;;) - { - if (type != ucp_Nd && PRIV(ucp_gentype)[type] != ucp_L && - c != CHAR_UNDERSCORE) break; - ptr++; - FORWARDCHARTEST(ptr, ptrend); - if (ptr >= ptrend) break; - GETCHAR(c, ptr); - type = UCD_CHARTYPE(c); - } - } -else -#else -(void)utf; /* Avoid compiler warning */ -#endif /* SUPPORT_UNICODE */ - -/* Handle non-group names and group names in non-UTF modes. A group name must -not start with a digit. If either of the others start with a digit it just -won't be recognized. */ - - { - if (is_group && IS_DIGIT(*ptr)) - { - *errorcodeptr = ERR44; - goto FAILED; - } - - while (ptr < ptrend && MAX_255(*ptr) && (cb->ctypes[*ptr] & ctype_word) != 0) - { - ptr++; - } - } - -/* Check name length */ - -if (ptr > *nameptr + MAX_NAME_SIZE) - { - *errorcodeptr = ERR48; - goto FAILED; - } -*namelenptr = (uint32_t)(ptr - *nameptr); - -/* Subpattern names must not be empty, and their terminator is checked here. -(What follows a verb or alpha assertion name is checked separately.) */ - -if (is_group) - { - if (ptr == *nameptr) - { - *errorcodeptr = ERR62; /* Subpattern name expected */ - goto FAILED; - } - if (ptr >= ptrend || *ptr != (PCRE2_UCHAR)terminator) - { - *errorcodeptr = ERR42; - goto FAILED; - } - ptr++; - } - -*ptrptr = ptr; -return TRUE; - -FAILED: -*ptrptr = ptr; -return FALSE; -} - - - -/************************************************* -* Manage callouts at start of cycle * -*************************************************/ - -/* At the start of a new item in parse_regex() we are able to record the -details of the previous item in a prior callout, and also to set up an -automatic callout if enabled. Avoid having two adjacent automatic callouts, -which would otherwise happen for items such as \Q that contribute nothing to -the parsed pattern. - -Arguments: - ptr current pattern pointer - pcalloutptr points to a pointer to previous callout, or NULL - auto_callout TRUE if auto_callouts are enabled - parsed_pattern the parsed pattern pointer - cb compile block - -Returns: possibly updated parsed_pattern pointer. -*/ - -static uint32_t * -manage_callouts(PCRE2_SPTR ptr, uint32_t **pcalloutptr, BOOL auto_callout, - uint32_t *parsed_pattern, compile_block *cb) -{ -uint32_t *previous_callout = *pcalloutptr; - -if (previous_callout != NULL) previous_callout[2] = (uint32_t)(ptr - - cb->start_pattern - (PCRE2_SIZE)previous_callout[1]); - -if (!auto_callout) previous_callout = NULL; else - { - if (previous_callout == NULL || - previous_callout != parsed_pattern - 4 || - previous_callout[3] != 255) - { - previous_callout = parsed_pattern; /* Set up new automatic callout */ - parsed_pattern += 4; - previous_callout[0] = META_CALLOUT_NUMBER; - previous_callout[2] = 0; - previous_callout[3] = 255; - } - previous_callout[1] = (uint32_t)(ptr - cb->start_pattern); - } - -*pcalloutptr = previous_callout; -return parsed_pattern; -} - - - -/************************************************* -* Parse regex and identify named groups * -*************************************************/ - -/* This function is called first of all. It scans the pattern and does two -things: (1) It identifies capturing groups and makes a table of named capturing -groups so that information about them is fully available to both the compiling -scans. (2) It writes a parsed version of the pattern with comments omitted and -escapes processed into the parsed_pattern vector. - -Arguments: - ptr points to the start of the pattern - options compiling dynamic options (may change during the scan) - has_lookbehind points to a boolean, set TRUE if a lookbehind is found - cb pointer to the compile data block - -Returns: zero on success or a non-zero error code, with the - error offset placed in the cb field -*/ - -/* A structure and some flags for dealing with nested groups. */ - -typedef struct nest_save { - uint16_t nest_depth; - uint16_t reset_group; - uint16_t max_group; - uint16_t flags; - uint32_t options; -} nest_save; - -#define NSF_RESET 0x0001u -#define NSF_CONDASSERT 0x0002u -#define NSF_ATOMICSR 0x0004u - -/* Options that are changeable within the pattern must be tracked during -parsing. Some (e.g. PCRE2_EXTENDED) are implemented entirely during parsing, -but all must be tracked so that META_OPTIONS items set the correct values for -the main compiling phase. */ - -#define PARSE_TRACKED_OPTIONS (PCRE2_CASELESS|PCRE2_DOTALL|PCRE2_DUPNAMES| \ - PCRE2_EXTENDED|PCRE2_EXTENDED_MORE|PCRE2_MULTILINE|PCRE2_NO_AUTO_CAPTURE| \ - PCRE2_UNGREEDY) - -/* States used for analyzing ranges in character classes. The two OK values -must be last. */ - -enum { RANGE_NO, RANGE_STARTED, RANGE_OK_ESCAPED, RANGE_OK_LITERAL }; - -/* Only in 32-bit mode can there be literals > META_END. A macro encapsulates -the storing of literal values in the main parsed pattern, where they can always -be quantified. */ - -#if PCRE2_CODE_UNIT_WIDTH == 32 -#define PARSED_LITERAL(c, p) \ - { \ - if (c >= META_END) *p++ = META_BIGVALUE; \ - *p++ = c; \ - okquantifier = TRUE; \ - } -#else -#define PARSED_LITERAL(c, p) *p++ = c; okquantifier = TRUE; -#endif - -/* Here's the actual function. */ - -static int parse_regex(PCRE2_SPTR ptr, uint32_t options, BOOL *has_lookbehind, - compile_block *cb) -{ -uint32_t c; -uint32_t delimiter; -uint32_t namelen; -uint32_t class_range_state; -uint32_t *verblengthptr = NULL; /* Value avoids compiler warning */ -uint32_t *verbstartptr = NULL; -uint32_t *previous_callout = NULL; -uint32_t *parsed_pattern = cb->parsed_pattern; -uint32_t *parsed_pattern_end = cb->parsed_pattern_end; -uint32_t meta_quantifier = 0; -uint32_t add_after_mark = 0; -uint32_t extra_options = cb->cx->extra_options; -uint16_t nest_depth = 0; -int after_manual_callout = 0; -int expect_cond_assert = 0; -int errorcode = 0; -int escape; -int i; -BOOL inescq = FALSE; -BOOL inverbname = FALSE; -BOOL utf = (options & PCRE2_UTF) != 0; -BOOL auto_callout = (options & PCRE2_AUTO_CALLOUT) != 0; -BOOL isdupname; -BOOL negate_class; -BOOL okquantifier = FALSE; -PCRE2_SPTR thisptr; -PCRE2_SPTR name; -PCRE2_SPTR ptrend = cb->end_pattern; -PCRE2_SPTR verbnamestart = NULL; /* Value avoids compiler warning */ -named_group *ng; -nest_save *top_nest, *end_nests; - -/* Insert leading items for word and line matching (features provided for the -benefit of pcre2grep). */ - -if ((extra_options & PCRE2_EXTRA_MATCH_LINE) != 0) - { - *parsed_pattern++ = META_CIRCUMFLEX; - *parsed_pattern++ = META_NOCAPTURE; - } -else if ((extra_options & PCRE2_EXTRA_MATCH_WORD) != 0) - { - *parsed_pattern++ = META_ESCAPE + ESC_b; - *parsed_pattern++ = META_NOCAPTURE; - } - -/* If the pattern is actually a literal string, process it separately to avoid -cluttering up the main loop. */ - -if ((options & PCRE2_LITERAL) != 0) - { - while (ptr < ptrend) - { - if (parsed_pattern >= parsed_pattern_end) - { - errorcode = ERR63; /* Internal error (parsed pattern overflow) */ - goto FAILED; - } - thisptr = ptr; - GETCHARINCTEST(c, ptr); - if (auto_callout) - parsed_pattern = manage_callouts(thisptr, &previous_callout, - auto_callout, parsed_pattern, cb); - PARSED_LITERAL(c, parsed_pattern); - } - goto PARSED_END; - } - -/* Process a real regex which may contain meta-characters. */ - -top_nest = NULL; -end_nests = (nest_save *)(cb->start_workspace + cb->workspace_size); - -/* The size of the nest_save structure might not be a factor of the size of the -workspace. Therefore we must round down end_nests so as to correctly avoid -creating a nest_save that spans the end of the workspace. */ - -end_nests = (nest_save *)((char *)end_nests - - ((cb->workspace_size * sizeof(PCRE2_UCHAR)) % sizeof(nest_save))); - -/* PCRE2_EXTENDED_MORE implies PCRE2_EXTENDED */ - -if ((options & PCRE2_EXTENDED_MORE) != 0) options |= PCRE2_EXTENDED; - -/* Now scan the pattern */ - -while (ptr < ptrend) - { - int prev_expect_cond_assert; - uint32_t min_repeat = 0, max_repeat = 0; - uint32_t set, unset, *optset; - uint32_t terminator; - uint32_t prev_meta_quantifier; - BOOL prev_okquantifier; - PCRE2_SPTR tempptr; - PCRE2_SIZE offset; - - if (parsed_pattern >= parsed_pattern_end) - { - errorcode = ERR63; /* Internal error (parsed pattern overflow) */ - goto FAILED; - } - - if (nest_depth > cb->cx->parens_nest_limit) - { - errorcode = ERR19; - goto FAILED; /* Parentheses too deeply nested */ - } - - /* Get next input character, save its position for callout handling. */ - - thisptr = ptr; - GETCHARINCTEST(c, ptr); - - /* Copy quoted literals until \E, allowing for the possibility of automatic - callouts, except when processing a (*VERB) "name". */ - - if (inescq) - { - if (c == CHAR_BACKSLASH && ptr < ptrend && *ptr == CHAR_E) - { - inescq = FALSE; - ptr++; /* Skip E */ - } - else - { - if (expect_cond_assert > 0) /* A literal is not allowed if we are */ - { /* expecting a conditional assertion, */ - ptr--; /* but an empty \Q\E sequence is OK. */ - errorcode = ERR28; - goto FAILED; - } - if (inverbname) - { /* Don't use PARSED_LITERAL() because it */ -#if PCRE2_CODE_UNIT_WIDTH == 32 /* sets okquantifier. */ - if (c >= META_END) *parsed_pattern++ = META_BIGVALUE; -#endif - *parsed_pattern++ = c; - } - else - { - if (after_manual_callout-- <= 0) - parsed_pattern = manage_callouts(thisptr, &previous_callout, - auto_callout, parsed_pattern, cb); - PARSED_LITERAL(c, parsed_pattern); - } - meta_quantifier = 0; - } - continue; /* Next character */ - } - - /* If we are processing the "name" part of a (*VERB:NAME) item, all - characters up to the closing parenthesis are literals except when - PCRE2_ALT_VERBNAMES is set. That causes backslash interpretation, but only \Q - and \E and escaped characters are allowed (no character types such as \d). If - PCRE2_EXTENDED is also set, we must ignore white space and # comments. Do - this by not entering the special (*VERB:NAME) processing - they are then - picked up below. Note that c is a character, not a code unit, so we must not - use MAX_255 to test its size because MAX_255 tests code units and is assumed - TRUE in 8-bit mode. */ - - if (inverbname && - ( - /* EITHER: not both options set */ - ((options & (PCRE2_EXTENDED | PCRE2_ALT_VERBNAMES)) != - (PCRE2_EXTENDED | PCRE2_ALT_VERBNAMES)) || -#ifdef SUPPORT_UNICODE - /* OR: character > 255 AND not Unicode Pattern White Space */ - (c > 255 && (c|1) != 0x200f && (c|1) != 0x2029) || -#endif - /* OR: not a # comment or isspace() white space */ - (c < 256 && c != CHAR_NUMBER_SIGN && (cb->ctypes[c] & ctype_space) == 0 -#ifdef SUPPORT_UNICODE - /* and not CHAR_NEL when Unicode is supported */ - && c != CHAR_NEL -#endif - ))) - { - PCRE2_SIZE verbnamelength; - - switch(c) - { - default: /* Don't use PARSED_LITERAL() because it */ -#if PCRE2_CODE_UNIT_WIDTH == 32 /* sets okquantifier. */ - if (c >= META_END) *parsed_pattern++ = META_BIGVALUE; -#endif - *parsed_pattern++ = c; - break; - - case CHAR_RIGHT_PARENTHESIS: - inverbname = FALSE; - /* This is the length in characters */ - verbnamelength = (PCRE2_SIZE)(parsed_pattern - verblengthptr - 1); - /* But the limit on the length is in code units */ - if (ptr - verbnamestart - 1 > (int)MAX_MARK) - { - ptr--; - errorcode = ERR76; - goto FAILED; - } - *verblengthptr = (uint32_t)verbnamelength; - - /* If this name was on a verb such as (*ACCEPT) which does not continue, - a (*MARK) was generated for the name. We now add the original verb as the - next item. */ - - if (add_after_mark != 0) - { - *parsed_pattern++ = add_after_mark; - add_after_mark = 0; - } - break; - - case CHAR_BACKSLASH: - if ((options & PCRE2_ALT_VERBNAMES) != 0) - { - escape = PRIV(check_escape)(&ptr, ptrend, &c, &errorcode, options, - cb->cx->extra_options, FALSE, cb); - if (errorcode != 0) goto FAILED; - } - else escape = 0; /* Treat all as literal */ - - switch(escape) - { - case 0: /* Don't use PARSED_LITERAL() because it */ -#if PCRE2_CODE_UNIT_WIDTH == 32 /* sets okquantifier. */ - if (c >= META_END) *parsed_pattern++ = META_BIGVALUE; -#endif - *parsed_pattern++ = c; - break; - - case ESC_Q: - inescq = TRUE; - break; - - case ESC_E: /* Ignore */ - break; - - default: - errorcode = ERR40; /* Invalid in verb name */ - goto FAILED; - } - } - continue; /* Next character in pattern */ - } - - /* Not a verb name character. At this point we must process everything that - must not change the quantification state. This is mainly comments, but we - handle \Q and \E here as well, so that an item such as A\Q\E+ is treated as - A+, as in Perl. An isolated \E is ignored. */ - - if (c == CHAR_BACKSLASH && ptr < ptrend) - { - if (*ptr == CHAR_Q || *ptr == CHAR_E) - { - inescq = *ptr == CHAR_Q; - ptr++; - continue; - } - } - - /* Skip over whitespace and # comments in extended mode. Note that c is a - character, not a code unit, so we must not use MAX_255 to test its size - because MAX_255 tests code units and is assumed TRUE in 8-bit mode. The - whitespace characters are those designated as "Pattern White Space" by - Unicode, which are the isspace() characters plus CHAR_NEL (newline), which is - U+0085 in Unicode, plus U+200E, U+200F, U+2028, and U+2029. These are a - subset of space characters that match \h and \v. */ - - if ((options & PCRE2_EXTENDED) != 0) - { - if (c < 256 && (cb->ctypes[c] & ctype_space) != 0) continue; -#ifdef SUPPORT_UNICODE - if (c == CHAR_NEL || (c|1) == 0x200f || (c|1) == 0x2029) continue; -#endif - if (c == CHAR_NUMBER_SIGN) - { - while (ptr < ptrend) - { - if (IS_NEWLINE(ptr)) /* For non-fixed-length newline cases, */ - { /* IS_NEWLINE sets cb->nllen. */ - ptr += cb->nllen; - break; - } - ptr++; -#ifdef SUPPORT_UNICODE - if (utf) FORWARDCHARTEST(ptr, ptrend); -#endif - } - continue; /* Next character in pattern */ - } - } - - /* Skip over bracketed comments */ - - if (c == CHAR_LEFT_PARENTHESIS && ptrend - ptr >= 2 && - ptr[0] == CHAR_QUESTION_MARK && ptr[1] == CHAR_NUMBER_SIGN) - { - while (++ptr < ptrend && *ptr != CHAR_RIGHT_PARENTHESIS); - if (ptr >= ptrend) - { - errorcode = ERR18; /* A special error for missing ) in a comment */ - goto FAILED; /* to make it easier to debug. */ - } - ptr++; - continue; /* Next character in pattern */ - } - - /* If the next item is not a quantifier, fill in length of any previous - callout and create an auto callout if required. */ - - if (c != CHAR_ASTERISK && c != CHAR_PLUS && c != CHAR_QUESTION_MARK && - (c != CHAR_LEFT_CURLY_BRACKET || - (tempptr = ptr, - !read_repeat_counts(&tempptr, ptrend, NULL, NULL, &errorcode)))) - { - if (after_manual_callout-- <= 0) - parsed_pattern = manage_callouts(thisptr, &previous_callout, auto_callout, - parsed_pattern, cb); - } - - /* If expect_cond_assert is 2, we have just passed (?( and are expecting an - assertion, possibly preceded by a callout. If the value is 1, we have just - had the callout and expect an assertion. There must be at least 3 more - characters in all cases. When expect_cond_assert is 2, we know that the - current character is an opening parenthesis, as otherwise we wouldn't be - here. However, when it is 1, we need to check, and it's easiest just to check - always. Note that expect_cond_assert may be negative, since all callouts just - decrement it. */ - - if (expect_cond_assert > 0) - { - BOOL ok = c == CHAR_LEFT_PARENTHESIS && ptrend - ptr >= 3 && - (ptr[0] == CHAR_QUESTION_MARK || ptr[0] == CHAR_ASTERISK); - if (ok) - { - if (ptr[0] == CHAR_ASTERISK) /* New alpha assertion format, possibly */ - { - ok = MAX_255(ptr[1]) && (cb->ctypes[ptr[1]] & ctype_lcletter) != 0; - } - else switch(ptr[1]) /* Traditional symbolic format */ - { - case CHAR_C: - ok = expect_cond_assert == 2; - break; - - case CHAR_EQUALS_SIGN: - case CHAR_EXCLAMATION_MARK: - break; - - case CHAR_LESS_THAN_SIGN: - ok = ptr[2] == CHAR_EQUALS_SIGN || ptr[2] == CHAR_EXCLAMATION_MARK; - break; - - default: - ok = FALSE; - } - } - - if (!ok) - { - ptr--; /* Adjust error offset */ - errorcode = ERR28; - goto FAILED; - } - } - - /* Remember whether we are expecting a conditional assertion, and set the - default for this item. */ - - prev_expect_cond_assert = expect_cond_assert; - expect_cond_assert = 0; - - /* Remember quantification status for the previous significant item, then set - default for this item. */ - - prev_okquantifier = okquantifier; - prev_meta_quantifier = meta_quantifier; - okquantifier = FALSE; - meta_quantifier = 0; - - /* If the previous significant item was a quantifier, adjust the parsed code - if there is a following modifier. The base meta value is always followed by - the PLUS and QUERY values, in that order. We do this here rather than after - reading a quantifier so that intervening comments and /x whitespace can be - ignored without having to replicate code. */ - - if (prev_meta_quantifier != 0 && (c == CHAR_QUESTION_MARK || c == CHAR_PLUS)) - { - parsed_pattern[(prev_meta_quantifier == META_MINMAX)? -3 : -1] = - prev_meta_quantifier + ((c == CHAR_QUESTION_MARK)? - 0x00020000u : 0x00010000u); - continue; /* Next character in pattern */ - } - - - /* Process the next item in the main part of a pattern. */ - - switch(c) - { - default: /* Non-special character */ - PARSED_LITERAL(c, parsed_pattern); - break; - - - /* ---- Escape sequence ---- */ - - case CHAR_BACKSLASH: - tempptr = ptr; - escape = PRIV(check_escape)(&ptr, ptrend, &c, &errorcode, options, - cb->cx->extra_options, FALSE, cb); - if (errorcode != 0) - { - ESCAPE_FAILED: - if ((extra_options & PCRE2_EXTRA_BAD_ESCAPE_IS_LITERAL) == 0) - goto FAILED; - ptr = tempptr; - if (ptr >= ptrend) c = CHAR_BACKSLASH; else - { - GETCHARINCTEST(c, ptr); /* Get character value, increment pointer */ - } - escape = 0; /* Treat as literal character */ - } - - /* The escape was a data escape or literal character. */ - - if (escape == 0) - { - PARSED_LITERAL(c, parsed_pattern); - } - - /* The escape was a back (or forward) reference. We keep the offset in - order to give a more useful diagnostic for a bad forward reference. For - references to groups numbered less than 10 we can't use more than two items - in parsed_pattern because they may be just two characters in the input (and - in a 64-bit world an offset may need two elements). So for them, the offset - of the first occurrent is held in a special vector. */ - - else if (escape < 0) - { - offset = (PCRE2_SIZE)(ptr - cb->start_pattern - 1); - escape = -escape; - *parsed_pattern++ = META_BACKREF | (uint32_t)escape; - if (escape < 10) - { - if (cb->small_ref_offset[escape] == PCRE2_UNSET) - cb->small_ref_offset[escape] = offset; - } - else - { - PUTOFFSET(offset, parsed_pattern); - } - okquantifier = TRUE; - } - - /* The escape was a character class such as \d etc. or other special - escape indicator such as \A or \X. Most of them generate just a single - parsed item, but \P and \p are followed by a 16-bit type and a 16-bit - value. They are supported only when Unicode is available. The type and - value are packed into a single 32-bit value so that the whole sequences - uses only two elements in the parsed_vector. This is because the same - coding is used if \d (for example) is turned into \p{Nd} when PCRE2_UCP is - set. - - There are also some cases where the escape sequence is followed by a name: - \k{name}, \k, and \k'name' are backreferences by name, and \g - and \g'name' are subroutine calls by name; \g{name} is a synonym for - \k{name}. Note that \g and \g'number' are handled by check_escape() - and returned as a negative value (handled above). A name is coded as an - offset into the pattern and a length. */ - - else switch (escape) - { - case ESC_C: -#ifdef NEVER_BACKSLASH_C - errorcode = ERR85; - goto ESCAPE_FAILED; -#else - if ((options & PCRE2_NEVER_BACKSLASH_C) != 0) - { - errorcode = ERR83; - goto ESCAPE_FAILED; - } -#endif - okquantifier = TRUE; - *parsed_pattern++ = META_ESCAPE + escape; - break; - - case ESC_X: -#ifndef SUPPORT_UNICODE - errorcode = ERR45; /* Supported only with Unicode support */ - goto ESCAPE_FAILED; -#endif - case ESC_H: - case ESC_h: - case ESC_N: - case ESC_R: - case ESC_V: - case ESC_v: - okquantifier = TRUE; - *parsed_pattern++ = META_ESCAPE + escape; - break; - - default: /* \A, \B, \b, \G, \K, \Z, \z cannot be quantified. */ - *parsed_pattern++ = META_ESCAPE + escape; - break; - - /* Escapes that change in UCP mode. Note that PCRE2_UCP will never be set - without Unicode support because it is checked when pcre2_compile() is - called. */ - - case ESC_d: - case ESC_D: - case ESC_s: - case ESC_S: - case ESC_w: - case ESC_W: - okquantifier = TRUE; - if ((options & PCRE2_UCP) == 0) - { - *parsed_pattern++ = META_ESCAPE + escape; - } - else - { - *parsed_pattern++ = META_ESCAPE + - ((escape == ESC_d || escape == ESC_s || escape == ESC_w)? - ESC_p : ESC_P); - switch(escape) - { - case ESC_d: - case ESC_D: - *parsed_pattern++ = (PT_PC << 16) | ucp_Nd; - break; - - case ESC_s: - case ESC_S: - *parsed_pattern++ = PT_SPACE << 16; - break; - - case ESC_w: - case ESC_W: - *parsed_pattern++ = PT_WORD << 16; - break; - } - } - break; - - /* Unicode property matching */ - - case ESC_P: - case ESC_p: -#ifdef SUPPORT_UNICODE - { - BOOL negated; - uint16_t ptype = 0, pdata = 0; - if (!get_ucp(&ptr, &negated, &ptype, &pdata, &errorcode, cb)) - goto ESCAPE_FAILED; - if (negated) escape = (escape == ESC_P)? ESC_p : ESC_P; - *parsed_pattern++ = META_ESCAPE + escape; - *parsed_pattern++ = (ptype << 16) | pdata; - okquantifier = TRUE; - } -#else - errorcode = ERR45; - goto ESCAPE_FAILED; -#endif - break; /* End \P and \p */ - - /* When \g is used with quotes or angle brackets as delimiters, it is a - numerical or named subroutine call, and control comes here. When used - with brace delimiters it is a numberical back reference and does not come - here because check_escape() returns it directly as a reference. \k is - always a named back reference. */ - - case ESC_g: - case ESC_k: - if (ptr >= ptrend || (*ptr != CHAR_LEFT_CURLY_BRACKET && - *ptr != CHAR_LESS_THAN_SIGN && *ptr != CHAR_APOSTROPHE)) - { - errorcode = (escape == ESC_g)? ERR57 : ERR69; - goto ESCAPE_FAILED; - } - terminator = (*ptr == CHAR_LESS_THAN_SIGN)? - CHAR_GREATER_THAN_SIGN : (*ptr == CHAR_APOSTROPHE)? - CHAR_APOSTROPHE : CHAR_RIGHT_CURLY_BRACKET; - - /* For a non-braced \g, check for a numerical recursion. */ - - if (escape == ESC_g && terminator != CHAR_RIGHT_CURLY_BRACKET) - { - PCRE2_SPTR p = ptr + 1; - - if (read_number(&p, ptrend, cb->bracount, MAX_GROUP_NUMBER, ERR61, &i, - &errorcode)) - { - if (p >= ptrend || *p != terminator) - { - errorcode = ERR57; - goto ESCAPE_FAILED; - } - ptr = p; - goto SET_RECURSION; - } - if (errorcode != 0) goto ESCAPE_FAILED; - } - - /* Not a numerical recursion */ - - if (!read_name(&ptr, ptrend, utf, terminator, &offset, &name, &namelen, - &errorcode, cb)) goto ESCAPE_FAILED; - - /* \k and \g when used with braces are back references, whereas \g used - with quotes or angle brackets is a recursion */ - - *parsed_pattern++ = - (escape == ESC_k || terminator == CHAR_RIGHT_CURLY_BRACKET)? - META_BACKREF_BYNAME : META_RECURSE_BYNAME; - *parsed_pattern++ = namelen; - - PUTOFFSET(offset, parsed_pattern); - okquantifier = TRUE; - break; /* End special escape processing */ - } - break; /* End escape sequence processing */ - - - /* ---- Single-character special items ---- */ - - case CHAR_CIRCUMFLEX_ACCENT: - *parsed_pattern++ = META_CIRCUMFLEX; - break; - - case CHAR_DOLLAR_SIGN: - *parsed_pattern++ = META_DOLLAR; - break; - - case CHAR_DOT: - *parsed_pattern++ = META_DOT; - okquantifier = TRUE; - break; - - - /* ---- Single-character quantifiers ---- */ - - case CHAR_ASTERISK: - meta_quantifier = META_ASTERISK; - goto CHECK_QUANTIFIER; - - case CHAR_PLUS: - meta_quantifier = META_PLUS; - goto CHECK_QUANTIFIER; - - case CHAR_QUESTION_MARK: - meta_quantifier = META_QUERY; - goto CHECK_QUANTIFIER; - - - /* ---- Potential {n,m} quantifier ---- */ - - case CHAR_LEFT_CURLY_BRACKET: - if (!read_repeat_counts(&ptr, ptrend, &min_repeat, &max_repeat, - &errorcode)) - { - if (errorcode != 0) goto FAILED; /* Error in quantifier. */ - PARSED_LITERAL(c, parsed_pattern); /* Not a quantifier */ - break; /* No more quantifier processing */ - } - meta_quantifier = META_MINMAX; - /* Fall through */ - - - /* ---- Quantifier post-processing ---- */ - - /* Check that a quantifier is allowed after the previous item. */ - - CHECK_QUANTIFIER: - if (!prev_okquantifier) - { - errorcode = ERR9; - goto FAILED_BACK; - } - - /* Most (*VERB)s are not allowed to be quantified, but an ungreedy - quantifier can be useful for (*ACCEPT) - meaning "succeed on backtrack", a - sort of negated (*COMMIT). We therefore allow (*ACCEPT) to be quantified by - wrapping it in non-capturing brackets, but we have to allow for a preceding - (*MARK) for when (*ACCEPT) has an argument. */ - - if (parsed_pattern[-1] == META_ACCEPT) - { - uint32_t *p; - for (p = parsed_pattern - 1; p >= verbstartptr; p--) p[1] = p[0]; - *verbstartptr = META_NOCAPTURE; - parsed_pattern[1] = META_KET; - parsed_pattern += 2; - } - - /* Now we can put the quantifier into the parsed pattern vector. At this - stage, we have only the basic quantifier. The check for a following + or ? - modifier happens at the top of the loop, after any intervening comments - have been removed. */ - - *parsed_pattern++ = meta_quantifier; - if (c == CHAR_LEFT_CURLY_BRACKET) - { - *parsed_pattern++ = min_repeat; - *parsed_pattern++ = max_repeat; - } - break; - - - /* ---- Character class ---- */ - - case CHAR_LEFT_SQUARE_BRACKET: - okquantifier = TRUE; - - /* In another (POSIX) regex library, the ugly syntax [[:<:]] and [[:>:]] is - used for "start of word" and "end of word". As these are otherwise illegal - sequences, we don't break anything by recognizing them. They are replaced - by \b(?=\w) and \b(?<=\w) respectively. Sequences like [a[:<:]] are - erroneous and are handled by the normal code below. */ - - if (ptrend - ptr >= 6 && - (PRIV(strncmp_c8)(ptr, STRING_WEIRD_STARTWORD, 6) == 0 || - PRIV(strncmp_c8)(ptr, STRING_WEIRD_ENDWORD, 6) == 0)) - { - *parsed_pattern++ = META_ESCAPE + ESC_b; - - if (ptr[2] == CHAR_LESS_THAN_SIGN) - { - *parsed_pattern++ = META_LOOKAHEAD; - } - else - { - *parsed_pattern++ = META_LOOKBEHIND; - *has_lookbehind = TRUE; - - /* The offset is used only for the "non-fixed length" error; this won't - occur here, so just store zero. */ - - PUTOFFSET((PCRE2_SIZE)0, parsed_pattern); - } - - if ((options & PCRE2_UCP) == 0) - *parsed_pattern++ = META_ESCAPE + ESC_w; - else - { - *parsed_pattern++ = META_ESCAPE + ESC_p; - *parsed_pattern++ = PT_WORD << 16; - } - *parsed_pattern++ = META_KET; - ptr += 6; - break; - } - - /* PCRE supports POSIX class stuff inside a class. Perl gives an error if - they are encountered at the top level, so we'll do that too. */ - - if (ptr < ptrend && (*ptr == CHAR_COLON || *ptr == CHAR_DOT || - *ptr == CHAR_EQUALS_SIGN) && - check_posix_syntax(ptr, ptrend, &tempptr)) - { - errorcode = (*ptr-- == CHAR_COLON)? ERR12 : ERR13; - goto FAILED; - } - - /* Process a regular character class. If the first character is '^', set - the negation flag. If the first few characters (either before or after ^) - are \Q\E or \E or space or tab in extended-more mode, we skip them too. - This makes for compatibility with Perl. */ - - negate_class = FALSE; - while (ptr < ptrend) - { - GETCHARINCTEST(c, ptr); - if (c == CHAR_BACKSLASH) - { - if (ptr < ptrend && *ptr == CHAR_E) ptr++; - else if (ptrend - ptr >= 3 && - PRIV(strncmp_c8)(ptr, STR_Q STR_BACKSLASH STR_E, 3) == 0) - ptr += 3; - else - break; - } - else if ((options & PCRE2_EXTENDED_MORE) != 0 && - (c == CHAR_SPACE || c == CHAR_HT)) /* Note: just these two */ - continue; - else if (!negate_class && c == CHAR_CIRCUMFLEX_ACCENT) - negate_class = TRUE; - else break; - } - - /* Now the real contents of the class; c has the first "real" character. - Empty classes are permitted only if the option is set. */ - - if (c == CHAR_RIGHT_SQUARE_BRACKET && - (cb->external_options & PCRE2_ALLOW_EMPTY_CLASS) != 0) - { - *parsed_pattern++ = negate_class? META_CLASS_EMPTY_NOT : META_CLASS_EMPTY; - break; /* End of class processing */ - } - - /* Process a non-empty class. */ - - *parsed_pattern++ = negate_class? META_CLASS_NOT : META_CLASS; - class_range_state = RANGE_NO; - - /* In an EBCDIC environment, Perl treats alphabetic ranges specially - because there are holes in the encoding, and simply using the range A-Z - (for example) would include the characters in the holes. This applies only - to ranges where both values are literal; [\xC1-\xE9] is different to [A-Z] - in this respect. In order to accommodate this, we keep track of whether - character values are literal or not, and a state variable for handling - ranges. */ - - /* Loop for the contents of the class */ - - for (;;) - { - BOOL char_is_literal = TRUE; - - /* Inside \Q...\E everything is literal except \E */ - - if (inescq) - { - if (c == CHAR_BACKSLASH && ptr < ptrend && *ptr == CHAR_E) - { - inescq = FALSE; /* Reset literal state */ - ptr++; /* Skip the 'E' */ - goto CLASS_CONTINUE; - } - goto CLASS_LITERAL; - } - - /* Skip over space and tab (only) in extended-more mode. */ - - if ((options & PCRE2_EXTENDED_MORE) != 0 && - (c == CHAR_SPACE || c == CHAR_HT)) - goto CLASS_CONTINUE; - - /* Handle POSIX class names. Perl allows a negation extension of the - form [:^name:]. A square bracket that doesn't match the syntax is - treated as a literal. We also recognize the POSIX constructions - [.ch.] and [=ch=] ("collating elements") and fault them, as Perl - 5.6 and 5.8 do. */ - - if (c == CHAR_LEFT_SQUARE_BRACKET && - ptrend - ptr >= 3 && - (*ptr == CHAR_COLON || *ptr == CHAR_DOT || - *ptr == CHAR_EQUALS_SIGN) && - check_posix_syntax(ptr, ptrend, &tempptr)) - { - BOOL posix_negate = FALSE; - int posix_class; - - /* Perl treats a hyphen before a POSIX class as a literal, not the - start of a range. However, it gives a warning in its warning mode. PCRE - does not have a warning mode, so we give an error, because this is - likely an error on the user's part. */ - - if (class_range_state == RANGE_STARTED) - { - errorcode = ERR50; - goto FAILED; - } - - if (*ptr != CHAR_COLON) - { - errorcode = ERR13; - goto FAILED_BACK; - } - - if (*(++ptr) == CHAR_CIRCUMFLEX_ACCENT) - { - posix_negate = TRUE; - ptr++; - } - - posix_class = check_posix_name(ptr, (int)(tempptr - ptr)); - if (posix_class < 0) - { - errorcode = ERR30; - goto FAILED; - } - ptr = tempptr + 2; - - /* Perl treats a hyphen after a POSIX class as a literal, not the - start of a range. However, it gives a warning in its warning mode - unless the hyphen is the last character in the class. PCRE does not - have a warning mode, so we give an error, because this is likely an - error on the user's part. */ - - if (ptr < ptrend - 1 && *ptr == CHAR_MINUS && - ptr[1] != CHAR_RIGHT_SQUARE_BRACKET) - { - errorcode = ERR50; - goto FAILED; - } - - /* Set "a hyphen is not the start of a range" for the -] case, and also - in case the POSIX class is followed by \E or \Q\E (possibly repeated - - fuzzers do that kind of thing) and *then* a hyphen. This causes that - hyphen to be treated as a literal. I don't think it's worth setting up - special apparatus to do otherwise. */ - - class_range_state = RANGE_NO; - - /* When PCRE2_UCP is set, some of the POSIX classes are converted to - use Unicode properties \p or \P or, in one case, \h or \H. The - substitutes table has two values per class, containing the type and - value of a \p or \P item. The special cases are specified with a - negative type: a non-zero value causes \h or \H to be used, and a zero - value falls through to behave like a non-UCP POSIX class. */ - -#ifdef SUPPORT_UNICODE - if ((options & PCRE2_UCP) != 0) - { - int ptype = posix_substitutes[2*posix_class]; - int pvalue = posix_substitutes[2*posix_class + 1]; - if (ptype >= 0) - { - *parsed_pattern++ = META_ESCAPE + (posix_negate? ESC_P : ESC_p); - *parsed_pattern++ = (ptype << 16) | pvalue; - goto CLASS_CONTINUE; - } - - if (pvalue != 0) - { - *parsed_pattern++ = META_ESCAPE + (posix_negate? ESC_H : ESC_h); - goto CLASS_CONTINUE; - } - - /* Fall through */ - } -#endif /* SUPPORT_UNICODE */ - - /* Non-UCP POSIX class */ - - *parsed_pattern++ = posix_negate? META_POSIX_NEG : META_POSIX; - *parsed_pattern++ = posix_class; - } - - /* Handle potential start of range */ - - else if (c == CHAR_MINUS && class_range_state >= RANGE_OK_ESCAPED) - { - *parsed_pattern++ = (class_range_state == RANGE_OK_LITERAL)? - META_RANGE_LITERAL : META_RANGE_ESCAPED; - class_range_state = RANGE_STARTED; - } - - /* Handle a literal character */ - - else if (c != CHAR_BACKSLASH) - { - CLASS_LITERAL: - if (class_range_state == RANGE_STARTED) - { - if (c == parsed_pattern[-2]) /* Optimize one-char range */ - parsed_pattern--; - else if (parsed_pattern[-2] > c) /* Check range is in order */ - { - errorcode = ERR8; - goto FAILED_BACK; - } - else - { - if (!char_is_literal && parsed_pattern[-1] == META_RANGE_LITERAL) - parsed_pattern[-1] = META_RANGE_ESCAPED; - PARSED_LITERAL(c, parsed_pattern); - } - class_range_state = RANGE_NO; - } - else /* Potential start of range */ - { - class_range_state = char_is_literal? - RANGE_OK_LITERAL : RANGE_OK_ESCAPED; - PARSED_LITERAL(c, parsed_pattern); - } - } - - /* Handle escapes in a class */ - - else - { - tempptr = ptr; - escape = PRIV(check_escape)(&ptr, ptrend, &c, &errorcode, options, - cb->cx->extra_options, TRUE, cb); - - if (errorcode != 0) - { - if ((extra_options & PCRE2_EXTRA_BAD_ESCAPE_IS_LITERAL) == 0) - goto FAILED; - ptr = tempptr; - if (ptr >= ptrend) c = CHAR_BACKSLASH; else - { - GETCHARINCTEST(c, ptr); /* Get character value, increment pointer */ - } - escape = 0; /* Treat as literal character */ - } - - switch(escape) - { - case 0: /* Escaped character code point is in c */ - char_is_literal = FALSE; - goto CLASS_LITERAL; - - case ESC_b: - c = CHAR_BS; /* \b is backspace in a class */ - char_is_literal = FALSE; - goto CLASS_LITERAL; - - case ESC_Q: - inescq = TRUE; /* Enter literal mode */ - goto CLASS_CONTINUE; - - case ESC_E: /* Ignore orphan \E */ - goto CLASS_CONTINUE; - - case ESC_B: /* Always an error in a class */ - case ESC_R: - case ESC_X: - errorcode = ERR7; - ptr--; - goto FAILED; - } - - /* The second part of a range can be a single-character escape - sequence (detected above), but not any of the other escapes. Perl - treats a hyphen as a literal in such circumstances. However, in Perl's - warning mode, a warning is given, so PCRE now faults it, as it is - almost certainly a mistake on the user's part. */ - - if (class_range_state == RANGE_STARTED) - { - errorcode = ERR50; - goto FAILED; /* Not CLASS_ESCAPE_FAILED; always an error */ - } - - /* Of the remaining escapes, only those that define characters are - allowed in a class. None may start a range. */ - - class_range_state = RANGE_NO; - switch(escape) - { - case ESC_N: - errorcode = ERR71; - goto FAILED; - - case ESC_H: - case ESC_h: - case ESC_V: - case ESC_v: - *parsed_pattern++ = META_ESCAPE + escape; - break; - - /* These escapes are converted to Unicode property tests when - PCRE2_UCP is set. */ - - case ESC_d: - case ESC_D: - case ESC_s: - case ESC_S: - case ESC_w: - case ESC_W: - if ((options & PCRE2_UCP) == 0) - { - *parsed_pattern++ = META_ESCAPE + escape; - } - else - { - *parsed_pattern++ = META_ESCAPE + - ((escape == ESC_d || escape == ESC_s || escape == ESC_w)? - ESC_p : ESC_P); - switch(escape) - { - case ESC_d: - case ESC_D: - *parsed_pattern++ = (PT_PC << 16) | ucp_Nd; - break; - - case ESC_s: - case ESC_S: - *parsed_pattern++ = PT_SPACE << 16; - break; - - case ESC_w: - case ESC_W: - *parsed_pattern++ = PT_WORD << 16; - break; - } - } - break; - - /* Explicit Unicode property matching */ - - case ESC_P: - case ESC_p: -#ifdef SUPPORT_UNICODE - { - BOOL negated; - uint16_t ptype = 0, pdata = 0; - if (!get_ucp(&ptr, &negated, &ptype, &pdata, &errorcode, cb)) - goto FAILED; - if (negated) escape = (escape == ESC_P)? ESC_p : ESC_P; - *parsed_pattern++ = META_ESCAPE + escape; - *parsed_pattern++ = (ptype << 16) | pdata; - } -#else - errorcode = ERR45; - goto FAILED; -#endif - break; /* End \P and \p */ - - default: /* All others are not allowed in a class */ - errorcode = ERR7; - ptr--; - goto FAILED; - } - - /* Perl gives a warning unless a following hyphen is the last character - in the class. PCRE throws an error. */ - - if (ptr < ptrend - 1 && *ptr == CHAR_MINUS && - ptr[1] != CHAR_RIGHT_SQUARE_BRACKET) - { - errorcode = ERR50; - goto FAILED; - } - } - - /* Proceed to next thing in the class. */ - - CLASS_CONTINUE: - if (ptr >= ptrend) - { - errorcode = ERR6; /* Missing terminating ']' */ - goto FAILED; - } - GETCHARINCTEST(c, ptr); - if (c == CHAR_RIGHT_SQUARE_BRACKET && !inescq) break; - } /* End of class-processing loop */ - - /* -] at the end of a class is a literal '-' */ - - if (class_range_state == RANGE_STARTED) - { - parsed_pattern[-1] = CHAR_MINUS; - class_range_state = RANGE_NO; - } - - *parsed_pattern++ = META_CLASS_END; - break; /* End of character class */ - - - /* ---- Opening parenthesis ---- */ - - case CHAR_LEFT_PARENTHESIS: - if (ptr >= ptrend) goto UNCLOSED_PARENTHESIS; - - /* If ( is not followed by ? it is either a capture or a special verb or an - alpha assertion or a positive non-atomic lookahead. */ - - if (*ptr != CHAR_QUESTION_MARK) - { - const char *vn; - - /* Handle capturing brackets (or non-capturing if auto-capture is turned - off). */ - - if (*ptr != CHAR_ASTERISK) - { - nest_depth++; - if ((options & PCRE2_NO_AUTO_CAPTURE) == 0) - { - if (cb->bracount >= MAX_GROUP_NUMBER) - { - errorcode = ERR97; - goto FAILED; - } - cb->bracount++; - *parsed_pattern++ = META_CAPTURE | cb->bracount; - } - else *parsed_pattern++ = META_NOCAPTURE; - } - - /* Do nothing for (* followed by end of pattern or ) so it gives a "bad - quantifier" error rather than "(*MARK) must have an argument". */ - - else if (ptrend - ptr <= 1 || (c = ptr[1]) == CHAR_RIGHT_PARENTHESIS) - break; - - /* Handle "alpha assertions" such as (*pla:...). Most of these are - synonyms for the historical symbolic assertions, but the script run and - non-atomic lookaround ones are new. They are distinguished by starting - with a lower case letter. Checking both ends of the alphabet makes this - work in all character codes. */ - - else if (CHMAX_255(c) && (cb->ctypes[c] & ctype_lcletter) != 0) - { - uint32_t meta; - - vn = alasnames; - if (!read_name(&ptr, ptrend, utf, 0, &offset, &name, &namelen, - &errorcode, cb)) goto FAILED; - if (ptr >= ptrend || *ptr != CHAR_COLON) - { - errorcode = ERR95; /* Malformed */ - goto FAILED; - } - - /* Scan the table of alpha assertion names */ - - for (i = 0; i < alascount; i++) - { - if (namelen == alasmeta[i].len && - PRIV(strncmp_c8)(name, vn, namelen) == 0) - break; - vn += alasmeta[i].len + 1; - } - - if (i >= alascount) - { - errorcode = ERR95; /* Alpha assertion not recognized */ - goto FAILED; - } - - /* Check for expecting an assertion condition. If so, only atomic - lookaround assertions are valid. */ - - meta = alasmeta[i].meta; - if (prev_expect_cond_assert > 0 && - (meta < META_LOOKAHEAD || meta > META_LOOKBEHINDNOT)) - { - errorcode = (meta == META_LOOKAHEAD_NA || meta == META_LOOKBEHIND_NA)? - ERR98 : ERR28; /* (Atomic) assertion expected */ - goto FAILED; - } - - /* The lookaround alphabetic synonyms can mostly be handled by jumping - to the code that handles the traditional symbolic forms. */ - - switch(meta) - { - default: - errorcode = ERR89; /* Unknown code; should never occur because */ - goto FAILED; /* the meta values come from a table above. */ - - case META_ATOMIC: - goto ATOMIC_GROUP; - - case META_LOOKAHEAD: - goto POSITIVE_LOOK_AHEAD; - - case META_LOOKAHEAD_NA: - goto POSITIVE_NONATOMIC_LOOK_AHEAD; - - case META_LOOKAHEADNOT: - goto NEGATIVE_LOOK_AHEAD; - - case META_LOOKBEHIND: - case META_LOOKBEHINDNOT: - case META_LOOKBEHIND_NA: - *parsed_pattern++ = meta; - ptr--; - goto POST_LOOKBEHIND; - - /* The script run facilities are handled here. Unicode support is - required (give an error if not, as this is a security issue). Always - record a META_SCRIPT_RUN item. Then, for the atomic version, insert - META_ATOMIC and remember that we need two META_KETs at the end. */ - - case META_SCRIPT_RUN: - case META_ATOMIC_SCRIPT_RUN: -#ifdef SUPPORT_UNICODE - *parsed_pattern++ = META_SCRIPT_RUN; - nest_depth++; - ptr++; - if (meta == META_ATOMIC_SCRIPT_RUN) - { - *parsed_pattern++ = META_ATOMIC; - if (top_nest == NULL) top_nest = (nest_save *)(cb->start_workspace); - else if (++top_nest >= end_nests) - { - errorcode = ERR84; - goto FAILED; - } - top_nest->nest_depth = nest_depth; - top_nest->flags = NSF_ATOMICSR; - top_nest->options = options & PARSE_TRACKED_OPTIONS; - } - break; -#else /* SUPPORT_UNICODE */ - errorcode = ERR96; - goto FAILED; -#endif - } - } - - - /* ---- Handle (*VERB) and (*VERB:NAME) ---- */ - - else - { - vn = verbnames; - if (!read_name(&ptr, ptrend, utf, 0, &offset, &name, &namelen, - &errorcode, cb)) goto FAILED; - if (ptr >= ptrend || (*ptr != CHAR_COLON && - *ptr != CHAR_RIGHT_PARENTHESIS)) - { - errorcode = ERR60; /* Malformed */ - goto FAILED; - } - - /* Scan the table of verb names */ - - for (i = 0; i < verbcount; i++) - { - if (namelen == verbs[i].len && - PRIV(strncmp_c8)(name, vn, namelen) == 0) - break; - vn += verbs[i].len + 1; - } - - if (i >= verbcount) - { - errorcode = ERR60; /* Verb not recognized */ - goto FAILED; - } - - /* An empty argument is treated as no argument. */ - - if (*ptr == CHAR_COLON && ptr + 1 < ptrend && - ptr[1] == CHAR_RIGHT_PARENTHESIS) - ptr++; /* Advance to the closing parens */ - - /* Check for mandatory non-empty argument; this is (*MARK) */ - - if (verbs[i].has_arg > 0 && *ptr != CHAR_COLON) - { - errorcode = ERR66; - goto FAILED; - } - - /* Remember where this verb, possibly with a preceding (*MARK), starts, - for handling quantified (*ACCEPT). */ - - verbstartptr = parsed_pattern; - okquantifier = (verbs[i].meta == META_ACCEPT); - - /* It appears that Perl allows any characters whatsoever, other than a - closing parenthesis, to appear in arguments ("names"), so we no longer - insist on letters, digits, and underscores. Perl does not, however, do - any interpretation within arguments, and has no means of including a - closing parenthesis. PCRE supports escape processing but only when it - is requested by an option. We set inverbname TRUE here, and let the - main loop take care of this so that escape and \x processing is done by - the main code above. */ - - if (*ptr++ == CHAR_COLON) /* Skip past : or ) */ - { - /* Some optional arguments can be treated as a preceding (*MARK) */ - - if (verbs[i].has_arg < 0) - { - add_after_mark = verbs[i].meta; - *parsed_pattern++ = META_MARK; - } - - /* The remaining verbs with arguments (except *MARK) need a different - opcode. */ - - else - { - *parsed_pattern++ = verbs[i].meta + - ((verbs[i].meta != META_MARK)? 0x00010000u:0); - } - - /* Set up for reading the name in the main loop. */ - - verblengthptr = parsed_pattern++; - verbnamestart = ptr; - inverbname = TRUE; - } - else /* No verb "name" argument */ - { - *parsed_pattern++ = verbs[i].meta; - } - } /* End of (*VERB) handling */ - break; /* Done with this parenthesis */ - } /* End of groups that don't start with (? */ - - - /* ---- Items starting (? ---- */ - - /* The type of item is determined by what follows (?. Handle (?| and option - changes under "default" because both need a new block on the nest stack. - Comments starting with (?# are handled above. Note that there is some - ambiguity about the sequence (?- because if a digit follows it's a relative - recursion or subroutine call whereas otherwise it's an option unsetting. */ - - if (++ptr >= ptrend) goto UNCLOSED_PARENTHESIS; - - switch(*ptr) - { - default: - if (*ptr == CHAR_MINUS && ptrend - ptr > 1 && IS_DIGIT(ptr[1])) - goto RECURSION_BYNUMBER; /* The + case is handled by CHAR_PLUS */ - - /* We now have either (?| or a (possibly empty) option setting, - optionally followed by a non-capturing group. */ - - nest_depth++; - if (top_nest == NULL) top_nest = (nest_save *)(cb->start_workspace); - else if (++top_nest >= end_nests) - { - errorcode = ERR84; - goto FAILED; - } - top_nest->nest_depth = nest_depth; - top_nest->flags = 0; - top_nest->options = options & PARSE_TRACKED_OPTIONS; - - /* Start of non-capturing group that resets the capture count for each - branch. */ - - if (*ptr == CHAR_VERTICAL_LINE) - { - top_nest->reset_group = (uint16_t)cb->bracount; - top_nest->max_group = (uint16_t)cb->bracount; - top_nest->flags |= NSF_RESET; - cb->external_flags |= PCRE2_DUPCAPUSED; - *parsed_pattern++ = META_NOCAPTURE; - ptr++; - } - - /* Scan for options imnsxJU to be set or unset. */ - - else - { - BOOL hyphenok = TRUE; - uint32_t oldoptions = options; - - top_nest->reset_group = 0; - top_nest->max_group = 0; - set = unset = 0; - optset = &set; - - /* ^ at the start unsets imnsx and disables the subsequent use of - */ - - if (ptr < ptrend && *ptr == CHAR_CIRCUMFLEX_ACCENT) - { - options &= ~(PCRE2_CASELESS|PCRE2_MULTILINE|PCRE2_NO_AUTO_CAPTURE| - PCRE2_DOTALL|PCRE2_EXTENDED|PCRE2_EXTENDED_MORE); - hyphenok = FALSE; - ptr++; - } - - while (ptr < ptrend && *ptr != CHAR_RIGHT_PARENTHESIS && - *ptr != CHAR_COLON) - { - switch (*ptr++) - { - case CHAR_MINUS: - if (!hyphenok) - { - errorcode = ERR94; - ptr--; /* Correct the offset */ - goto FAILED; - } - optset = &unset; - hyphenok = FALSE; - break; - - case CHAR_J: /* Record that it changed in the external options */ - *optset |= PCRE2_DUPNAMES; - cb->external_flags |= PCRE2_JCHANGED; - break; - - case CHAR_i: *optset |= PCRE2_CASELESS; break; - case CHAR_m: *optset |= PCRE2_MULTILINE; break; - case CHAR_n: *optset |= PCRE2_NO_AUTO_CAPTURE; break; - case CHAR_s: *optset |= PCRE2_DOTALL; break; - case CHAR_U: *optset |= PCRE2_UNGREEDY; break; - - /* If x appears twice it sets the extended extended option. */ - - case CHAR_x: - *optset |= PCRE2_EXTENDED; - if (ptr < ptrend && *ptr == CHAR_x) - { - *optset |= PCRE2_EXTENDED_MORE; - ptr++; - } - break; - - default: - errorcode = ERR11; - ptr--; /* Correct the offset */ - goto FAILED; - } - } - - /* If we are setting extended without extended-more, ensure that any - existing extended-more gets unset. Also, unsetting extended must also - unset extended-more. */ - - if ((set & (PCRE2_EXTENDED|PCRE2_EXTENDED_MORE)) == PCRE2_EXTENDED || - (unset & PCRE2_EXTENDED) != 0) - unset |= PCRE2_EXTENDED_MORE; - - options = (options | set) & (~unset); - - /* If the options ended with ')' this is not the start of a nested - group with option changes, so the options change at this level. - In this case, if the previous level set up a nest block, discard the - one we have just created. Otherwise adjust it for the previous level. - If the options ended with ':' we are starting a non-capturing group, - possibly with an options setting. */ - - if (ptr >= ptrend) goto UNCLOSED_PARENTHESIS; - if (*ptr++ == CHAR_RIGHT_PARENTHESIS) - { - nest_depth--; /* This is not a nested group after all. */ - if (top_nest > (nest_save *)(cb->start_workspace) && - (top_nest-1)->nest_depth == nest_depth) top_nest--; - else top_nest->nest_depth = nest_depth; - } - else *parsed_pattern++ = META_NOCAPTURE; - - /* If nothing changed, no need to record. */ - - if (options != oldoptions) - { - *parsed_pattern++ = META_OPTIONS; - *parsed_pattern++ = options; - } - } /* End options processing */ - break; /* End default case after (? */ - - - /* ---- Python syntax support ---- */ - - case CHAR_P: - if (++ptr >= ptrend) goto UNCLOSED_PARENTHESIS; - - /* (?P is the same as (?, which defines a named group. */ - - if (*ptr == CHAR_LESS_THAN_SIGN) - { - terminator = CHAR_GREATER_THAN_SIGN; - goto DEFINE_NAME; - } - - /* (?P>name) is the same as (?&name), which is a recursion or subroutine - call. */ - - if (*ptr == CHAR_GREATER_THAN_SIGN) goto RECURSE_BY_NAME; - - /* (?P=name) is the same as \k, a back reference by name. Anything - else after (?P is an error. */ - - if (*ptr != CHAR_EQUALS_SIGN) - { - errorcode = ERR41; - goto FAILED; - } - if (!read_name(&ptr, ptrend, utf, CHAR_RIGHT_PARENTHESIS, &offset, &name, - &namelen, &errorcode, cb)) goto FAILED; - *parsed_pattern++ = META_BACKREF_BYNAME; - *parsed_pattern++ = namelen; - PUTOFFSET(offset, parsed_pattern); - okquantifier = TRUE; - break; /* End of (?P processing */ - - - /* ---- Recursion/subroutine calls by number ---- */ - - case CHAR_R: - i = 0; /* (?R) == (?R0) */ - ptr++; - if (ptr >= ptrend || *ptr != CHAR_RIGHT_PARENTHESIS) - { - errorcode = ERR58; - goto FAILED; - } - goto SET_RECURSION; - - /* An item starting (?- followed by a digit comes here via the "default" - case because (?- followed by a non-digit is an options setting. */ - - case CHAR_PLUS: - if (ptrend - ptr < 2 || !IS_DIGIT(ptr[1])) - { - errorcode = ERR29; /* Missing number */ - goto FAILED; - } - /* Fall through */ - - case CHAR_0: case CHAR_1: case CHAR_2: case CHAR_3: case CHAR_4: - case CHAR_5: case CHAR_6: case CHAR_7: case CHAR_8: case CHAR_9: - RECURSION_BYNUMBER: - if (!read_number(&ptr, ptrend, - (IS_DIGIT(*ptr))? -1:(int)(cb->bracount), /* + and - are relative */ - MAX_GROUP_NUMBER, ERR61, - &i, &errorcode)) goto FAILED; - if (i < 0) /* NB (?0) is permitted */ - { - errorcode = ERR15; /* Unknown group */ - goto FAILED_BACK; - } - if (ptr >= ptrend || *ptr != CHAR_RIGHT_PARENTHESIS) - goto UNCLOSED_PARENTHESIS; - - SET_RECURSION: - *parsed_pattern++ = META_RECURSE | (uint32_t)i; - offset = (PCRE2_SIZE)(ptr - cb->start_pattern); - ptr++; - PUTOFFSET(offset, parsed_pattern); - okquantifier = TRUE; - break; /* End of recursive call by number handling */ - - - /* ---- Recursion/subroutine calls by name ---- */ - - case CHAR_AMPERSAND: - RECURSE_BY_NAME: - if (!read_name(&ptr, ptrend, utf, CHAR_RIGHT_PARENTHESIS, &offset, &name, - &namelen, &errorcode, cb)) goto FAILED; - *parsed_pattern++ = META_RECURSE_BYNAME; - *parsed_pattern++ = namelen; - PUTOFFSET(offset, parsed_pattern); - okquantifier = TRUE; - break; - - /* ---- Callout with numerical or string argument ---- */ - - case CHAR_C: - if (++ptr >= ptrend) goto UNCLOSED_PARENTHESIS; - - /* If the previous item was a condition starting (?(? an assertion, - optionally preceded by a callout, is expected. This is checked later on, - during actual compilation. However we need to identify this kind of - assertion in this pass because it must not be qualified. The value of - expect_cond_assert is set to 2 after (?(? is processed. We decrement it - for a callout - still leaving a positive value that identifies the - assertion. Multiple callouts or any other items will make it zero or - less, which doesn't matter because they will cause an error later. */ - - expect_cond_assert = prev_expect_cond_assert - 1; - - /* If previous_callout is not NULL, it means this follows a previous - callout. If it was a manual callout, do nothing; this means its "length - of next pattern item" field will remain zero. If it was an automatic - callout, abolish it. */ - - if (previous_callout != NULL && (options & PCRE2_AUTO_CALLOUT) != 0 && - previous_callout == parsed_pattern - 4 && - parsed_pattern[-1] == 255) - parsed_pattern = previous_callout; - - /* Save for updating next pattern item length, and skip one item before - completing. */ - - previous_callout = parsed_pattern; - after_manual_callout = 1; - - /* Handle a string argument; specific delimiter is required. */ - - if (*ptr != CHAR_RIGHT_PARENTHESIS && !IS_DIGIT(*ptr)) - { - PCRE2_SIZE calloutlength; - PCRE2_SPTR startptr = ptr; - - delimiter = 0; - for (i = 0; PRIV(callout_start_delims)[i] != 0; i++) - { - if (*ptr == PRIV(callout_start_delims)[i]) - { - delimiter = PRIV(callout_end_delims)[i]; - break; - } - } - if (delimiter == 0) - { - errorcode = ERR82; - goto FAILED; - } - - *parsed_pattern = META_CALLOUT_STRING; - parsed_pattern += 3; /* Skip pattern info */ - - for (;;) - { - if (++ptr >= ptrend) - { - errorcode = ERR81; - ptr = startptr; /* To give a more useful message */ - goto FAILED; - } - if (*ptr == delimiter && (++ptr >= ptrend || *ptr != delimiter)) - break; - } - - calloutlength = (PCRE2_SIZE)(ptr - startptr); - if (calloutlength > UINT32_MAX) - { - errorcode = ERR72; - goto FAILED; - } - *parsed_pattern++ = (uint32_t)calloutlength; - offset = (PCRE2_SIZE)(startptr - cb->start_pattern); - PUTOFFSET(offset, parsed_pattern); - } - - /* Handle a callout with an optional numerical argument, which must be - less than or equal to 255. A missing argument gives 0. */ - - else - { - int n = 0; - *parsed_pattern = META_CALLOUT_NUMBER; /* Numerical callout */ - parsed_pattern += 3; /* Skip pattern info */ - while (ptr < ptrend && IS_DIGIT(*ptr)) - { - n = n * 10 + *ptr++ - CHAR_0; - if (n > 255) - { - errorcode = ERR38; - goto FAILED; - } - } - *parsed_pattern++ = n; - } - - /* Both formats must have a closing parenthesis */ - - if (ptr >= ptrend || *ptr != CHAR_RIGHT_PARENTHESIS) - { - errorcode = ERR39; - goto FAILED; - } - ptr++; - - /* Remember the offset to the next item in the pattern, and set a default - length. This should get updated after the next item is read. */ - - previous_callout[1] = (uint32_t)(ptr - cb->start_pattern); - previous_callout[2] = 0; - break; /* End callout */ - - - /* ---- Conditional group ---- */ - - /* A condition can be an assertion, a number (referring to a numbered - group's having been set), a name (referring to a named group), or 'R', - referring to overall recursion. R and R&name are also permitted - for recursion state tests. Numbers may be preceded by + or - to specify a - relative group number. - - There are several syntaxes for testing a named group: (?(name)) is used - by Python; Perl 5.10 onwards uses (?() or (?('name')). - - There are two unfortunate ambiguities. 'R' can be the recursive thing or - the name 'R' (and similarly for 'R' followed by digits). 'DEFINE' can be - the Perl DEFINE feature or the Python named test. We look for a name - first; if not found, we try the other case. - - For compatibility with auto-callouts, we allow a callout to be specified - before a condition that is an assertion. */ - - case CHAR_LEFT_PARENTHESIS: - if (++ptr >= ptrend) goto UNCLOSED_PARENTHESIS; - nest_depth++; - - /* If the next character is ? or * there must be an assertion next - (optionally preceded by a callout). We do not check this here, but - instead we set expect_cond_assert to 2. If this is still greater than - zero (callouts decrement it) when the next assertion is read, it will be - marked as a condition that must not be repeated. A value greater than - zero also causes checking that an assertion (possibly with callout) - follows. */ - - if (*ptr == CHAR_QUESTION_MARK || *ptr == CHAR_ASTERISK) - { - *parsed_pattern++ = META_COND_ASSERT; - ptr--; /* Pull pointer back to the opening parenthesis. */ - expect_cond_assert = 2; - break; /* End of conditional */ - } - - /* Handle (?([+-]number)... */ - - if (read_number(&ptr, ptrend, cb->bracount, MAX_GROUP_NUMBER, ERR61, &i, - &errorcode)) - { - if (i <= 0) - { - errorcode = ERR15; - goto FAILED; - } - *parsed_pattern++ = META_COND_NUMBER; - offset = (PCRE2_SIZE)(ptr - cb->start_pattern - 2); - PUTOFFSET(offset, parsed_pattern); - *parsed_pattern++ = i; - } - else if (errorcode != 0) goto FAILED; /* Number too big */ - - /* No number found. Handle the special case (?(VERSION[>]=n.m)... */ - - else if (ptrend - ptr >= 10 && - PRIV(strncmp_c8)(ptr, STRING_VERSION, 7) == 0 && - ptr[7] != CHAR_RIGHT_PARENTHESIS) - { - uint32_t ge = 0; - int major = 0; - int minor = 0; - - ptr += 7; - if (*ptr == CHAR_GREATER_THAN_SIGN) - { - ge = 1; - ptr++; - } - - /* NOTE: cannot write IS_DIGIT(*(++ptr)) here because IS_DIGIT - references its argument twice. */ - - if (*ptr != CHAR_EQUALS_SIGN || (ptr++, !IS_DIGIT(*ptr))) - goto BAD_VERSION_CONDITION; - - if (!read_number(&ptr, ptrend, -1, 1000, ERR79, &major, &errorcode)) - goto FAILED; - - if (ptr >= ptrend) goto BAD_VERSION_CONDITION; - if (*ptr == CHAR_DOT) - { - if (++ptr >= ptrend || !IS_DIGIT(*ptr)) goto BAD_VERSION_CONDITION; - minor = (*ptr++ - CHAR_0) * 10; - if (ptr >= ptrend) goto BAD_VERSION_CONDITION; - if (IS_DIGIT(*ptr)) minor += *ptr++ - CHAR_0; - if (ptr >= ptrend || *ptr != CHAR_RIGHT_PARENTHESIS) - goto BAD_VERSION_CONDITION; - } - - *parsed_pattern++ = META_COND_VERSION; - *parsed_pattern++ = ge; - *parsed_pattern++ = major; - *parsed_pattern++ = minor; - } - - /* All the remaining cases now require us to read a name. We cannot at - this stage distinguish ambiguous cases such as (?(R12) which might be a - recursion test by number or a name, because the named groups have not yet - all been identified. Those cases are treated as names, but given a - different META code. */ - - else - { - BOOL was_r_ampersand = FALSE; - - if (*ptr == CHAR_R && ptrend - ptr > 1 && ptr[1] == CHAR_AMPERSAND) - { - terminator = CHAR_RIGHT_PARENTHESIS; - was_r_ampersand = TRUE; - ptr++; - } - else if (*ptr == CHAR_LESS_THAN_SIGN) - terminator = CHAR_GREATER_THAN_SIGN; - else if (*ptr == CHAR_APOSTROPHE) - terminator = CHAR_APOSTROPHE; - else - { - terminator = CHAR_RIGHT_PARENTHESIS; - ptr--; /* Point to char before name */ - } - if (!read_name(&ptr, ptrend, utf, terminator, &offset, &name, &namelen, - &errorcode, cb)) goto FAILED; - - /* Handle (?(R&name) */ - - if (was_r_ampersand) - { - *parsed_pattern = META_COND_RNAME; - ptr--; /* Back to closing parens */ - } - - /* Handle (?(name). If the name is "DEFINE" we identify it with a - special code. Likewise if the name consists of R followed only by - digits. Otherwise, handle it like a quoted name. */ - - else if (terminator == CHAR_RIGHT_PARENTHESIS) - { - if (namelen == 6 && PRIV(strncmp_c8)(name, STRING_DEFINE, 6) == 0) - *parsed_pattern = META_COND_DEFINE; - else - { - for (i = 1; i < (int)namelen; i++) - if (!IS_DIGIT(name[i])) break; - *parsed_pattern = (*name == CHAR_R && i >= (int)namelen)? - META_COND_RNUMBER : META_COND_NAME; - } - ptr--; /* Back to closing parens */ - } - - /* Handle (?('name') or (?() */ - - else *parsed_pattern = META_COND_NAME; - - /* All these cases except DEFINE end with the name length and offset; - DEFINE just has an offset (for the "too many branches" error). */ - - if (*parsed_pattern++ != META_COND_DEFINE) *parsed_pattern++ = namelen; - PUTOFFSET(offset, parsed_pattern); - } /* End cases that read a name */ - - /* Check the closing parenthesis of the condition */ - - if (ptr >= ptrend || *ptr != CHAR_RIGHT_PARENTHESIS) - { - errorcode = ERR24; - goto FAILED; - } - ptr++; - break; /* End of condition processing */ - - - /* ---- Atomic group ---- */ - - case CHAR_GREATER_THAN_SIGN: - ATOMIC_GROUP: /* Come from (*atomic: */ - *parsed_pattern++ = META_ATOMIC; - nest_depth++; - ptr++; - break; - - - /* ---- Lookahead assertions ---- */ - - case CHAR_EQUALS_SIGN: - POSITIVE_LOOK_AHEAD: /* Come from (*pla: */ - *parsed_pattern++ = META_LOOKAHEAD; - ptr++; - goto POST_ASSERTION; - - case CHAR_ASTERISK: - POSITIVE_NONATOMIC_LOOK_AHEAD: /* Come from (?* */ - *parsed_pattern++ = META_LOOKAHEAD_NA; - ptr++; - goto POST_ASSERTION; - - case CHAR_EXCLAMATION_MARK: - NEGATIVE_LOOK_AHEAD: /* Come from (*nla: */ - *parsed_pattern++ = META_LOOKAHEADNOT; - ptr++; - goto POST_ASSERTION; - - - /* ---- Lookbehind assertions ---- */ - - /* (?< followed by = or ! or * is a lookbehind assertion. Otherwise (?< - is the start of the name of a capturing group. */ - - case CHAR_LESS_THAN_SIGN: - if (ptrend - ptr <= 1 || - (ptr[1] != CHAR_EQUALS_SIGN && - ptr[1] != CHAR_EXCLAMATION_MARK && - ptr[1] != CHAR_ASTERISK)) - { - terminator = CHAR_GREATER_THAN_SIGN; - goto DEFINE_NAME; - } - *parsed_pattern++ = (ptr[1] == CHAR_EQUALS_SIGN)? - META_LOOKBEHIND : (ptr[1] == CHAR_EXCLAMATION_MARK)? - META_LOOKBEHINDNOT : META_LOOKBEHIND_NA; - - POST_LOOKBEHIND: /* Come from (*plb: (*naplb: and (*nlb: */ - *has_lookbehind = TRUE; - offset = (PCRE2_SIZE)(ptr - cb->start_pattern - 2); - PUTOFFSET(offset, parsed_pattern); - ptr += 2; - /* Fall through */ - - /* If the previous item was a condition starting (?(? an assertion, - optionally preceded by a callout, is expected. This is checked later on, - during actual compilation. However we need to identify this kind of - assertion in this pass because it must not be qualified. The value of - expect_cond_assert is set to 2 after (?(? is processed. We decrement it - for a callout - still leaving a positive value that identifies the - assertion. Multiple callouts or any other items will make it zero or - less, which doesn't matter because they will cause an error later. */ - - POST_ASSERTION: - nest_depth++; - if (prev_expect_cond_assert > 0) - { - if (top_nest == NULL) top_nest = (nest_save *)(cb->start_workspace); - else if (++top_nest >= end_nests) - { - errorcode = ERR84; - goto FAILED; - } - top_nest->nest_depth = nest_depth; - top_nest->flags = NSF_CONDASSERT; - top_nest->options = options & PARSE_TRACKED_OPTIONS; - } - break; - - - /* ---- Define a named group ---- */ - - /* A named group may be defined as (?'name') or (?). In the latter - case we jump to DEFINE_NAME from the disambiguation of (?< above with the - terminator set to '>'. */ - - case CHAR_APOSTROPHE: - terminator = CHAR_APOSTROPHE; /* Terminator */ - - DEFINE_NAME: - if (!read_name(&ptr, ptrend, utf, terminator, &offset, &name, &namelen, - &errorcode, cb)) goto FAILED; - - /* We have a name for this capturing group. It is also assigned a number, - which is its primary means of identification. */ - - if (cb->bracount >= MAX_GROUP_NUMBER) - { - errorcode = ERR97; - goto FAILED; - } - cb->bracount++; - *parsed_pattern++ = META_CAPTURE | cb->bracount; - nest_depth++; - - /* Check not too many names */ - - if (cb->names_found >= MAX_NAME_COUNT) - { - errorcode = ERR49; - goto FAILED; - } - - /* Adjust the entry size to accommodate the longest name found. */ - - if (namelen + IMM2_SIZE + 1 > cb->name_entry_size) - cb->name_entry_size = (uint16_t)(namelen + IMM2_SIZE + 1); - - /* Scan the list to check for duplicates. For duplicate names, if the - number is the same, break the loop, which causes the name to be - discarded; otherwise, if DUPNAMES is not set, give an error. - If it is set, allow the name with a different number, but continue - scanning in case this is a duplicate with the same number. For - non-duplicate names, give an error if the number is duplicated. */ - - isdupname = FALSE; - ng = cb->named_groups; - for (i = 0; i < cb->names_found; i++, ng++) - { - if (namelen == ng->length && - PRIV(strncmp)(name, ng->name, (PCRE2_SIZE)namelen) == 0) - { - if (ng->number == cb->bracount) break; - if ((options & PCRE2_DUPNAMES) == 0) - { - errorcode = ERR43; - goto FAILED; - } - isdupname = ng->isdup = TRUE; /* Mark as a duplicate */ - cb->dupnames = TRUE; /* Duplicate names exist */ - } - else if (ng->number == cb->bracount) - { - errorcode = ERR65; - goto FAILED; - } - } - - if (i < cb->names_found) break; /* Ignore duplicate with same number */ - - /* Increase the list size if necessary */ - - if (cb->names_found >= cb->named_group_list_size) - { - uint32_t newsize = cb->named_group_list_size * 2; - named_group *newspace = - cb->cx->memctl.malloc(newsize * sizeof(named_group), - cb->cx->memctl.memory_data); - if (newspace == NULL) - { - errorcode = ERR21; - goto FAILED; - } - - memcpy(newspace, cb->named_groups, - cb->named_group_list_size * sizeof(named_group)); - if (cb->named_group_list_size > NAMED_GROUP_LIST_SIZE) - cb->cx->memctl.free((void *)cb->named_groups, - cb->cx->memctl.memory_data); - cb->named_groups = newspace; - cb->named_group_list_size = newsize; - } - - /* Add this name to the list */ - - cb->named_groups[cb->names_found].name = name; - cb->named_groups[cb->names_found].length = (uint16_t)namelen; - cb->named_groups[cb->names_found].number = cb->bracount; - cb->named_groups[cb->names_found].isdup = (uint16_t)isdupname; - cb->names_found++; - break; - } /* End of (? switch */ - break; /* End of ( handling */ - - - /* ---- Branch terminators ---- */ - - /* Alternation: reset the capture count if we are in a (?| group. */ - - case CHAR_VERTICAL_LINE: - if (top_nest != NULL && top_nest->nest_depth == nest_depth && - (top_nest->flags & NSF_RESET) != 0) - { - if (cb->bracount > top_nest->max_group) - top_nest->max_group = (uint16_t)cb->bracount; - cb->bracount = top_nest->reset_group; - } - *parsed_pattern++ = META_ALT; - break; - - /* End of group; reset the capture count to the maximum if we are in a (?| - group and/or reset the options that are tracked during parsing. Disallow - quantifier for a condition that is an assertion. */ - - case CHAR_RIGHT_PARENTHESIS: - okquantifier = TRUE; - if (top_nest != NULL && top_nest->nest_depth == nest_depth) - { - options = (options & ~PARSE_TRACKED_OPTIONS) | top_nest->options; - if ((top_nest->flags & NSF_RESET) != 0 && - top_nest->max_group > cb->bracount) - cb->bracount = top_nest->max_group; - if ((top_nest->flags & NSF_CONDASSERT) != 0) - okquantifier = FALSE; - - if ((top_nest->flags & NSF_ATOMICSR) != 0) - { - *parsed_pattern++ = META_KET; - } - - if (top_nest == (nest_save *)(cb->start_workspace)) top_nest = NULL; - else top_nest--; - } - if (nest_depth == 0) /* Unmatched closing parenthesis */ - { - errorcode = ERR22; - goto FAILED_BACK; - } - nest_depth--; - *parsed_pattern++ = META_KET; - break; - } /* End of switch on pattern character */ - } /* End of main character scan loop */ - -/* End of pattern reached. Check for missing ) at the end of a verb name. */ - -if (inverbname && ptr >= ptrend) - { - errorcode = ERR60; - goto FAILED; - } - -/* Manage callout for the final item */ - -PARSED_END: -parsed_pattern = manage_callouts(ptr, &previous_callout, auto_callout, - parsed_pattern, cb); - -/* Insert trailing items for word and line matching (features provided for the -benefit of pcre2grep). */ - -if ((extra_options & PCRE2_EXTRA_MATCH_LINE) != 0) - { - *parsed_pattern++ = META_KET; - *parsed_pattern++ = META_DOLLAR; - } -else if ((extra_options & PCRE2_EXTRA_MATCH_WORD) != 0) - { - *parsed_pattern++ = META_KET; - *parsed_pattern++ = META_ESCAPE + ESC_b; - } - -/* Terminate the parsed pattern, then return success if all groups are closed. -Otherwise we have unclosed parentheses. */ - -if (parsed_pattern >= parsed_pattern_end) - { - errorcode = ERR63; /* Internal error (parsed pattern overflow) */ - goto FAILED; - } - -*parsed_pattern = META_END; -if (nest_depth == 0) return 0; - -UNCLOSED_PARENTHESIS: -errorcode = ERR14; - -/* Come here for all failures. */ - -FAILED: -cb->erroroffset = (PCRE2_SIZE)(ptr - cb->start_pattern); -return errorcode; - -/* Some errors need to indicate the previous character. */ - -FAILED_BACK: -ptr--; -goto FAILED; - -/* This failure happens several times. */ - -BAD_VERSION_CONDITION: -errorcode = ERR79; -goto FAILED; -} - - - -/************************************************* -* Find first significant opcode * -*************************************************/ - -/* This is called by several functions that scan a compiled expression looking -for a fixed first character, or an anchoring opcode etc. It skips over things -that do not influence this. For some calls, it makes sense to skip negative -forward and all backward assertions, and also the \b assertion; for others it -does not. - -Arguments: - code pointer to the start of the group - skipassert TRUE if certain assertions are to be skipped - -Returns: pointer to the first significant opcode -*/ - -static const PCRE2_UCHAR* -first_significant_code(PCRE2_SPTR code, BOOL skipassert) -{ -for (;;) - { - switch ((int)*code) - { - case OP_ASSERT_NOT: - case OP_ASSERTBACK: - case OP_ASSERTBACK_NOT: - case OP_ASSERTBACK_NA: - if (!skipassert) return code; - do code += GET(code, 1); while (*code == OP_ALT); - code += PRIV(OP_lengths)[*code]; - break; - - case OP_WORD_BOUNDARY: - case OP_NOT_WORD_BOUNDARY: - if (!skipassert) return code; - /* Fall through */ - - case OP_CALLOUT: - case OP_CREF: - case OP_DNCREF: - case OP_RREF: - case OP_DNRREF: - case OP_FALSE: - case OP_TRUE: - code += PRIV(OP_lengths)[*code]; - break; - - case OP_CALLOUT_STR: - code += GET(code, 1 + 2*LINK_SIZE); - break; - - case OP_SKIPZERO: - code += 2 + GET(code, 2) + LINK_SIZE; - break; - - case OP_COND: - case OP_SCOND: - if (code[1+LINK_SIZE] != OP_FALSE || /* Not DEFINE */ - code[GET(code, 1)] != OP_KET) /* More than one branch */ - return code; - code += GET(code, 1) + 1 + LINK_SIZE; - break; - - case OP_MARK: - case OP_COMMIT_ARG: - case OP_PRUNE_ARG: - case OP_SKIP_ARG: - case OP_THEN_ARG: - code += code[1] + PRIV(OP_lengths)[*code]; - break; - - default: - return code; - } - } -/* Control never reaches here */ -} - - - -#ifdef SUPPORT_UNICODE -/************************************************* -* Get othercase range * -*************************************************/ - -/* This function is passed the start and end of a class range in UCP mode. It -searches up the characters, looking for ranges of characters in the "other" -case. Each call returns the next one, updating the start address. A character -with multiple other cases is returned on its own with a special return value. - -Arguments: - cptr points to starting character value; updated - d end value - ocptr where to put start of othercase range - odptr where to put end of othercase range - -Yield: -1 when no more - 0 when a range is returned - >0 the CASESET offset for char with multiple other cases - in this case, ocptr contains the original -*/ - -static int -get_othercase_range(uint32_t *cptr, uint32_t d, uint32_t *ocptr, - uint32_t *odptr) -{ -uint32_t c, othercase, next; -unsigned int co; - -/* Find the first character that has an other case. If it has multiple other -cases, return its case offset value. */ - -for (c = *cptr; c <= d; c++) - { - if ((co = UCD_CASESET(c)) != 0) - { - *ocptr = c++; /* Character that has the set */ - *cptr = c; /* Rest of input range */ - return (int)co; - } - if ((othercase = UCD_OTHERCASE(c)) != c) break; - } - -if (c > d) return -1; /* Reached end of range */ - -/* Found a character that has a single other case. Search for the end of the -range, which is either the end of the input range, or a character that has zero -or more than one other cases. */ - -*ocptr = othercase; -next = othercase + 1; - -for (++c; c <= d; c++) - { - if ((co = UCD_CASESET(c)) != 0 || UCD_OTHERCASE(c) != next) break; - next++; - } - -*odptr = next - 1; /* End of othercase range */ -*cptr = c; /* Rest of input range */ -return 0; -} -#endif /* SUPPORT_UNICODE */ - - - -/************************************************* -* Add a character or range to a class (internal) * -*************************************************/ - -/* This function packages up the logic of adding a character or range of -characters to a class. The character values in the arguments will be within the -valid values for the current mode (8-bit, 16-bit, UTF, etc). This function is -called only from within the "add to class" group of functions, some of which -are recursive and mutually recursive. The external entry point is -add_to_class(). - -Arguments: - classbits the bit map for characters < 256 - uchardptr points to the pointer for extra data - options the options word - cb compile data - start start of range character - end end of range character - -Returns: the number of < 256 characters added - the pointer to extra data is updated -*/ - -static unsigned int -add_to_class_internal(uint8_t *classbits, PCRE2_UCHAR **uchardptr, - uint32_t options, compile_block *cb, uint32_t start, uint32_t end) -{ -uint32_t c; -uint32_t classbits_end = (end <= 0xff ? end : 0xff); -unsigned int n8 = 0; - -/* If caseless matching is required, scan the range and process alternate -cases. In Unicode, there are 8-bit characters that have alternate cases that -are greater than 255 and vice-versa. Sometimes we can just extend the original -range. */ - -if ((options & PCRE2_CASELESS) != 0) - { -#ifdef SUPPORT_UNICODE - if ((options & (PCRE2_UTF|PCRE2_UCP)) != 0) - { - int rc; - uint32_t oc, od; - - options &= ~PCRE2_CASELESS; /* Remove for recursive calls */ - c = start; - - while ((rc = get_othercase_range(&c, end, &oc, &od)) >= 0) - { - /* Handle a single character that has more than one other case. */ - - if (rc > 0) n8 += add_list_to_class_internal(classbits, uchardptr, options, cb, - PRIV(ucd_caseless_sets) + rc, oc); - - /* Do nothing if the other case range is within the original range. */ - - else if (oc >= cb->class_range_start && od <= cb->class_range_end) continue; - - /* Extend the original range if there is overlap, noting that if oc < c, we - can't have od > end because a subrange is always shorter than the basic - range. Otherwise, use a recursive call to add the additional range. */ - - else if (oc < start && od >= start - 1) start = oc; /* Extend downwards */ - else if (od > end && oc <= end + 1) - { - end = od; /* Extend upwards */ - if (end > classbits_end) classbits_end = (end <= 0xff ? end : 0xff); - } - else n8 += add_to_class_internal(classbits, uchardptr, options, cb, oc, od); - } - } - else -#endif /* SUPPORT_UNICODE */ - - /* Not UTF mode */ - - for (c = start; c <= classbits_end; c++) - { - SETBIT(classbits, cb->fcc[c]); - n8++; - } - } - -/* Now handle the originally supplied range. Adjust the final value according -to the bit length - this means that the same lists of (e.g.) horizontal spaces -can be used in all cases. */ - -if ((options & PCRE2_UTF) == 0 && end > MAX_NON_UTF_CHAR) - end = MAX_NON_UTF_CHAR; - -if (start > cb->class_range_start && end < cb->class_range_end) return n8; - -/* Use the bitmap for characters < 256. Otherwise use extra data.*/ - -for (c = start; c <= classbits_end; c++) - { - /* Regardless of start, c will always be <= 255. */ - SETBIT(classbits, c); - n8++; - } - -#ifdef SUPPORT_WIDE_CHARS -if (start <= 0xff) start = 0xff + 1; - -if (end >= start) - { - PCRE2_UCHAR *uchardata = *uchardptr; - -#ifdef SUPPORT_UNICODE - if ((options & PCRE2_UTF) != 0) - { - if (start < end) - { - *uchardata++ = XCL_RANGE; - uchardata += PRIV(ord2utf)(start, uchardata); - uchardata += PRIV(ord2utf)(end, uchardata); - } - else if (start == end) - { - *uchardata++ = XCL_SINGLE; - uchardata += PRIV(ord2utf)(start, uchardata); - } - } - else -#endif /* SUPPORT_UNICODE */ - - /* Without UTF support, character values are constrained by the bit length, - and can only be > 256 for 16-bit and 32-bit libraries. */ - -#if PCRE2_CODE_UNIT_WIDTH == 8 - {} -#else - if (start < end) - { - *uchardata++ = XCL_RANGE; - *uchardata++ = start; - *uchardata++ = end; - } - else if (start == end) - { - *uchardata++ = XCL_SINGLE; - *uchardata++ = start; - } -#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */ - *uchardptr = uchardata; /* Updata extra data pointer */ - } -#else /* SUPPORT_WIDE_CHARS */ - (void)uchardptr; /* Avoid compiler warning */ -#endif /* SUPPORT_WIDE_CHARS */ - -return n8; /* Number of 8-bit characters */ -} - - - -#ifdef SUPPORT_UNICODE -/************************************************* -* Add a list of characters to a class (internal) * -*************************************************/ - -/* This function is used for adding a list of case-equivalent characters to a -class when in UTF mode. This function is called only from within -add_to_class_internal(), with which it is mutually recursive. - -Arguments: - classbits the bit map for characters < 256 - uchardptr points to the pointer for extra data - options the options word - cb contains pointers to tables etc. - p points to row of 32-bit values, terminated by NOTACHAR - except character to omit; this is used when adding lists of - case-equivalent characters to avoid including the one we - already know about - -Returns: the number of < 256 characters added - the pointer to extra data is updated -*/ - -static unsigned int -add_list_to_class_internal(uint8_t *classbits, PCRE2_UCHAR **uchardptr, - uint32_t options, compile_block *cb, const uint32_t *p, unsigned int except) -{ -unsigned int n8 = 0; -while (p[0] < NOTACHAR) - { - unsigned int n = 0; - if (p[0] != except) - { - while(p[n+1] == p[0] + n + 1) n++; - n8 += add_to_class_internal(classbits, uchardptr, options, cb, p[0], p[n]); - } - p += n + 1; - } -return n8; -} -#endif - - - -/************************************************* -* External entry point for add range to class * -*************************************************/ - -/* This function sets the overall range so that the internal functions can try -to avoid duplication when handling case-independence. - -Arguments: - classbits the bit map for characters < 256 - uchardptr points to the pointer for extra data - options the options word - cb compile data - start start of range character - end end of range character - -Returns: the number of < 256 characters added - the pointer to extra data is updated -*/ - -static unsigned int -add_to_class(uint8_t *classbits, PCRE2_UCHAR **uchardptr, uint32_t options, - compile_block *cb, uint32_t start, uint32_t end) -{ -cb->class_range_start = start; -cb->class_range_end = end; -return add_to_class_internal(classbits, uchardptr, options, cb, start, end); -} - - -/************************************************* -* External entry point for add list to class * -*************************************************/ - -/* This function is used for adding a list of horizontal or vertical whitespace -characters to a class. The list must be in order so that ranges of characters -can be detected and handled appropriately. This function sets the overall range -so that the internal functions can try to avoid duplication when handling -case-independence. - -Arguments: - classbits the bit map for characters < 256 - uchardptr points to the pointer for extra data - options the options word - cb contains pointers to tables etc. - p points to row of 32-bit values, terminated by NOTACHAR - except character to omit; this is used when adding lists of - case-equivalent characters to avoid including the one we - already know about - -Returns: the number of < 256 characters added - the pointer to extra data is updated -*/ - -static unsigned int -add_list_to_class(uint8_t *classbits, PCRE2_UCHAR **uchardptr, uint32_t options, - compile_block *cb, const uint32_t *p, unsigned int except) -{ -unsigned int n8 = 0; -while (p[0] < NOTACHAR) - { - unsigned int n = 0; - if (p[0] != except) - { - while(p[n+1] == p[0] + n + 1) n++; - cb->class_range_start = p[0]; - cb->class_range_end = p[n]; - n8 += add_to_class_internal(classbits, uchardptr, options, cb, p[0], p[n]); - } - p += n + 1; - } -return n8; -} - - - -/************************************************* -* Add characters not in a list to a class * -*************************************************/ - -/* This function is used for adding the complement of a list of horizontal or -vertical whitespace to a class. The list must be in order. - -Arguments: - classbits the bit map for characters < 256 - uchardptr points to the pointer for extra data - options the options word - cb contains pointers to tables etc. - p points to row of 32-bit values, terminated by NOTACHAR - -Returns: the number of < 256 characters added - the pointer to extra data is updated -*/ - -static unsigned int -add_not_list_to_class(uint8_t *classbits, PCRE2_UCHAR **uchardptr, - uint32_t options, compile_block *cb, const uint32_t *p) -{ -BOOL utf = (options & PCRE2_UTF) != 0; -unsigned int n8 = 0; -if (p[0] > 0) - n8 += add_to_class(classbits, uchardptr, options, cb, 0, p[0] - 1); -while (p[0] < NOTACHAR) - { - while (p[1] == p[0] + 1) p++; - n8 += add_to_class(classbits, uchardptr, options, cb, p[0] + 1, - (p[1] == NOTACHAR) ? (utf ? 0x10ffffu : 0xffffffffu) : p[1] - 1); - p++; - } -return n8; -} - - - -/************************************************* -* Find details of duplicate group names * -*************************************************/ - -/* This is called from compile_branch() when it needs to know the index and -count of duplicates in the names table when processing named backreferences, -either directly, or as conditions. - -Arguments: - name points to the name - length the length of the name - indexptr where to put the index - countptr where to put the count of duplicates - errorcodeptr where to put an error code - cb the compile block - -Returns: TRUE if OK, FALSE if not, error code set -*/ - -static BOOL -find_dupname_details(PCRE2_SPTR name, uint32_t length, int *indexptr, - int *countptr, int *errorcodeptr, compile_block *cb) -{ -uint32_t i, groupnumber; -int count; -PCRE2_UCHAR *slot = cb->name_table; - -/* Find the first entry in the table */ - -for (i = 0; i < cb->names_found; i++) - { - if (PRIV(strncmp)(name, slot+IMM2_SIZE, length) == 0 && - slot[IMM2_SIZE+length] == 0) break; - slot += cb->name_entry_size; - } - -/* This should not occur, because this function is called only when we know we -have duplicate names. Give an internal error. */ - -if (i >= cb->names_found) - { - *errorcodeptr = ERR53; - cb->erroroffset = name - cb->start_pattern; - return FALSE; - } - -/* Record the index and then see how many duplicates there are, updating the -backref map and maximum back reference as we do. */ - -*indexptr = i; -count = 0; - -for (;;) - { - count++; - groupnumber = GET2(slot,0); - cb->backref_map |= (groupnumber < 32)? (1u << groupnumber) : 1; - if (groupnumber > cb->top_backref) cb->top_backref = groupnumber; - if (++i >= cb->names_found) break; - slot += cb->name_entry_size; - if (PRIV(strncmp)(name, slot+IMM2_SIZE, length) != 0 || - (slot+IMM2_SIZE)[length] != 0) break; - } - -*countptr = count; -return TRUE; -} - - - -/************************************************* -* Compile one branch * -*************************************************/ - -/* Scan the parsed pattern, compiling it into the a vector of PCRE2_UCHAR. If -the options are changed during the branch, the pointer is used to change the -external options bits. This function is used during the pre-compile phase when -we are trying to find out the amount of memory needed, as well as during the -real compile phase. The value of lengthptr distinguishes the two phases. - -Arguments: - optionsptr pointer to the option bits - codeptr points to the pointer to the current code point - pptrptr points to the current parsed pattern pointer - errorcodeptr points to error code variable - firstcuptr place to put the first required code unit - firstcuflagsptr place to put the first code unit flags - reqcuptr place to put the last required code unit - reqcuflagsptr place to put the last required code unit flags - bcptr points to current branch chain - cb contains pointers to tables etc. - lengthptr NULL during the real compile phase - points to length accumulator during pre-compile phase - -Returns: 0 There's been an error, *errorcodeptr is non-zero - +1 Success, this branch must match at least one character - -1 Success, this branch may match an empty string -*/ - -static int -compile_branch(uint32_t *optionsptr, PCRE2_UCHAR **codeptr, uint32_t **pptrptr, - int *errorcodeptr, uint32_t *firstcuptr, uint32_t *firstcuflagsptr, - uint32_t *reqcuptr, uint32_t *reqcuflagsptr, branch_chain *bcptr, - compile_block *cb, PCRE2_SIZE *lengthptr) -{ -int bravalue = 0; -int okreturn = -1; -int group_return = 0; -uint32_t repeat_min = 0, repeat_max = 0; /* To please picky compilers */ -uint32_t greedy_default, greedy_non_default; -uint32_t repeat_type, op_type; -uint32_t options = *optionsptr; /* May change dynamically */ -uint32_t firstcu, reqcu; -uint32_t zeroreqcu, zerofirstcu; -uint32_t escape; -uint32_t *pptr = *pptrptr; -uint32_t meta, meta_arg; -uint32_t firstcuflags, reqcuflags; -uint32_t zeroreqcuflags, zerofirstcuflags; -uint32_t req_caseopt, reqvary, tempreqvary; -PCRE2_SIZE offset = 0; -PCRE2_SIZE length_prevgroup = 0; -PCRE2_UCHAR *code = *codeptr; -PCRE2_UCHAR *last_code = code; -PCRE2_UCHAR *orig_code = code; -PCRE2_UCHAR *tempcode; -PCRE2_UCHAR *previous = NULL; -PCRE2_UCHAR op_previous; -BOOL groupsetfirstcu = FALSE; -BOOL had_accept = FALSE; -BOOL matched_char = FALSE; -BOOL previous_matched_char = FALSE; -BOOL reset_caseful = FALSE; -const uint8_t *cbits = cb->cbits; -uint8_t classbits[32]; - -/* We can fish out the UTF setting once and for all into a BOOL, but we must -not do this for other options (e.g. PCRE2_EXTENDED) because they may change -dynamically as we process the pattern. */ - -#ifdef SUPPORT_UNICODE -BOOL utf = (options & PCRE2_UTF) != 0; -BOOL ucp = (options & PCRE2_UCP) != 0; -#else /* No Unicode support */ -BOOL utf = FALSE; -#endif - -/* Helper variables for OP_XCLASS opcode (for characters > 255). We define -class_uchardata always so that it can be passed to add_to_class() always, -though it will not be used in non-UTF 8-bit cases. This avoids having to supply -alternative calls for the different cases. */ - -PCRE2_UCHAR *class_uchardata; -#ifdef SUPPORT_WIDE_CHARS -BOOL xclass; -PCRE2_UCHAR *class_uchardata_base; -#endif - -/* Set up the default and non-default settings for greediness */ - -greedy_default = ((options & PCRE2_UNGREEDY) != 0); -greedy_non_default = greedy_default ^ 1; - -/* Initialize no first unit, no required unit. REQ_UNSET means "no char -matching encountered yet". It gets changed to REQ_NONE if we hit something that -matches a non-fixed first unit; reqcu just remains unset if we never find one. - -When we hit a repeat whose minimum is zero, we may have to adjust these values -to take the zero repeat into account. This is implemented by setting them to -zerofirstcu and zeroreqcu when such a repeat is encountered. The individual -item types that can be repeated set these backoff variables appropriately. */ - -firstcu = reqcu = zerofirstcu = zeroreqcu = 0; -firstcuflags = reqcuflags = zerofirstcuflags = zeroreqcuflags = REQ_UNSET; - -/* The variable req_caseopt contains either the REQ_CASELESS bit or zero, -according to the current setting of the caseless flag. The REQ_CASELESS value -leaves the lower 28 bit empty. It is added into the firstcu or reqcu variables -to record the case status of the value. This is used only for ASCII characters. -*/ - -req_caseopt = ((options & PCRE2_CASELESS) != 0)? REQ_CASELESS : 0; - -/* Switch on next META item until the end of the branch */ - -for (;; pptr++) - { -#ifdef SUPPORT_WIDE_CHARS - BOOL xclass_has_prop; -#endif - BOOL negate_class; - BOOL should_flip_negation; - BOOL match_all_or_no_wide_chars; - BOOL possessive_quantifier; - BOOL note_group_empty; - int class_has_8bitchar; - uint32_t mclength; - uint32_t skipunits; - uint32_t subreqcu, subfirstcu; - uint32_t groupnumber; - uint32_t verbarglen, verbculen; - uint32_t subreqcuflags, subfirstcuflags; - open_capitem *oc; - PCRE2_UCHAR mcbuffer[8]; - - /* Get next META item in the pattern and its potential argument. */ - - meta = META_CODE(*pptr); - meta_arg = META_DATA(*pptr); - - /* If we are in the pre-compile phase, accumulate the length used for the - previous cycle of this loop, unless the next item is a quantifier. */ - - if (lengthptr != NULL) - { - if (code > cb->start_workspace + cb->workspace_size - - WORK_SIZE_SAFETY_MARGIN) /* Check for overrun */ - { - *errorcodeptr = (code >= cb->start_workspace + cb->workspace_size)? - ERR52 : ERR86; - return 0; - } - - /* There is at least one situation where code goes backwards: this is the - case of a zero quantifier after a class (e.g. [ab]{0}). When the quantifier - is processed, the whole class is eliminated. However, it is created first, - so we have to allow memory for it. Therefore, don't ever reduce the length - at this point. */ - - if (code < last_code) code = last_code; - - /* If the next thing is not a quantifier, we add the length of the previous - item into the total, and reset the code pointer to the start of the - workspace. Otherwise leave the previous item available to be quantified. */ - - if (meta < META_ASTERISK || meta > META_MINMAX_QUERY) - { - if (OFLOW_MAX - *lengthptr < (PCRE2_SIZE)(code - orig_code)) - { - *errorcodeptr = ERR20; /* Integer overflow */ - return 0; - } - *lengthptr += (PCRE2_SIZE)(code - orig_code); - if (*lengthptr > MAX_PATTERN_SIZE) - { - *errorcodeptr = ERR20; /* Pattern is too large */ - return 0; - } - code = orig_code; - } - - /* Remember where this code item starts so we can catch the "backwards" - case above next time round. */ - - last_code = code; - } - - /* Process the next parsed pattern item. If it is not a quantifier, remember - where it starts so that it can be quantified when a quantifier follows. - Checking for the legality of quantifiers happens in parse_regex(), except for - a quantifier after an assertion that is a condition. */ - - if (meta < META_ASTERISK || meta > META_MINMAX_QUERY) - { - previous = code; - if (matched_char && !had_accept) okreturn = 1; - } - - previous_matched_char = matched_char; - matched_char = FALSE; - note_group_empty = FALSE; - skipunits = 0; /* Default value for most subgroups */ - - switch(meta) - { - /* ===================================================================*/ - /* The branch terminates at pattern end or | or ) */ - - case META_END: - case META_ALT: - case META_KET: - *firstcuptr = firstcu; - *firstcuflagsptr = firstcuflags; - *reqcuptr = reqcu; - *reqcuflagsptr = reqcuflags; - *codeptr = code; - *pptrptr = pptr; - return okreturn; - - - /* ===================================================================*/ - /* Handle single-character metacharacters. In multiline mode, ^ disables - the setting of any following char as a first character. */ - - case META_CIRCUMFLEX: - if ((options & PCRE2_MULTILINE) != 0) - { - if (firstcuflags == REQ_UNSET) - zerofirstcuflags = firstcuflags = REQ_NONE; - *code++ = OP_CIRCM; - } - else *code++ = OP_CIRC; - break; - - case META_DOLLAR: - *code++ = ((options & PCRE2_MULTILINE) != 0)? OP_DOLLM : OP_DOLL; - break; - - /* There can never be a first char if '.' is first, whatever happens about - repeats. The value of reqcu doesn't change either. */ - - case META_DOT: - matched_char = TRUE; - if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE; - zerofirstcu = firstcu; - zerofirstcuflags = firstcuflags; - zeroreqcu = reqcu; - zeroreqcuflags = reqcuflags; - *code++ = ((options & PCRE2_DOTALL) != 0)? OP_ALLANY: OP_ANY; - break; - - - /* ===================================================================*/ - /* Empty character classes are allowed if PCRE2_ALLOW_EMPTY_CLASS is set. - Otherwise, an initial ']' is taken as a data character. When empty classes - are allowed, [] must always fail, so generate OP_FAIL, whereas [^] must - match any character, so generate OP_ALLANY. */ - - case META_CLASS_EMPTY: - case META_CLASS_EMPTY_NOT: - matched_char = TRUE; - *code++ = (meta == META_CLASS_EMPTY_NOT)? OP_ALLANY : OP_FAIL; - if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE; - zerofirstcu = firstcu; - zerofirstcuflags = firstcuflags; - break; - - - /* ===================================================================*/ - /* Non-empty character class. If the included characters are all < 256, we - build a 32-byte bitmap of the permitted characters, except in the special - case where there is only one such character. For negated classes, we build - the map as usual, then invert it at the end. However, we use a different - opcode so that data characters > 255 can be handled correctly. - - If the class contains characters outside the 0-255 range, a different - opcode is compiled. It may optionally have a bit map for characters < 256, - but those above are are explicitly listed afterwards. A flag code unit - tells whether the bitmap is present, and whether this is a negated class or - not. */ - - case META_CLASS_NOT: - case META_CLASS: - matched_char = TRUE; - negate_class = meta == META_CLASS_NOT; - - /* We can optimize the case of a single character in a class by generating - OP_CHAR or OP_CHARI if it's positive, or OP_NOT or OP_NOTI if it's - negative. In the negative case there can be no first char if this item is - first, whatever repeat count may follow. In the case of reqcu, save the - previous value for reinstating. */ - - /* NOTE: at present this optimization is not effective if the only - character in a class in 32-bit, non-UCP mode has its top bit set. */ - - if (pptr[1] < META_END && pptr[2] == META_CLASS_END) - { -#ifdef SUPPORT_UNICODE - uint32_t d; -#endif - uint32_t c = pptr[1]; - - pptr += 2; /* Move on to class end */ - if (meta == META_CLASS) /* A positive one-char class can be */ - { /* handled as a normal literal character. */ - meta = c; /* Set up the character */ - goto NORMAL_CHAR_SET; - } - - /* Handle a negative one-character class */ - - zeroreqcu = reqcu; - zeroreqcuflags = reqcuflags; - if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE; - zerofirstcu = firstcu; - zerofirstcuflags = firstcuflags; - - /* For caseless UTF or UCP mode, check whether this character has more - than one other case. If so, generate a special OP_NOTPROP item instead of - OP_NOTI. */ - -#ifdef SUPPORT_UNICODE - if ((utf||ucp) && (options & PCRE2_CASELESS) != 0 && - (d = UCD_CASESET(c)) != 0) - { - *code++ = OP_NOTPROP; - *code++ = PT_CLIST; - *code++ = d; - break; /* We are finished with this class */ - } -#endif - /* Char has only one other case, or UCP not available */ - - *code++ = ((options & PCRE2_CASELESS) != 0)? OP_NOTI: OP_NOT; - code += PUTCHAR(c, code); - break; /* We are finished with this class */ - } /* End of 1-char optimization */ - - /* Handle character classes that contain more than just one literal - character. If there are exactly two characters in a positive class, see if - they are case partners. This can be optimized to generate a caseless single - character match (which also sets first/required code units if relevant). */ - - if (meta == META_CLASS && pptr[1] < META_END && pptr[2] < META_END && - pptr[3] == META_CLASS_END) - { - uint32_t c = pptr[1]; - -#ifdef SUPPORT_UNICODE - if (UCD_CASESET(c) == 0) -#endif - { - uint32_t d; - -#ifdef SUPPORT_UNICODE - if ((utf || ucp) && c > 127) d = UCD_OTHERCASE(c); else -#endif - { -#if PCRE2_CODE_UNIT_WIDTH != 8 - if (c > 255) d = c; else -#endif - d = TABLE_GET(c, cb->fcc, c); - } - - if (c != d && pptr[2] == d) - { - pptr += 3; /* Move on to class end */ - meta = c; - if ((options & PCRE2_CASELESS) == 0) - { - reset_caseful = TRUE; - options |= PCRE2_CASELESS; - req_caseopt = REQ_CASELESS; - } - goto CLASS_CASELESS_CHAR; - } - } - } - - /* If a non-extended class contains a negative special such as \S, we need - to flip the negation flag at the end, so that support for characters > 255 - works correctly (they are all included in the class). An extended class may - need to insert specific matching or non-matching code for wide characters. - */ - - should_flip_negation = match_all_or_no_wide_chars = FALSE; - - /* Extended class (xclass) will be used when characters > 255 - might match. */ - -#ifdef SUPPORT_WIDE_CHARS - xclass = FALSE; - class_uchardata = code + LINK_SIZE + 2; /* For XCLASS items */ - class_uchardata_base = class_uchardata; /* Save the start */ -#endif - - /* For optimization purposes, we track some properties of the class: - class_has_8bitchar will be non-zero if the class contains at least one - character with a code point less than 256; xclass_has_prop will be TRUE if - Unicode property checks are present in the class. */ - - class_has_8bitchar = 0; -#ifdef SUPPORT_WIDE_CHARS - xclass_has_prop = FALSE; -#endif - - /* Initialize the 256-bit (32-byte) bit map to all zeros. We build the map - in a temporary bit of memory, in case the class contains fewer than two - 8-bit characters because in that case the compiled code doesn't use the bit - map. */ - - memset(classbits, 0, 32 * sizeof(uint8_t)); - - /* Process items until META_CLASS_END is reached. */ - - while ((meta = *(++pptr)) != META_CLASS_END) - { - /* Handle POSIX classes such as [:alpha:] etc. */ - - if (meta == META_POSIX || meta == META_POSIX_NEG) - { - BOOL local_negate = (meta == META_POSIX_NEG); - int posix_class = *(++pptr); - int taboffset, tabopt; - uint8_t pbits[32]; - - should_flip_negation = local_negate; /* Note negative special */ - - /* If matching is caseless, upper and lower are converted to alpha. - This relies on the fact that the class table starts with alpha, - lower, upper as the first 3 entries. */ - - if ((options & PCRE2_CASELESS) != 0 && posix_class <= 2) - posix_class = 0; - - /* When PCRE2_UCP is set, some of the POSIX classes are converted to - different escape sequences that use Unicode properties \p or \P. - Others that are not available via \p or \P have to generate - XCL_PROP/XCL_NOTPROP directly, which is done here. */ - -#ifdef SUPPORT_UNICODE - if ((options & PCRE2_UCP) != 0) switch(posix_class) - { - case PC_GRAPH: - case PC_PRINT: - case PC_PUNCT: - *class_uchardata++ = local_negate? XCL_NOTPROP : XCL_PROP; - *class_uchardata++ = (PCRE2_UCHAR) - ((posix_class == PC_GRAPH)? PT_PXGRAPH : - (posix_class == PC_PRINT)? PT_PXPRINT : PT_PXPUNCT); - *class_uchardata++ = 0; - xclass_has_prop = TRUE; - goto CONTINUE_CLASS; - - /* For the other POSIX classes (ascii, xdigit) we are going to - fall through to the non-UCP case and build a bit map for - characters with code points less than 256. However, if we are in - a negated POSIX class, characters with code points greater than - 255 must either all match or all not match, depending on whether - the whole class is not or is negated. For example, for - [[:^ascii:]... they must all match, whereas for [^[:^xdigit:]... - they must not. - - In the special case where there are no xclass items, this is - automatically handled by the use of OP_CLASS or OP_NCLASS, but an - explicit range is needed for OP_XCLASS. Setting a flag here - causes the range to be generated later when it is known that - OP_XCLASS is required. In the 8-bit library this is relevant only in - utf mode, since no wide characters can exist otherwise. */ - - default: -#if PCRE2_CODE_UNIT_WIDTH == 8 - if (utf) -#endif - match_all_or_no_wide_chars |= local_negate; - break; - } -#endif /* SUPPORT_UNICODE */ - - /* In the non-UCP case, or when UCP makes no difference, we build the - bit map for the POSIX class in a chunk of local store because we may - be adding and subtracting from it, and we don't want to subtract bits - that may be in the main map already. At the end we or the result into - the bit map that is being built. */ - - posix_class *= 3; - - /* Copy in the first table (always present) */ - - memcpy(pbits, cbits + posix_class_maps[posix_class], - 32 * sizeof(uint8_t)); - - /* If there is a second table, add or remove it as required. */ - - taboffset = posix_class_maps[posix_class + 1]; - tabopt = posix_class_maps[posix_class + 2]; - - if (taboffset >= 0) - { - if (tabopt >= 0) - for (int i = 0; i < 32; i++) pbits[i] |= cbits[(int)i + taboffset]; - else - for (int i = 0; i < 32; i++) pbits[i] &= ~cbits[(int)i + taboffset]; - } - - /* Now see if we need to remove any special characters. An option - value of 1 removes vertical space and 2 removes underscore. */ - - if (tabopt < 0) tabopt = -tabopt; - if (tabopt == 1) pbits[1] &= ~0x3c; - else if (tabopt == 2) pbits[11] &= 0x7f; - - /* Add the POSIX table or its complement into the main table that is - being built and we are done. */ - - if (local_negate) - for (int i = 0; i < 32; i++) classbits[i] |= (uint8_t)(~pbits[i]); - else - for (int i = 0; i < 32; i++) classbits[i] |= pbits[i]; - - /* Every class contains at least one < 256 character. */ - - class_has_8bitchar = 1; - goto CONTINUE_CLASS; /* End of POSIX handling */ - } - - /* Other than POSIX classes, the only items we should encounter are - \d-type escapes and literal characters (possibly as ranges). */ - - if (meta == META_BIGVALUE) - { - meta = *(++pptr); - goto CLASS_LITERAL; - } - - /* Any other non-literal must be an escape */ - - if (meta >= META_END) - { - if (META_CODE(meta) != META_ESCAPE) - { -#ifdef DEBUG_SHOW_PARSED - fprintf(stderr, "** Unrecognized parsed pattern item 0x%.8x " - "in character class\n", meta); -#endif - *errorcodeptr = ERR89; /* Internal error - unrecognized. */ - return 0; - } - escape = META_DATA(meta); - - /* Every class contains at least one < 256 character. */ - - class_has_8bitchar++; - - switch(escape) - { - case ESC_d: - for (int i = 0; i < 32; i++) classbits[i] |= cbits[i+cbit_digit]; - break; - - case ESC_D: - should_flip_negation = TRUE; - for (int i = 0; i < 32; i++) - classbits[i] |= (uint8_t)(~cbits[i+cbit_digit]); - break; - - case ESC_w: - for (int i = 0; i < 32; i++) classbits[i] |= cbits[i+cbit_word]; - break; - - case ESC_W: - should_flip_negation = TRUE; - for (int i = 0; i < 32; i++) - classbits[i] |= (uint8_t)(~cbits[i+cbit_word]); - break; - - /* Perl 5.004 onwards omitted VT from \s, but restored it at Perl - 5.18. Before PCRE 8.34, we had to preserve the VT bit if it was - previously set by something earlier in the character class. - Luckily, the value of CHAR_VT is 0x0b in both ASCII and EBCDIC, so - we could just adjust the appropriate bit. From PCRE 8.34 we no - longer treat \s and \S specially. */ - - case ESC_s: - for (int i = 0; i < 32; i++) classbits[i] |= cbits[i+cbit_space]; - break; - - case ESC_S: - should_flip_negation = TRUE; - for (int i = 0; i < 32; i++) - classbits[i] |= (uint8_t)(~cbits[i+cbit_space]); - break; - - /* When adding the horizontal or vertical space lists to a class, or - their complements, disable PCRE2_CASELESS, because it justs wastes - time, and in the "not-x" UTF cases can create unwanted duplicates in - the XCLASS list (provoked by characters that have more than one other - case and by both cases being in the same "not-x" sublist). */ - - case ESC_h: - (void)add_list_to_class(classbits, &class_uchardata, - options & ~PCRE2_CASELESS, cb, PRIV(hspace_list), NOTACHAR); - break; - - case ESC_H: - (void)add_not_list_to_class(classbits, &class_uchardata, - options & ~PCRE2_CASELESS, cb, PRIV(hspace_list)); - break; - - case ESC_v: - (void)add_list_to_class(classbits, &class_uchardata, - options & ~PCRE2_CASELESS, cb, PRIV(vspace_list), NOTACHAR); - break; - - case ESC_V: - (void)add_not_list_to_class(classbits, &class_uchardata, - options & ~PCRE2_CASELESS, cb, PRIV(vspace_list)); - break; - - /* If Unicode is not supported, \P and \p are not allowed and are - faulted at parse time, so will never appear here. */ - -#ifdef SUPPORT_UNICODE - case ESC_p: - case ESC_P: - { - uint32_t ptype = *(++pptr) >> 16; - uint32_t pdata = *pptr & 0xffff; - *class_uchardata++ = (escape == ESC_p)? XCL_PROP : XCL_NOTPROP; - *class_uchardata++ = ptype; - *class_uchardata++ = pdata; - xclass_has_prop = TRUE; - class_has_8bitchar--; /* Undo! */ - } - break; -#endif - } - - goto CONTINUE_CLASS; - } /* End handling \d-type escapes */ - - /* A literal character may be followed by a range meta. At parse time - there are checks for out-of-order characters, for ranges where the two - characters are equal, and for hyphens that cannot indicate a range. At - this point, therefore, no checking is needed. */ - - else - { - uint32_t c, d; - - CLASS_LITERAL: - c = d = meta; - - /* Remember if \r or \n were explicitly used */ - - if (c == CHAR_CR || c == CHAR_NL) cb->external_flags |= PCRE2_HASCRORLF; - - /* Process a character range */ - - if (pptr[1] == META_RANGE_LITERAL || pptr[1] == META_RANGE_ESCAPED) - { -#ifdef EBCDIC - BOOL range_is_literal = (pptr[1] == META_RANGE_LITERAL); -#endif - pptr += 2; - d = *pptr; - if (d == META_BIGVALUE) d = *(++pptr); - - /* Remember an explicit \r or \n, and add the range to the class. */ - - if (d == CHAR_CR || d == CHAR_NL) cb->external_flags |= PCRE2_HASCRORLF; - - /* In an EBCDIC environment, Perl treats alphabetic ranges specially - because there are holes in the encoding, and simply using the range - A-Z (for example) would include the characters in the holes. This - applies only to literal ranges; [\xC1-\xE9] is different to [A-Z]. */ - -#ifdef EBCDIC - if (range_is_literal && - (cb->ctypes[c] & ctype_letter) != 0 && - (cb->ctypes[d] & ctype_letter) != 0 && - (c <= CHAR_z) == (d <= CHAR_z)) - { - uint32_t uc = (d <= CHAR_z)? 0 : 64; - uint32_t C = c - uc; - uint32_t D = d - uc; - - if (C <= CHAR_i) - { - class_has_8bitchar += - add_to_class(classbits, &class_uchardata, options, cb, C + uc, - ((D < CHAR_i)? D : CHAR_i) + uc); - C = CHAR_j; - } - - if (C <= D && C <= CHAR_r) - { - class_has_8bitchar += - add_to_class(classbits, &class_uchardata, options, cb, C + uc, - ((D < CHAR_r)? D : CHAR_r) + uc); - C = CHAR_s; - } - - if (C <= D) - { - class_has_8bitchar += - add_to_class(classbits, &class_uchardata, options, cb, C + uc, - D + uc); - } - } - else -#endif - /* Not an EBCDIC special range */ - - class_has_8bitchar += - add_to_class(classbits, &class_uchardata, options, cb, c, d); - goto CONTINUE_CLASS; /* Go get the next char in the class */ - } /* End of range handling */ - - - /* Handle a single character. */ - - class_has_8bitchar += - add_to_class(classbits, &class_uchardata, options, cb, meta, meta); - } - - /* Continue to the next item in the class. */ - - CONTINUE_CLASS: - -#ifdef SUPPORT_WIDE_CHARS - /* If any wide characters or Unicode properties have been encountered, - set xclass = TRUE. Then, in the pre-compile phase, accumulate the length - of the extra data and reset the pointer. This is so that very large - classes that contain a zillion wide characters or Unicode property tests - do not overwrite the workspace (which is on the stack). */ - - if (class_uchardata > class_uchardata_base) - { - xclass = TRUE; - if (lengthptr != NULL) - { - *lengthptr += class_uchardata - class_uchardata_base; - class_uchardata = class_uchardata_base; - } - } -#endif - - continue; /* Needed to avoid error when not supporting wide chars */ - } /* End of main class-processing loop */ - - /* If this class is the first thing in the branch, there can be no first - char setting, whatever the repeat count. Any reqcu setting must remain - unchanged after any kind of repeat. */ - - if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE; - zerofirstcu = firstcu; - zerofirstcuflags = firstcuflags; - zeroreqcu = reqcu; - zeroreqcuflags = reqcuflags; - - /* If there are characters with values > 255, or Unicode property settings - (\p or \P), we have to compile an extended class, with its own opcode, - unless there were no property settings and there was a negated special such - as \S in the class, and PCRE2_UCP is not set, because in that case all - characters > 255 are in or not in the class, so any that were explicitly - given as well can be ignored. - - In the UCP case, if certain negated POSIX classes ([:^ascii:] or - [^:xdigit:]) were present in a class, we either have to match or not match - all wide characters (depending on whether the whole class is or is not - negated). This requirement is indicated by match_all_or_no_wide_chars being - true. We do this by including an explicit range, which works in both cases. - This applies only in UTF and 16-bit and 32-bit non-UTF modes, since there - cannot be any wide characters in 8-bit non-UTF mode. - - When there *are* properties in a positive UTF-8 or any 16-bit or 32_bit - class where \S etc is present without PCRE2_UCP, causing an extended class - to be compiled, we make sure that all characters > 255 are included by - forcing match_all_or_no_wide_chars to be true. - - If, when generating an xclass, there are no characters < 256, we can omit - the bitmap in the actual compiled code. */ - -#ifdef SUPPORT_WIDE_CHARS /* Defined for 16/32 bits, or 8-bit with Unicode */ - if (xclass && ( -#ifdef SUPPORT_UNICODE - (options & PCRE2_UCP) != 0 || -#endif - xclass_has_prop || !should_flip_negation)) - { - if (match_all_or_no_wide_chars || ( -#if PCRE2_CODE_UNIT_WIDTH == 8 - utf && -#endif - should_flip_negation && !negate_class && (options & PCRE2_UCP) == 0)) - { - *class_uchardata++ = XCL_RANGE; - if (utf) /* Will always be utf in the 8-bit library */ - { - class_uchardata += PRIV(ord2utf)(0x100, class_uchardata); - class_uchardata += PRIV(ord2utf)(MAX_UTF_CODE_POINT, class_uchardata); - } - else /* Can only happen for the 16-bit & 32-bit libraries */ - { -#if PCRE2_CODE_UNIT_WIDTH == 16 - *class_uchardata++ = 0x100; - *class_uchardata++ = 0xffffu; -#elif PCRE2_CODE_UNIT_WIDTH == 32 - *class_uchardata++ = 0x100; - *class_uchardata++ = 0xffffffffu; -#endif - } - } - *class_uchardata++ = XCL_END; /* Marks the end of extra data */ - *code++ = OP_XCLASS; - code += LINK_SIZE; - *code = negate_class? XCL_NOT:0; - if (xclass_has_prop) *code |= XCL_HASPROP; - - /* If the map is required, move up the extra data to make room for it; - otherwise just move the code pointer to the end of the extra data. */ - - if (class_has_8bitchar > 0) - { - *code++ |= XCL_MAP; - (void)memmove(code + (32 / sizeof(PCRE2_UCHAR)), code, - CU2BYTES(class_uchardata - code)); - if (negate_class && !xclass_has_prop) - { - /* Using 255 ^ instead of ~ avoids clang sanitize warning. */ - for (int i = 0; i < 32; i++) classbits[i] = 255 ^ classbits[i]; - } - memcpy(code, classbits, 32); - code = class_uchardata + (32 / sizeof(PCRE2_UCHAR)); - } - else code = class_uchardata; - - /* Now fill in the complete length of the item */ - - PUT(previous, 1, (int)(code - previous)); - break; /* End of class handling */ - } -#endif /* SUPPORT_WIDE_CHARS */ - - /* If there are no characters > 255, or they are all to be included or - excluded, set the opcode to OP_CLASS or OP_NCLASS, depending on whether the - whole class was negated and whether there were negative specials such as \S - (non-UCP) in the class. Then copy the 32-byte map into the code vector, - negating it if necessary. */ - - *code++ = (negate_class == should_flip_negation) ? OP_CLASS : OP_NCLASS; - if (lengthptr == NULL) /* Save time in the pre-compile phase */ - { - if (negate_class) - { - /* Using 255 ^ instead of ~ avoids clang sanitize warning. */ - for (int i = 0; i < 32; i++) classbits[i] = 255 ^ classbits[i]; - } - memcpy(code, classbits, 32); - } - code += 32 / sizeof(PCRE2_UCHAR); - break; /* End of class processing */ - - - /* ===================================================================*/ - /* Deal with (*VERB)s. */ - - /* Check for open captures before ACCEPT and close those that are within - the same assertion level, also converting ACCEPT to ASSERT_ACCEPT in an - assertion. In the first pass, just accumulate the length required; - otherwise hitting (*ACCEPT) inside many nested parentheses can cause - workspace overflow. Do not set firstcu after *ACCEPT. */ - - case META_ACCEPT: - cb->had_accept = had_accept = TRUE; - for (oc = cb->open_caps; - oc != NULL && oc->assert_depth >= cb->assert_depth; - oc = oc->next) - { - if (lengthptr != NULL) - { - *lengthptr += CU2BYTES(1) + IMM2_SIZE; - } - else - { - *code++ = OP_CLOSE; - PUT2INC(code, 0, oc->number); - } - } - *code++ = (cb->assert_depth > 0)? OP_ASSERT_ACCEPT : OP_ACCEPT; - if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE; - break; - - case META_PRUNE: - case META_SKIP: - cb->had_pruneorskip = TRUE; - /* Fall through */ - case META_COMMIT: - case META_FAIL: - *code++ = verbops[(meta - META_MARK) >> 16]; - break; - - case META_THEN: - cb->external_flags |= PCRE2_HASTHEN; - *code++ = OP_THEN; - break; - - /* Handle verbs with arguments. Arguments can be very long, especially in - 16- and 32-bit modes, and can overflow the workspace in the first pass. - However, the argument length is constrained to be small enough to fit in - one code unit. This check happens in parse_regex(). In the first pass, - instead of putting the argument into memory, we just update the length - counter and set up an empty argument. */ - - case META_THEN_ARG: - cb->external_flags |= PCRE2_HASTHEN; - goto VERB_ARG; - - case META_PRUNE_ARG: - case META_SKIP_ARG: - cb->had_pruneorskip = TRUE; - /* Fall through */ - case META_MARK: - case META_COMMIT_ARG: - VERB_ARG: - *code++ = verbops[(meta - META_MARK) >> 16]; - /* The length is in characters. */ - verbarglen = *(++pptr); - verbculen = 0; - tempcode = code++; - for (int i = 0; i < (int)verbarglen; i++) - { - meta = *(++pptr); -#ifdef SUPPORT_UNICODE - if (utf) mclength = PRIV(ord2utf)(meta, mcbuffer); else -#endif - { - mclength = 1; - mcbuffer[0] = meta; - } - if (lengthptr != NULL) *lengthptr += mclength; else - { - memcpy(code, mcbuffer, CU2BYTES(mclength)); - code += mclength; - verbculen += mclength; - } - } - - *tempcode = verbculen; /* Fill in the code unit length */ - *code++ = 0; /* Terminating zero */ - break; - - - /* ===================================================================*/ - /* Handle options change. The new setting must be passed back for use in - subsequent branches. Reset the greedy defaults and the case value for - firstcu and reqcu. */ - - case META_OPTIONS: - *optionsptr = options = *(++pptr); - greedy_default = ((options & PCRE2_UNGREEDY) != 0); - greedy_non_default = greedy_default ^ 1; - req_caseopt = ((options & PCRE2_CASELESS) != 0)? REQ_CASELESS : 0; - break; - - - /* ===================================================================*/ - /* Handle conditional subpatterns. The case of (?(Rdigits) is ambiguous - because it could be a numerical check on recursion, or a name check on a - group's being set. The pre-pass sets up META_COND_RNUMBER as a name so that - we can handle it either way. We first try for a name; if not found, process - the number. */ - - case META_COND_RNUMBER: /* (?(Rdigits) */ - case META_COND_NAME: /* (?(name) or (?'name') or ?() */ - case META_COND_RNAME: /* (?(R&name) - test for recursion */ - bravalue = OP_COND; - { - int count, index; - unsigned int i; - PCRE2_SPTR name; - named_group *ng = cb->named_groups; - uint32_t length = *(++pptr); - - GETPLUSOFFSET(offset, pptr); - name = cb->start_pattern + offset; - - /* In the first pass, the names generated in the pre-pass are available, - but the main name table has not yet been created. Scan the list of names - generated in the pre-pass in order to get a number and whether or not - this name is duplicated. If it is not duplicated, we can handle it as a - numerical group. */ - - for (i = 0; i < cb->names_found; i++, ng++) - { - if (length == ng->length && - PRIV(strncmp)(name, ng->name, length) == 0) - { - if (!ng->isdup) - { - code[1+LINK_SIZE] = (meta == META_COND_RNAME)? OP_RREF : OP_CREF; - PUT2(code, 2+LINK_SIZE, ng->number); - if (ng->number > cb->top_backref) cb->top_backref = ng->number; - skipunits = 1+IMM2_SIZE; - goto GROUP_PROCESS_NOTE_EMPTY; - } - break; /* Found a duplicated name */ - } - } - - /* If the name was not found we have a bad reference, unless we are - dealing with R, which is treated as a recursion test by number. - */ - - if (i >= cb->names_found) - { - groupnumber = 0; - if (meta == META_COND_RNUMBER) - { - for (i = 1; i < length; i++) - { - groupnumber = groupnumber * 10 + name[i] - CHAR_0; - if (groupnumber > MAX_GROUP_NUMBER) - { - *errorcodeptr = ERR61; - cb->erroroffset = offset + i; - return 0; - } - } - } - - if (meta != META_COND_RNUMBER || groupnumber > cb->bracount) - { - *errorcodeptr = ERR15; - cb->erroroffset = offset; - return 0; - } - - /* (?Rdigits) treated as a recursion reference by number. A value of - zero (which is the result of both (?R) and (?R0)) means "any", and is - translated into RREF_ANY (which is 0xffff). */ - - if (groupnumber == 0) groupnumber = RREF_ANY; - code[1+LINK_SIZE] = OP_RREF; - PUT2(code, 2+LINK_SIZE, groupnumber); - skipunits = 1+IMM2_SIZE; - goto GROUP_PROCESS_NOTE_EMPTY; - } - - /* A duplicated name was found. Note that if an R name is found - (META_COND_RNUMBER), it is a reference test, not a recursion test. */ - - code[1+LINK_SIZE] = (meta == META_COND_RNAME)? OP_RREF : OP_CREF; - - /* We have a duplicated name. In the compile pass we have to search the - main table in order to get the index and count values. */ - - count = 0; /* Values for first pass (avoids compiler warning) */ - index = 0; - if (lengthptr == NULL && !find_dupname_details(name, length, &index, - &count, errorcodeptr, cb)) return 0; - - /* Add one to the opcode to change CREF/RREF into DNCREF/DNRREF and - insert appropriate data values. */ - - code[1+LINK_SIZE]++; - skipunits = 1+2*IMM2_SIZE; - PUT2(code, 2+LINK_SIZE, index); - PUT2(code, 2+LINK_SIZE+IMM2_SIZE, count); - } - goto GROUP_PROCESS_NOTE_EMPTY; - - /* The DEFINE condition is always false. Its internal groups may never - be called, so matched_char must remain false, hence the jump to - GROUP_PROCESS rather than GROUP_PROCESS_NOTE_EMPTY. */ - - case META_COND_DEFINE: - bravalue = OP_COND; - GETPLUSOFFSET(offset, pptr); - code[1+LINK_SIZE] = OP_DEFINE; - skipunits = 1; - goto GROUP_PROCESS; - - /* Conditional test of a group's being set. */ - - case META_COND_NUMBER: - bravalue = OP_COND; - GETPLUSOFFSET(offset, pptr); - groupnumber = *(++pptr); - if (groupnumber > cb->bracount) - { - *errorcodeptr = ERR15; - cb->erroroffset = offset; - return 0; - } - if (groupnumber > cb->top_backref) cb->top_backref = groupnumber; - offset -= 2; /* Point at initial ( for too many branches error */ - code[1+LINK_SIZE] = OP_CREF; - skipunits = 1+IMM2_SIZE; - PUT2(code, 2+LINK_SIZE, groupnumber); - goto GROUP_PROCESS_NOTE_EMPTY; - - /* Test for the PCRE2 version. */ - - case META_COND_VERSION: - bravalue = OP_COND; - if (pptr[1] > 0) - code[1+LINK_SIZE] = ((PCRE2_MAJOR > pptr[2]) || - (PCRE2_MAJOR == pptr[2] && PCRE2_MINOR >= pptr[3]))? - OP_TRUE : OP_FALSE; - else - code[1+LINK_SIZE] = (PCRE2_MAJOR == pptr[2] && PCRE2_MINOR == pptr[3])? - OP_TRUE : OP_FALSE; - skipunits = 1; - pptr += 3; - goto GROUP_PROCESS_NOTE_EMPTY; - - /* The condition is an assertion, possibly preceded by a callout. */ - - case META_COND_ASSERT: - bravalue = OP_COND; - goto GROUP_PROCESS_NOTE_EMPTY; - - - /* ===================================================================*/ - /* Handle all kinds of nested bracketed groups. The non-capturing, - non-conditional cases are here; others come to GROUP_PROCESS via goto. */ - - case META_LOOKAHEAD: - bravalue = OP_ASSERT; - cb->assert_depth += 1; - goto GROUP_PROCESS; - - case META_LOOKAHEAD_NA: - bravalue = OP_ASSERT_NA; - cb->assert_depth += 1; - goto GROUP_PROCESS; - - /* Optimize (?!) to (*FAIL) unless it is quantified - which is a weird - thing to do, but Perl allows all assertions to be quantified, and when - they contain capturing parentheses there may be a potential use for - this feature. Not that that applies to a quantified (?!) but we allow - it for uniformity. */ - - case META_LOOKAHEADNOT: - if (pptr[1] == META_KET && - (pptr[2] < META_ASTERISK || pptr[2] > META_MINMAX_QUERY)) - { - *code++ = OP_FAIL; - pptr++; - } - else - { - bravalue = OP_ASSERT_NOT; - cb->assert_depth += 1; - goto GROUP_PROCESS; - } - break; - - case META_LOOKBEHIND: - bravalue = OP_ASSERTBACK; - cb->assert_depth += 1; - goto GROUP_PROCESS; - - case META_LOOKBEHINDNOT: - bravalue = OP_ASSERTBACK_NOT; - cb->assert_depth += 1; - goto GROUP_PROCESS; - - case META_LOOKBEHIND_NA: - bravalue = OP_ASSERTBACK_NA; - cb->assert_depth += 1; - goto GROUP_PROCESS; - - case META_ATOMIC: - bravalue = OP_ONCE; - goto GROUP_PROCESS_NOTE_EMPTY; - - case META_SCRIPT_RUN: - bravalue = OP_SCRIPT_RUN; - goto GROUP_PROCESS_NOTE_EMPTY; - - case META_NOCAPTURE: - bravalue = OP_BRA; - /* Fall through */ - - /* Process nested bracketed regex. The nesting depth is maintained for the - benefit of the stackguard function. The test for too deep nesting is now - done in parse_regex(). Assertion and DEFINE groups come to GROUP_PROCESS; - others come to GROUP_PROCESS_NOTE_EMPTY, to indicate that we need to take - note of whether or not they may match an empty string. */ - - GROUP_PROCESS_NOTE_EMPTY: - note_group_empty = TRUE; - - GROUP_PROCESS: - cb->parens_depth += 1; - *code = bravalue; - pptr++; - tempcode = code; - tempreqvary = cb->req_varyopt; /* Save value before group */ - length_prevgroup = 0; /* Initialize for pre-compile phase */ - - if ((group_return = - compile_regex( - options, /* The option state */ - &tempcode, /* Where to put code (updated) */ - &pptr, /* Input pointer (updated) */ - errorcodeptr, /* Where to put an error message */ - skipunits, /* Skip over bracket number */ - &subfirstcu, /* For possible first char */ - &subfirstcuflags, - &subreqcu, /* For possible last char */ - &subreqcuflags, - bcptr, /* Current branch chain */ - cb, /* Compile data block */ - (lengthptr == NULL)? NULL : /* Actual compile phase */ - &length_prevgroup /* Pre-compile phase */ - )) == 0) - return 0; /* Error */ - - cb->parens_depth -= 1; - - /* If that was a non-conditional significant group (not an assertion, not a - DEFINE) that matches at least one character, then the current item matches - a character. Conditionals are handled below. */ - - if (note_group_empty && bravalue != OP_COND && group_return > 0) - matched_char = TRUE; - - /* If we've just compiled an assertion, pop the assert depth. */ - - if (bravalue >= OP_ASSERT && bravalue <= OP_ASSERTBACK_NA) - cb->assert_depth -= 1; - - /* At the end of compiling, code is still pointing to the start of the - group, while tempcode has been updated to point past the end of the group. - The parsed pattern pointer (pptr) is on the closing META_KET. - - If this is a conditional bracket, check that there are no more than - two branches in the group, or just one if it's a DEFINE group. We do this - in the real compile phase, not in the pre-pass, where the whole group may - not be available. */ - - if (bravalue == OP_COND && lengthptr == NULL) - { - PCRE2_UCHAR *tc = code; - int condcount = 0; - - do { - condcount++; - tc += GET(tc,1); - } - while (*tc != OP_KET); - - /* A DEFINE group is never obeyed inline (the "condition" is always - false). It must have only one branch. Having checked this, change the - opcode to OP_FALSE. */ - - if (code[LINK_SIZE+1] == OP_DEFINE) - { - if (condcount > 1) - { - cb->erroroffset = offset; - *errorcodeptr = ERR54; - return 0; - } - code[LINK_SIZE+1] = OP_FALSE; - bravalue = OP_DEFINE; /* A flag to suppress char handling below */ - } - - /* A "normal" conditional group. If there is just one branch, we must not - make use of its firstcu or reqcu, because this is equivalent to an - empty second branch. Also, it may match an empty string. If there are two - branches, this item must match a character if the group must. */ - - else - { - if (condcount > 2) - { - cb->erroroffset = offset; - *errorcodeptr = ERR27; - return 0; - } - if (condcount == 1) subfirstcuflags = subreqcuflags = REQ_NONE; - else if (group_return > 0) matched_char = TRUE; - } - } - - /* In the pre-compile phase, update the length by the length of the group, - less the brackets at either end. Then reduce the compiled code to just a - set of non-capturing brackets so that it doesn't use much memory if it is - duplicated by a quantifier.*/ - - if (lengthptr != NULL) - { - if (OFLOW_MAX - *lengthptr < length_prevgroup - 2 - 2*LINK_SIZE) - { - *errorcodeptr = ERR20; - return 0; - } - *lengthptr += length_prevgroup - 2 - 2*LINK_SIZE; - code++; /* This already contains bravalue */ - PUTINC(code, 0, 1 + LINK_SIZE); - *code++ = OP_KET; - PUTINC(code, 0, 1 + LINK_SIZE); - break; /* No need to waste time with special character handling */ - } - - /* Otherwise update the main code pointer to the end of the group. */ - - code = tempcode; - - /* For a DEFINE group, required and first character settings are not - relevant. */ - - if (bravalue == OP_DEFINE) break; - - /* Handle updating of the required and first code units for other types of - group. Update for normal brackets of all kinds, and conditions with two - branches (see code above). If the bracket is followed by a quantifier with - zero repeat, we have to back off. Hence the definition of zeroreqcu and - zerofirstcu outside the main loop so that they can be accessed for the back - off. */ - - zeroreqcu = reqcu; - zeroreqcuflags = reqcuflags; - zerofirstcu = firstcu; - zerofirstcuflags = firstcuflags; - groupsetfirstcu = FALSE; - - if (bravalue >= OP_ONCE) /* Not an assertion */ - { - /* If we have not yet set a firstcu in this branch, take it from the - subpattern, remembering that it was set here so that a repeat of more - than one can replicate it as reqcu if necessary. If the subpattern has - no firstcu, set "none" for the whole branch. In both cases, a zero - repeat forces firstcu to "none". */ - - if (firstcuflags == REQ_UNSET && subfirstcuflags != REQ_UNSET) - { - if (subfirstcuflags < REQ_NONE) - { - firstcu = subfirstcu; - firstcuflags = subfirstcuflags; - groupsetfirstcu = TRUE; - } - else firstcuflags = REQ_NONE; - zerofirstcuflags = REQ_NONE; - } - - /* If firstcu was previously set, convert the subpattern's firstcu - into reqcu if there wasn't one, using the vary flag that was in - existence beforehand. */ - - else if (subfirstcuflags < REQ_NONE && subreqcuflags >= REQ_NONE) - { - subreqcu = subfirstcu; - subreqcuflags = subfirstcuflags | tempreqvary; - } - - /* If the subpattern set a required code unit (or set a first code unit - that isn't really the first code unit - see above), set it. */ - - if (subreqcuflags < REQ_NONE) - { - reqcu = subreqcu; - reqcuflags = subreqcuflags; - } - } - - /* For a forward assertion, we take the reqcu, if set, provided that the - group has also set a firstcu. This can be helpful if the pattern that - follows the assertion doesn't set a different char. For example, it's - useful for /(?=abcde).+/. We can't set firstcu for an assertion, however - because it leads to incorrect effect for patterns such as /(?=a)a.+/ when - the "real" "a" would then become a reqcu instead of a firstcu. This is - overcome by a scan at the end if there's no firstcu, looking for an - asserted first char. A similar effect for patterns like /(?=.*X)X$/ means - we must only take the reqcu when the group also set a firstcu. Otherwise, - in that example, 'X' ends up set for both. */ - - else if ((bravalue == OP_ASSERT || bravalue == OP_ASSERT_NA) && - subreqcuflags < REQ_NONE && subfirstcuflags < REQ_NONE) - { - reqcu = subreqcu; - reqcuflags = subreqcuflags; - } - - break; /* End of nested group handling */ - - - /* ===================================================================*/ - /* Handle named backreferences and recursions. */ - - case META_BACKREF_BYNAME: - case META_RECURSE_BYNAME: - { - int count, index; - PCRE2_SPTR name; - BOOL is_dupname = FALSE; - named_group *ng = cb->named_groups; - uint32_t length = *(++pptr); - - GETPLUSOFFSET(offset, pptr); - name = cb->start_pattern + offset; - - /* In the first pass, the names generated in the pre-pass are available, - but the main name table has not yet been created. Scan the list of names - generated in the pre-pass in order to get a number and whether or not - this name is duplicated. */ - - groupnumber = 0; - for (unsigned int i = 0; i < cb->names_found; i++, ng++) - { - if (length == ng->length && - PRIV(strncmp)(name, ng->name, length) == 0) - { - is_dupname = ng->isdup; - groupnumber = ng->number; - - /* For a recursion, that's all that is needed. We can now go to - the code that handles numerical recursion, applying it to the first - group with the given name. */ - - if (meta == META_RECURSE_BYNAME) - { - meta_arg = groupnumber; - goto HANDLE_NUMERICAL_RECURSION; - } - - /* For a back reference, update the back reference map and the - maximum back reference. */ - - cb->backref_map |= (groupnumber < 32)? (1u << groupnumber) : 1; - if (groupnumber > cb->top_backref) - cb->top_backref = groupnumber; - } - } - - /* If the name was not found we have a bad reference. */ - - if (groupnumber == 0) - { - *errorcodeptr = ERR15; - cb->erroroffset = offset; - return 0; - } - - /* If a back reference name is not duplicated, we can handle it as - a numerical reference. */ - - if (!is_dupname) - { - meta_arg = groupnumber; - goto HANDLE_SINGLE_REFERENCE; - } - - /* If a back reference name is duplicated, we generate a different - opcode to a numerical back reference. In the second pass we must - search for the index and count in the final name table. */ - - count = 0; /* Values for first pass (avoids compiler warning) */ - index = 0; - if (lengthptr == NULL && !find_dupname_details(name, length, &index, - &count, errorcodeptr, cb)) return 0; - - if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE; - *code++ = ((options & PCRE2_CASELESS) != 0)? OP_DNREFI : OP_DNREF; - PUT2INC(code, 0, index); - PUT2INC(code, 0, count); - } - break; - - - /* ===================================================================*/ - /* Handle a numerical callout. */ - - case META_CALLOUT_NUMBER: - code[0] = OP_CALLOUT; - PUT(code, 1, pptr[1]); /* Offset to next pattern item */ - PUT(code, 1 + LINK_SIZE, pptr[2]); /* Length of next pattern item */ - code[1 + 2*LINK_SIZE] = pptr[3]; - pptr += 3; - code += PRIV(OP_lengths)[OP_CALLOUT]; - break; - - - /* ===================================================================*/ - /* Handle a callout with a string argument. In the pre-pass we just compute - the length without generating anything. The length in pptr[3] includes both - delimiters; in the actual compile only the first one is copied, but a - terminating zero is added. Any doubled delimiters within the string make - this an overestimate, but it is not worth bothering about. */ - - case META_CALLOUT_STRING: - if (lengthptr != NULL) - { - *lengthptr += pptr[3] + (1 + 4*LINK_SIZE); - pptr += 3; - SKIPOFFSET(pptr); - } - - /* In the real compile we can copy the string. The starting delimiter is - included so that the client can discover it if they want. We also pass the - start offset to help a script language give better error messages. */ - - else - { - PCRE2_SPTR pp; - uint32_t delimiter; - uint32_t length = pptr[3]; - PCRE2_UCHAR *callout_string = code + (1 + 4*LINK_SIZE); - - code[0] = OP_CALLOUT_STR; - PUT(code, 1, pptr[1]); /* Offset to next pattern item */ - PUT(code, 1 + LINK_SIZE, pptr[2]); /* Length of next pattern item */ - - pptr += 3; - GETPLUSOFFSET(offset, pptr); /* Offset to string in pattern */ - pp = cb->start_pattern + offset; - delimiter = *callout_string++ = *pp++; - if (delimiter == CHAR_LEFT_CURLY_BRACKET) - delimiter = CHAR_RIGHT_CURLY_BRACKET; - PUT(code, 1 + 3*LINK_SIZE, (int)(offset + 1)); /* One after delimiter */ - - /* The syntax of the pattern was checked in the parsing scan. The length - includes both delimiters, but we have passed the opening one just above, - so we reduce length before testing it. The test is for > 1 because we do - not want to copy the final delimiter. This also ensures that pp[1] is - accessible. */ - - while (--length > 1) - { - if (*pp == delimiter && pp[1] == delimiter) - { - *callout_string++ = delimiter; - pp += 2; - length--; - } - else *callout_string++ = *pp++; - } - *callout_string++ = CHAR_NUL; - - /* Set the length of the entire item, the advance to its end. */ - - PUT(code, 1 + 2*LINK_SIZE, (int)(callout_string - code)); - code = callout_string; - } - break; - - - /* ===================================================================*/ - /* Handle repetition. The different types are all sorted out in the parsing - pass. */ - - case META_MINMAX_PLUS: - case META_MINMAX_QUERY: - case META_MINMAX: - repeat_min = *(++pptr); - repeat_max = *(++pptr); - goto REPEAT; - - case META_ASTERISK: - case META_ASTERISK_PLUS: - case META_ASTERISK_QUERY: - repeat_min = 0; - repeat_max = REPEAT_UNLIMITED; - goto REPEAT; - - case META_PLUS: - case META_PLUS_PLUS: - case META_PLUS_QUERY: - repeat_min = 1; - repeat_max = REPEAT_UNLIMITED; - goto REPEAT; - - case META_QUERY: - case META_QUERY_PLUS: - case META_QUERY_QUERY: - repeat_min = 0; - repeat_max = 1; - - REPEAT: - if (previous_matched_char && repeat_min > 0) matched_char = TRUE; - - /* Remember whether this is a variable length repeat, and default to - single-char opcodes. */ - - reqvary = (repeat_min == repeat_max)? 0 : REQ_VARY; - op_type = 0; - - /* Adjust first and required code units for a zero repeat. */ - - if (repeat_min == 0) - { - firstcu = zerofirstcu; - firstcuflags = zerofirstcuflags; - reqcu = zeroreqcu; - reqcuflags = zeroreqcuflags; - } - - /* Note the greediness and possessiveness. */ - - switch (meta) - { - case META_MINMAX_PLUS: - case META_ASTERISK_PLUS: - case META_PLUS_PLUS: - case META_QUERY_PLUS: - repeat_type = 0; /* Force greedy */ - possessive_quantifier = TRUE; - break; - - case META_MINMAX_QUERY: - case META_ASTERISK_QUERY: - case META_PLUS_QUERY: - case META_QUERY_QUERY: - repeat_type = greedy_non_default; - possessive_quantifier = FALSE; - break; - - default: - repeat_type = greedy_default; - possessive_quantifier = FALSE; - break; - } - - /* Save start of previous item, in case we have to move it up in order to - insert something before it, and remember what it was. */ - - tempcode = previous; - op_previous = *previous; - - /* Now handle repetition for the different types of item. If the repeat - minimum and the repeat maximum are both 1, we can ignore the quantifier for - non-parenthesized items, as they have only one alternative. For anything in - parentheses, we must not ignore if {1} is possessive. */ - - switch (op_previous) - { - /* If previous was a character or negated character match, abolish the - item and generate a repeat item instead. If a char item has a minimum of - more than one, ensure that it is set in reqcu - it might not be if a - sequence such as x{3} is the first thing in a branch because the x will - have gone into firstcu instead. */ - - case OP_CHAR: - case OP_CHARI: - case OP_NOT: - case OP_NOTI: - if (repeat_max == 1 && repeat_min == 1) goto END_REPEAT; - op_type = chartypeoffset[op_previous - OP_CHAR]; - - /* Deal with UTF characters that take up more than one code unit. */ - -#ifdef MAYBE_UTF_MULTI - if (utf && NOT_FIRSTCU(code[-1])) - { - PCRE2_UCHAR *lastchar = code - 1; - BACKCHAR(lastchar); - mclength = (uint32_t)(code - lastchar); /* Length of UTF character */ - memcpy(mcbuffer, lastchar, CU2BYTES(mclength)); /* Save the char */ - } - else -#endif /* MAYBE_UTF_MULTI */ - - /* Handle the case of a single code unit - either with no UTF support, or - with UTF disabled, or for a single-code-unit UTF character. In the latter - case, for a repeated positive match, get the caseless flag for the - required code unit from the previous character, because a class like [Aa] - sets a caseless A but by now the req_caseopt flag has been reset. */ - - { - mcbuffer[0] = code[-1]; - mclength = 1; - if (op_previous <= OP_CHARI && repeat_min > 1) - { - reqcu = mcbuffer[0]; - reqcuflags = cb->req_varyopt; - if (op_previous == OP_CHARI) reqcuflags |= REQ_CASELESS; - } - } - goto OUTPUT_SINGLE_REPEAT; /* Code shared with single character types */ - - /* If previous was a character class or a back reference, we put the - repeat stuff after it, but just skip the item if the repeat was {0,0}. */ - -#ifdef SUPPORT_WIDE_CHARS - case OP_XCLASS: -#endif - case OP_CLASS: - case OP_NCLASS: - case OP_REF: - case OP_REFI: - case OP_DNREF: - case OP_DNREFI: - - if (repeat_max == 0) - { - code = previous; - goto END_REPEAT; - } - if (repeat_max == 1 && repeat_min == 1) goto END_REPEAT; - - if (repeat_min == 0 && repeat_max == REPEAT_UNLIMITED) - *code++ = OP_CRSTAR + repeat_type; - else if (repeat_min == 1 && repeat_max == REPEAT_UNLIMITED) - *code++ = OP_CRPLUS + repeat_type; - else if (repeat_min == 0 && repeat_max == 1) - *code++ = OP_CRQUERY + repeat_type; - else - { - *code++ = OP_CRRANGE + repeat_type; - PUT2INC(code, 0, repeat_min); - if (repeat_max == REPEAT_UNLIMITED) repeat_max = 0; /* 2-byte encoding for max */ - PUT2INC(code, 0, repeat_max); - } - break; - - /* If previous is OP_FAIL, it was generated by an empty class [] - (PCRE2_ALLOW_EMPTY_CLASS is set). The other ways in which OP_FAIL can be - generated, that is by (*FAIL) or (?!), disallow a quantifier at parse - time. We can just ignore this repeat. */ - - case OP_FAIL: - goto END_REPEAT; - - /* Prior to 10.30, repeated recursions were wrapped in OP_ONCE brackets - because pcre2_match() could not handle backtracking into recursively - called groups. Now that this backtracking is available, we no longer need - to do this. However, we still need to replicate recursions as we do for - groups so as to have independent backtracking points. We can replicate - for the minimum number of repeats directly. For optional repeats we now - wrap the recursion in OP_BRA brackets and make use of the bracket - repetition. */ - - case OP_RECURSE: - if (repeat_max == 1 && repeat_min == 1 && !possessive_quantifier) - goto END_REPEAT; - - /* Generate unwrapped repeats for a non-zero minimum, except when the - minimum is 1 and the maximum unlimited, because that can be handled with - OP_BRA terminated by OP_KETRMAX/MIN. When the maximum is equal to the - minimum, we just need to generate the appropriate additional copies. - Otherwise we need to generate one more, to simulate the situation when - the minimum is zero. */ - - if (repeat_min > 0 && (repeat_min != 1 || repeat_max != REPEAT_UNLIMITED)) - { - int replicate = repeat_min; - if (repeat_min == repeat_max) replicate--; - - /* In the pre-compile phase, we don't actually do the replication. We - just adjust the length as if we had. Do some paranoid checks for - potential integer overflow. The INT64_OR_DOUBLE type is a 64-bit - integer type when available, otherwise double. */ - - if (lengthptr != NULL) - { - PCRE2_SIZE delta = replicate*(1 + LINK_SIZE); - if ((INT64_OR_DOUBLE)replicate* - (INT64_OR_DOUBLE)(1 + LINK_SIZE) > - (INT64_OR_DOUBLE)INT_MAX || - OFLOW_MAX - *lengthptr < delta) - { - *errorcodeptr = ERR20; - return 0; - } - *lengthptr += delta; - } - - else for (int i = 0; i < replicate; i++) - { - memcpy(code, previous, CU2BYTES(1 + LINK_SIZE)); - previous = code; - code += 1 + LINK_SIZE; - } - - /* If the number of repeats is fixed, we are done. Otherwise, adjust - the counts and fall through. */ - - if (repeat_min == repeat_max) break; - if (repeat_max != REPEAT_UNLIMITED) repeat_max -= repeat_min; - repeat_min = 0; - } - - /* Wrap the recursion call in OP_BRA brackets. */ - - (void)memmove(previous + 1 + LINK_SIZE, previous, CU2BYTES(1 + LINK_SIZE)); - op_previous = *previous = OP_BRA; - PUT(previous, 1, 2 + 2*LINK_SIZE); - previous[2 + 2*LINK_SIZE] = OP_KET; - PUT(previous, 3 + 2*LINK_SIZE, 2 + 2*LINK_SIZE); - code += 2 + 2 * LINK_SIZE; - length_prevgroup = 3 + 3*LINK_SIZE; - group_return = -1; /* Set "may match empty string" */ - - /* Now treat as a repeated OP_BRA. */ - /* Fall through */ - - /* If previous was a bracket group, we may have to replicate it in - certain cases. Note that at this point we can encounter only the "basic" - bracket opcodes such as BRA and CBRA, as this is the place where they get - converted into the more special varieties such as BRAPOS and SBRA. - Originally, PCRE did not allow repetition of assertions, but now it does, - for Perl compatibility. */ - - case OP_ASSERT: - case OP_ASSERT_NOT: - case OP_ASSERT_NA: - case OP_ASSERTBACK: - case OP_ASSERTBACK_NOT: - case OP_ASSERTBACK_NA: - case OP_ONCE: - case OP_SCRIPT_RUN: - case OP_BRA: - case OP_CBRA: - case OP_COND: - { - int len = (int)(code - previous); - PCRE2_UCHAR *bralink = NULL; - PCRE2_UCHAR *brazeroptr = NULL; - - if (repeat_max == 1 && repeat_min == 1 && !possessive_quantifier) - goto END_REPEAT; - - /* Repeating a DEFINE group (or any group where the condition is always - FALSE and there is only one branch) is pointless, but Perl allows the - syntax, so we just ignore the repeat. */ - - if (op_previous == OP_COND && previous[LINK_SIZE+1] == OP_FALSE && - previous[GET(previous, 1)] != OP_ALT) - goto END_REPEAT; - - /* Perl allows all assertions to be quantified, and when they contain - capturing parentheses and/or are optional there are potential uses for - this feature. PCRE2 used to force the maximum quantifier to 1 on the - invalid grounds that further repetition was never useful. This was - always a bit pointless, since an assertion could be wrapped with a - repeated group to achieve the effect. General repetition is now - permitted, but if the maximum is unlimited it is set to one more than - the minimum. */ - - if (op_previous < OP_ONCE) /* Assertion */ - { - if (repeat_max == REPEAT_UNLIMITED) repeat_max = repeat_min + 1; - } - - /* The case of a zero minimum is special because of the need to stick - OP_BRAZERO in front of it, and because the group appears once in the - data, whereas in other cases it appears the minimum number of times. For - this reason, it is simplest to treat this case separately, as otherwise - the code gets far too messy. There are several special subcases when the - minimum is zero. */ - - if (repeat_min == 0) - { - /* If the maximum is also zero, we used to just omit the group from - the output altogether, like this: - - ** if (repeat_max == 0) - ** { - ** code = previous; - ** goto END_REPEAT; - ** } - - However, that fails when a group or a subgroup within it is - referenced as a subroutine from elsewhere in the pattern, so now we - stick in OP_SKIPZERO in front of it so that it is skipped on - execution. As we don't have a list of which groups are referenced, we - cannot do this selectively. - - If the maximum is 1 or unlimited, we just have to stick in the - BRAZERO and do no more at this point. */ - - if (repeat_max <= 1 || repeat_max == REPEAT_UNLIMITED) - { - (void)memmove(previous + 1, previous, CU2BYTES(len)); - code++; - if (repeat_max == 0) - { - *previous++ = OP_SKIPZERO; - goto END_REPEAT; - } - brazeroptr = previous; /* Save for possessive optimizing */ - *previous++ = OP_BRAZERO + repeat_type; - } - - /* If the maximum is greater than 1 and limited, we have to replicate - in a nested fashion, sticking OP_BRAZERO before each set of brackets. - The first one has to be handled carefully because it's the original - copy, which has to be moved up. The remainder can be handled by code - that is common with the non-zero minimum case below. We have to - adjust the value or repeat_max, since one less copy is required. */ - - else - { - int linkoffset; - (void)memmove(previous + 2 + LINK_SIZE, previous, CU2BYTES(len)); - code += 2 + LINK_SIZE; - *previous++ = OP_BRAZERO + repeat_type; - *previous++ = OP_BRA; - - /* We chain together the bracket link offset fields that have to be - filled in later when the ends of the brackets are reached. */ - - linkoffset = (bralink == NULL)? 0 : (int)(previous - bralink); - bralink = previous; - PUTINC(previous, 0, linkoffset); - } - - if (repeat_max != REPEAT_UNLIMITED) repeat_max--; - } - - /* If the minimum is greater than zero, replicate the group as many - times as necessary, and adjust the maximum to the number of subsequent - copies that we need. */ - - else - { - if (repeat_min > 1) - { - /* In the pre-compile phase, we don't actually do the replication. - We just adjust the length as if we had. Do some paranoid checks for - potential integer overflow. The INT64_OR_DOUBLE type is a 64-bit - integer type when available, otherwise double. */ - - if (lengthptr != NULL) - { - PCRE2_SIZE delta = (repeat_min - 1)*length_prevgroup; - if ((INT64_OR_DOUBLE)(repeat_min - 1)* - (INT64_OR_DOUBLE)length_prevgroup > - (INT64_OR_DOUBLE)INT_MAX || - OFLOW_MAX - *lengthptr < delta) - { - *errorcodeptr = ERR20; - return 0; - } - *lengthptr += delta; - } - - /* This is compiling for real. If there is a set first code unit - for the group, and we have not yet set a "required code unit", set - it. */ - - else - { - if (groupsetfirstcu && reqcuflags >= REQ_NONE) - { - reqcu = firstcu; - reqcuflags = firstcuflags; - } - for (uint32_t i = 1; i < repeat_min; i++) - { - memcpy(code, previous, CU2BYTES(len)); - code += len; - } - } - } - - if (repeat_max != REPEAT_UNLIMITED) repeat_max -= repeat_min; - } - - /* This code is common to both the zero and non-zero minimum cases. If - the maximum is limited, it replicates the group in a nested fashion, - remembering the bracket starts on a stack. In the case of a zero - minimum, the first one was set up above. In all cases the repeat_max - now specifies the number of additional copies needed. Again, we must - remember to replicate entries on the forward reference list. */ - - if (repeat_max != REPEAT_UNLIMITED) - { - /* In the pre-compile phase, we don't actually do the replication. We - just adjust the length as if we had. For each repetition we must add - 1 to the length for BRAZERO and for all but the last repetition we - must add 2 + 2*LINKSIZE to allow for the nesting that occurs. Do some - paranoid checks to avoid integer overflow. The INT64_OR_DOUBLE type - is a 64-bit integer type when available, otherwise double. */ - - if (lengthptr != NULL && repeat_max > 0) - { - PCRE2_SIZE delta = repeat_max*(length_prevgroup + 1 + 2 + 2*LINK_SIZE) - - 2 - 2*LINK_SIZE; /* Last one doesn't nest */ - if ((INT64_OR_DOUBLE)repeat_max * - (INT64_OR_DOUBLE)(length_prevgroup + 1 + 2 + 2*LINK_SIZE) - > (INT64_OR_DOUBLE)INT_MAX || - OFLOW_MAX - *lengthptr < delta) - { - *errorcodeptr = ERR20; - return 0; - } - *lengthptr += delta; - } - - /* This is compiling for real */ - - else for (uint32_t i = repeat_max; i >= 1; i--) - { - *code++ = OP_BRAZERO + repeat_type; - - /* All but the final copy start a new nesting, maintaining the - chain of brackets outstanding. */ - - if (i != 1) - { - int linkoffset; - *code++ = OP_BRA; - linkoffset = (bralink == NULL)? 0 : (int)(code - bralink); - bralink = code; - PUTINC(code, 0, linkoffset); - } - - memcpy(code, previous, CU2BYTES(len)); - code += len; - } - - /* Now chain through the pending brackets, and fill in their length - fields (which are holding the chain links pro tem). */ - - while (bralink != NULL) - { - int oldlinkoffset; - int linkoffset = (int)(code - bralink + 1); - PCRE2_UCHAR *bra = code - linkoffset; - oldlinkoffset = GET(bra, 1); - bralink = (oldlinkoffset == 0)? NULL : bralink - oldlinkoffset; - *code++ = OP_KET; - PUTINC(code, 0, linkoffset); - PUT(bra, 1, linkoffset); - } - } - - /* If the maximum is unlimited, set a repeater in the final copy. For - SCRIPT_RUN and ONCE brackets, that's all we need to do. However, - possessively repeated ONCE brackets can be converted into non-capturing - brackets, as the behaviour of (?:xx)++ is the same as (?>xx)++ and this - saves having to deal with possessive ONCEs specially. - - Otherwise, when we are doing the actual compile phase, check to see - whether this group is one that could match an empty string. If so, - convert the initial operator to the S form (e.g. OP_BRA -> OP_SBRA) so - that runtime checking can be done. [This check is also applied to ONCE - and SCRIPT_RUN groups at runtime, but in a different way.] - - Then, if the quantifier was possessive and the bracket is not a - conditional, we convert the BRA code to the POS form, and the KET code - to KETRPOS. (It turns out to be convenient at runtime to detect this - kind of subpattern at both the start and at the end.) The use of - special opcodes makes it possible to reduce greatly the stack usage in - pcre2_match(). If the group is preceded by OP_BRAZERO, convert this to - OP_BRAPOSZERO. - - Then, if the minimum number of matches is 1 or 0, cancel the possessive - flag so that the default action below, of wrapping everything inside - atomic brackets, does not happen. When the minimum is greater than 1, - there will be earlier copies of the group, and so we still have to wrap - the whole thing. */ - - else - { - PCRE2_UCHAR *ketcode = code - 1 - LINK_SIZE; - PCRE2_UCHAR *bracode = ketcode - GET(ketcode, 1); - - /* Convert possessive ONCE brackets to non-capturing */ - - if (*bracode == OP_ONCE && possessive_quantifier) *bracode = OP_BRA; - - /* For non-possessive ONCE and for SCRIPT_RUN brackets, all we need - to do is to set the KET. */ - - if (*bracode == OP_ONCE || *bracode == OP_SCRIPT_RUN) - *ketcode = OP_KETRMAX + repeat_type; - - /* Handle non-SCRIPT_RUN and non-ONCE brackets and possessive ONCEs - (which have been converted to non-capturing above). */ - - else - { - /* In the compile phase, adjust the opcode if the group can match - an empty string. For a conditional group with only one branch, the - value of group_return will not show "could be empty", so we must - check that separately. */ - - if (lengthptr == NULL) - { - if (group_return < 0) *bracode += OP_SBRA - OP_BRA; - if (*bracode == OP_COND && bracode[GET(bracode,1)] != OP_ALT) - *bracode = OP_SCOND; - } - - /* Handle possessive quantifiers. */ - - if (possessive_quantifier) - { - /* For COND brackets, we wrap the whole thing in a possessively - repeated non-capturing bracket, because we have not invented POS - versions of the COND opcodes. */ - - if (*bracode == OP_COND || *bracode == OP_SCOND) - { - int nlen = (int)(code - bracode); - (void)memmove(bracode + 1 + LINK_SIZE, bracode, CU2BYTES(nlen)); - code += 1 + LINK_SIZE; - nlen += 1 + LINK_SIZE; - *bracode = (*bracode == OP_COND)? OP_BRAPOS : OP_SBRAPOS; - *code++ = OP_KETRPOS; - PUTINC(code, 0, nlen); - PUT(bracode, 1, nlen); - } - - /* For non-COND brackets, we modify the BRA code and use KETRPOS. */ - - else - { - *bracode += 1; /* Switch to xxxPOS opcodes */ - *ketcode = OP_KETRPOS; - } - - /* If the minimum is zero, mark it as possessive, then unset the - possessive flag when the minimum is 0 or 1. */ - - if (brazeroptr != NULL) *brazeroptr = OP_BRAPOSZERO; - if (repeat_min < 2) possessive_quantifier = FALSE; - } - - /* Non-possessive quantifier */ - - else *ketcode = OP_KETRMAX + repeat_type; - } - } - } - break; - - /* If previous was a character type match (\d or similar), abolish it and - create a suitable repeat item. The code is shared with single-character - repeats by setting op_type to add a suitable offset into repeat_type. - Note the the Unicode property types will be present only when - SUPPORT_UNICODE is defined, but we don't wrap the little bits of code - here because it just makes it horribly messy. */ - - default: - if (op_previous >= OP_EODN) /* Not a character type - internal error */ - { - *errorcodeptr = ERR10; - return 0; - } - else - { - int prop_type, prop_value; - PCRE2_UCHAR *oldcode; - - if (repeat_max == 1 && repeat_min == 1) goto END_REPEAT; - - op_type = OP_TYPESTAR - OP_STAR; /* Use type opcodes */ - mclength = 0; /* Not a character */ - - if (op_previous == OP_PROP || op_previous == OP_NOTPROP) - { - prop_type = previous[1]; - prop_value = previous[2]; - } - else - { - /* Come here from just above with a character in mcbuffer/mclength. */ - OUTPUT_SINGLE_REPEAT: - prop_type = prop_value = -1; - } - - /* At this point, if prop_type == prop_value == -1 we either have a - character in mcbuffer when mclength is greater than zero, or we have - mclength zero, in which case there is a non-property character type in - op_previous. If prop_type/value are not negative, we have a property - character type in op_previous. */ - - oldcode = code; /* Save where we were */ - code = previous; /* Usually overwrite previous item */ - - /* If the maximum is zero then the minimum must also be zero; Perl allows - this case, so we do too - by simply omitting the item altogether. */ - - if (repeat_max == 0) goto END_REPEAT; - - /* Combine the op_type with the repeat_type */ - - repeat_type += op_type; - - /* A minimum of zero is handled either as the special case * or ?, or as - an UPTO, with the maximum given. */ - - if (repeat_min == 0) - { - if (repeat_max == REPEAT_UNLIMITED) *code++ = OP_STAR + repeat_type; - else if (repeat_max == 1) *code++ = OP_QUERY + repeat_type; - else - { - *code++ = OP_UPTO + repeat_type; - PUT2INC(code, 0, repeat_max); - } - } - - /* A repeat minimum of 1 is optimized into some special cases. If the - maximum is unlimited, we use OP_PLUS. Otherwise, the original item is - left in place and, if the maximum is greater than 1, we use OP_UPTO with - one less than the maximum. */ - - else if (repeat_min == 1) - { - if (repeat_max == REPEAT_UNLIMITED) - *code++ = OP_PLUS + repeat_type; - else - { - code = oldcode; /* Leave previous item in place */ - if (repeat_max == 1) goto END_REPEAT; - *code++ = OP_UPTO + repeat_type; - PUT2INC(code, 0, repeat_max - 1); - } - } - - /* The case {n,n} is just an EXACT, while the general case {n,m} is - handled as an EXACT followed by an UPTO or STAR or QUERY. */ - - else - { - *code++ = OP_EXACT + op_type; /* NB EXACT doesn't have repeat_type */ - PUT2INC(code, 0, repeat_min); - - /* Unless repeat_max equals repeat_min, fill in the data for EXACT, - and then generate the second opcode. For a repeated Unicode property - match, there are two extra values that define the required property, - and mclength is set zero to indicate this. */ - - if (repeat_max != repeat_min) - { - if (mclength > 0) - { - memcpy(code, mcbuffer, CU2BYTES(mclength)); - code += mclength; - } - else - { - *code++ = op_previous; - if (prop_type >= 0) - { - *code++ = prop_type; - *code++ = prop_value; - } - } - - /* Now set up the following opcode */ - - if (repeat_max == REPEAT_UNLIMITED) - *code++ = OP_STAR + repeat_type; - else - { - repeat_max -= repeat_min; - if (repeat_max == 1) - { - *code++ = OP_QUERY + repeat_type; - } - else - { - *code++ = OP_UPTO + repeat_type; - PUT2INC(code, 0, repeat_max); - } - } - } - } - - /* Fill in the character or character type for the final opcode. */ - - if (mclength > 0) - { - memcpy(code, mcbuffer, CU2BYTES(mclength)); - code += mclength; - } - else - { - *code++ = op_previous; - if (prop_type >= 0) - { - *code++ = prop_type; - *code++ = prop_value; - } - } - } - break; - } /* End of switch on different op_previous values */ - - - /* If the character following a repeat is '+', possessive_quantifier is - TRUE. For some opcodes, there are special alternative opcodes for this - case. For anything else, we wrap the entire repeated item inside OP_ONCE - brackets. Logically, the '+' notation is just syntactic sugar, taken from - Sun's Java package, but the special opcodes can optimize it. - - Some (but not all) possessively repeated subpatterns have already been - completely handled in the code just above. For them, possessive_quantifier - is always FALSE at this stage. Note that the repeated item starts at - tempcode, not at previous, which might be the first part of a string whose - (former) last char we repeated. */ - - if (possessive_quantifier) - { - int len; - - /* Possessifying an EXACT quantifier has no effect, so we can ignore it. - However, QUERY, STAR, or UPTO may follow (for quantifiers such as {5,6}, - {5,}, or {5,10}). We skip over an EXACT item; if the length of what - remains is greater than zero, there's a further opcode that can be - handled. If not, do nothing, leaving the EXACT alone. */ - - switch(*tempcode) - { - case OP_TYPEEXACT: - tempcode += PRIV(OP_lengths)[*tempcode] + - ((tempcode[1 + IMM2_SIZE] == OP_PROP - || tempcode[1 + IMM2_SIZE] == OP_NOTPROP)? 2 : 0); - break; - - /* CHAR opcodes are used for exacts whose count is 1. */ - - case OP_CHAR: - case OP_CHARI: - case OP_NOT: - case OP_NOTI: - case OP_EXACT: - case OP_EXACTI: - case OP_NOTEXACT: - case OP_NOTEXACTI: - tempcode += PRIV(OP_lengths)[*tempcode]; -#ifdef SUPPORT_UNICODE - if (utf && HAS_EXTRALEN(tempcode[-1])) - tempcode += GET_EXTRALEN(tempcode[-1]); -#endif - break; - - /* For the class opcodes, the repeat operator appears at the end; - adjust tempcode to point to it. */ - - case OP_CLASS: - case OP_NCLASS: - tempcode += 1 + 32/sizeof(PCRE2_UCHAR); - break; - -#ifdef SUPPORT_WIDE_CHARS - case OP_XCLASS: - tempcode += GET(tempcode, 1); - break; -#endif - } - - /* If tempcode is equal to code (which points to the end of the repeated - item), it means we have skipped an EXACT item but there is no following - QUERY, STAR, or UPTO; the value of len will be 0, and we do nothing. In - all other cases, tempcode will be pointing to the repeat opcode, and will - be less than code, so the value of len will be greater than 0. */ - - len = (int)(code - tempcode); - if (len > 0) - { - unsigned int repcode = *tempcode; - - /* There is a table for possessifying opcodes, all of which are less - than OP_CALLOUT. A zero entry means there is no possessified version. - */ - - if (repcode < OP_CALLOUT && opcode_possessify[repcode] > 0) - *tempcode = opcode_possessify[repcode]; - - /* For opcode without a special possessified version, wrap the item in - ONCE brackets. */ - - else - { - (void)memmove(tempcode + 1 + LINK_SIZE, tempcode, CU2BYTES(len)); - code += 1 + LINK_SIZE; - len += 1 + LINK_SIZE; - tempcode[0] = OP_ONCE; - *code++ = OP_KET; - PUTINC(code, 0, len); - PUT(tempcode, 1, len); - } - } - } - - /* We set the "follows varying string" flag for subsequently encountered - reqcus if it isn't already set and we have just passed a varying length - item. */ - - END_REPEAT: - cb->req_varyopt |= reqvary; - break; - - - /* ===================================================================*/ - /* Handle a 32-bit data character with a value greater than META_END. */ - - case META_BIGVALUE: - pptr++; - goto NORMAL_CHAR; - - - /* ===============================================================*/ - /* Handle a back reference by number, which is the meta argument. The - pattern offsets for back references to group numbers less than 10 are held - in a special vector, to avoid using more than two parsed pattern elements - in 64-bit environments. We only need the offset to the first occurrence, - because if that doesn't fail, subsequent ones will also be OK. */ - - case META_BACKREF: - if (meta_arg < 10) offset = cb->small_ref_offset[meta_arg]; - else GETPLUSOFFSET(offset, pptr); - - if (meta_arg > cb->bracount) - { - cb->erroroffset = offset; - *errorcodeptr = ERR15; /* Non-existent subpattern */ - return 0; - } - - /* Come here from named backref handling when the reference is to a - single group (that is, not to a duplicated name). The back reference - data will have already been updated. We must disable firstcu if not - set, to cope with cases like (?=(\w+))\1: which would otherwise set ':' - later. */ - - HANDLE_SINGLE_REFERENCE: - if (firstcuflags == REQ_UNSET) zerofirstcuflags = firstcuflags = REQ_NONE; - *code++ = ((options & PCRE2_CASELESS) != 0)? OP_REFI : OP_REF; - PUT2INC(code, 0, meta_arg); - - /* Update the map of back references, and keep the highest one. We - could do this in parse_regex() for numerical back references, but not - for named back references, because we don't know the numbers to which - named back references refer. So we do it all in this function. */ - - cb->backref_map |= (meta_arg < 32)? (1u << meta_arg) : 1; - if (meta_arg > cb->top_backref) cb->top_backref = meta_arg; - break; - - - /* ===============================================================*/ - /* Handle recursion by inserting the number of the called group (which is - the meta argument) after OP_RECURSE. At the end of compiling the pattern is - scanned and these numbers are replaced by offsets within the pattern. It is - done like this to avoid problems with forward references and adjusting - offsets when groups are duplicated and moved (as discovered in previous - implementations). Note that a recursion does not have a set first - character. */ - - case META_RECURSE: - GETPLUSOFFSET(offset, pptr); - if (meta_arg > cb->bracount) - { - cb->erroroffset = offset; - *errorcodeptr = ERR15; /* Non-existent subpattern */ - return 0; - } - HANDLE_NUMERICAL_RECURSION: - *code = OP_RECURSE; - PUT(code, 1, meta_arg); - code += 1 + LINK_SIZE; - groupsetfirstcu = FALSE; - cb->had_recurse = TRUE; - if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE; - zerofirstcu = firstcu; - zerofirstcuflags = firstcuflags; - break; - - - /* ===============================================================*/ - /* Handle capturing parentheses; the number is the meta argument. */ - - case META_CAPTURE: - bravalue = OP_CBRA; - skipunits = IMM2_SIZE; - PUT2(code, 1+LINK_SIZE, meta_arg); - cb->lastcapture = meta_arg; - goto GROUP_PROCESS_NOTE_EMPTY; - - - /* ===============================================================*/ - /* Handle escape sequence items. For ones like \d, the ESC_values are - arranged to be the same as the corresponding OP_values in the default case - when PCRE2_UCP is not set (which is the only case in which they will appear - here). - - Note: \Q and \E are never seen here, as they were dealt with in - parse_pattern(). Neither are numerical back references or recursions, which - were turned into META_BACKREF or META_RECURSE items, respectively. \k and - \g, when followed by names, are turned into META_BACKREF_BYNAME or - META_RECURSE_BYNAME. */ - - case META_ESCAPE: - - /* We can test for escape sequences that consume a character because their - values lie between ESC_b and ESC_Z; this may have to change if any new ones - are ever created. For these sequences, we disable the setting of a first - character if it hasn't already been set. */ - - if (meta_arg > ESC_b && meta_arg < ESC_Z) - { - matched_char = TRUE; - if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE; - } - - /* Set values to reset to if this is followed by a zero repeat. */ - - zerofirstcu = firstcu; - zerofirstcuflags = firstcuflags; - zeroreqcu = reqcu; - zeroreqcuflags = reqcuflags; - - /* If Unicode is not supported, \P and \p are not allowed and are - faulted at parse time, so will never appear here. */ - -#ifdef SUPPORT_UNICODE - if (meta_arg == ESC_P || meta_arg == ESC_p) - { - uint32_t ptype = *(++pptr) >> 16; - uint32_t pdata = *pptr & 0xffff; - - /* The special case of \p{Any} is compiled to OP_ALLANY so as to benefit - from the auto-anchoring code. */ - - if (meta_arg == ESC_p && ptype == PT_ANY) - { - *code++ = OP_ALLANY; - } - else - { - *code++ = (meta_arg == ESC_p)? OP_PROP : OP_NOTPROP; - *code++ = ptype; - *code++ = pdata; - } - break; /* End META_ESCAPE */ - } -#endif - - /* \K is forbidden in lookarounds since 10.38 because that's what Perl has - done. However, there's an option, in case anyone was relying on it. */ - - if (cb->assert_depth > 0 && meta_arg == ESC_K && - (cb->cx->extra_options & PCRE2_EXTRA_ALLOW_LOOKAROUND_BSK) == 0) - { - *errorcodeptr = ERR99; - return 0; - } - - /* For the rest (including \X when Unicode is supported - if not it's - faulted at parse time), the OP value is the escape value when PCRE2_UCP is - not set; if it is set, these escapes do not show up here because they are - converted into Unicode property tests in parse_regex(). Note that \b and \B - do a one-character lookbehind, and \A also behaves as if it does. */ - - if (meta_arg == ESC_C) cb->external_flags |= PCRE2_HASBKC; /* Record */ - if ((meta_arg == ESC_b || meta_arg == ESC_B || meta_arg == ESC_A) && - cb->max_lookbehind == 0) - cb->max_lookbehind = 1; - - /* In non-UTF mode, and for both 32-bit modes, we turn \C into OP_ALLANY - instead of OP_ANYBYTE so that it works in DFA mode and in lookbehinds. */ - -#if PCRE2_CODE_UNIT_WIDTH == 32 - *code++ = (meta_arg == ESC_C)? OP_ALLANY : meta_arg; -#else - *code++ = (!utf && meta_arg == ESC_C)? OP_ALLANY : meta_arg; -#endif - break; /* End META_ESCAPE */ - - - /* ===================================================================*/ - /* Handle an unrecognized meta value. A parsed pattern value less than - META_END is a literal. Otherwise we have a problem. */ - - default: - if (meta >= META_END) - { -#ifdef DEBUG_SHOW_PARSED - fprintf(stderr, "** Unrecognized parsed pattern item 0x%.8x\n", *pptr); -#endif - *errorcodeptr = ERR89; /* Internal error - unrecognized. */ - return 0; - } - - /* Handle a literal character. We come here by goto in the case of a - 32-bit, non-UTF character whose value is greater than META_END. */ - - NORMAL_CHAR: - meta = *pptr; /* Get the full 32 bits */ - NORMAL_CHAR_SET: /* Character is already in meta */ - matched_char = TRUE; - - /* For caseless UTF or UCP mode, check whether this character has more than - one other case. If so, generate a special OP_PROP item instead of OP_CHARI. - */ - -#ifdef SUPPORT_UNICODE - if ((utf||ucp) && (options & PCRE2_CASELESS) != 0) - { - uint32_t caseset = UCD_CASESET(meta); - if (caseset != 0) - { - *code++ = OP_PROP; - *code++ = PT_CLIST; - *code++ = caseset; - if (firstcuflags == REQ_UNSET) - firstcuflags = zerofirstcuflags = REQ_NONE; - break; /* End handling this meta item */ - } - } -#endif - - /* Caseful matches, or caseless and not one of the multicase characters. We - come here by goto in the case of a positive class that contains only - case-partners of a character with just two cases; matched_char has already - been set TRUE and options fudged if necessary. */ - - CLASS_CASELESS_CHAR: - - /* Get the character's code units into mcbuffer, with the length in - mclength. When not in UTF mode, the length is always 1. */ - -#ifdef SUPPORT_UNICODE - if (utf) mclength = PRIV(ord2utf)(meta, mcbuffer); else -#endif - { - mclength = 1; - mcbuffer[0] = meta; - } - - /* Generate the appropriate code */ - - *code++ = ((options & PCRE2_CASELESS) != 0)? OP_CHARI : OP_CHAR; - memcpy(code, mcbuffer, CU2BYTES(mclength)); - code += mclength; - - /* Remember if \r or \n were seen */ - - if (mcbuffer[0] == CHAR_CR || mcbuffer[0] == CHAR_NL) - cb->external_flags |= PCRE2_HASCRORLF; - - /* Set the first and required code units appropriately. If no previous - first code unit, set it from this character, but revert to none on a zero - repeat. Otherwise, leave the firstcu value alone, and don't change it on - a zero repeat. */ - - if (firstcuflags == REQ_UNSET) - { - zerofirstcuflags = REQ_NONE; - zeroreqcu = reqcu; - zeroreqcuflags = reqcuflags; - - /* If the character is more than one code unit long, we can set a single - firstcu only if it is not to be matched caselessly. Multiple possible - starting code units may be picked up later in the studying code. */ - - if (mclength == 1 || req_caseopt == 0) - { - firstcu = mcbuffer[0]; - firstcuflags = req_caseopt; - if (mclength != 1) - { - reqcu = code[-1]; - reqcuflags = cb->req_varyopt; - } - } - else firstcuflags = reqcuflags = REQ_NONE; - } - - /* firstcu was previously set; we can set reqcu only if the length is - 1 or the matching is caseful. */ - - else - { - zerofirstcu = firstcu; - zerofirstcuflags = firstcuflags; - zeroreqcu = reqcu; - zeroreqcuflags = reqcuflags; - if (mclength == 1 || req_caseopt == 0) - { - reqcu = code[-1]; - reqcuflags = req_caseopt | cb->req_varyopt; - } - } - - /* If caselessness was temporarily instated, reset it. */ - - if (reset_caseful) - { - options &= ~PCRE2_CASELESS; - req_caseopt = 0; - reset_caseful = FALSE; - } - - break; /* End literal character handling */ - } /* End of big switch */ - } /* End of big loop */ - -/* Control never reaches here. */ -} - - - -/************************************************* -* Compile regex: a sequence of alternatives * -*************************************************/ - -/* On entry, pptr is pointing past the bracket meta, but on return it points to -the closing bracket or META_END. The code variable is pointing at the code unit -into which the BRA operator has been stored. This function is used during the -pre-compile phase when we are trying to find out the amount of memory needed, -as well as during the real compile phase. The value of lengthptr distinguishes -the two phases. - -Arguments: - options option bits, including any changes for this subpattern - codeptr -> the address of the current code pointer - pptrptr -> the address of the current parsed pattern pointer - errorcodeptr -> pointer to error code variable - skipunits skip this many code units at start (for brackets and OP_COND) - firstcuptr place to put the first required code unit - firstcuflagsptr place to put the first code unit flags - reqcuptr place to put the last required code unit - reqcuflagsptr place to put the last required code unit flags - bcptr pointer to the chain of currently open branches - cb points to the data block with tables pointers etc. - lengthptr NULL during the real compile phase - points to length accumulator during pre-compile phase - -Returns: 0 There has been an error - +1 Success, this group must match at least one character - -1 Success, this group may match an empty string -*/ - -static int -compile_regex(uint32_t options, PCRE2_UCHAR **codeptr, uint32_t **pptrptr, - int *errorcodeptr, uint32_t skipunits, uint32_t *firstcuptr, - uint32_t *firstcuflagsptr, uint32_t *reqcuptr, uint32_t *reqcuflagsptr, - branch_chain *bcptr, compile_block *cb, PCRE2_SIZE *lengthptr) -{ -PCRE2_UCHAR *code = *codeptr; -PCRE2_UCHAR *last_branch = code; -PCRE2_UCHAR *start_bracket = code; -BOOL lookbehind; -open_capitem capitem; -int capnumber = 0; -int okreturn = 1; -uint32_t *pptr = *pptrptr; -uint32_t firstcu, reqcu; -uint32_t lookbehindlength; -uint32_t firstcuflags, reqcuflags; -uint32_t branchfirstcu, branchreqcu; -uint32_t branchfirstcuflags, branchreqcuflags; -PCRE2_SIZE length; -branch_chain bc; - -/* If set, call the external function that checks for stack availability. */ - -if (cb->cx->stack_guard != NULL && - cb->cx->stack_guard(cb->parens_depth, cb->cx->stack_guard_data)) - { - *errorcodeptr= ERR33; - return 0; - } - -/* Miscellaneous initialization */ - -bc.outer = bcptr; -bc.current_branch = code; - -firstcu = reqcu = 0; -firstcuflags = reqcuflags = REQ_UNSET; - -/* Accumulate the length for use in the pre-compile phase. Start with the -length of the BRA and KET and any extra code units that are required at the -beginning. We accumulate in a local variable to save frequent testing of -lengthptr for NULL. We cannot do this by looking at the value of 'code' at the -start and end of each alternative, because compiled items are discarded during -the pre-compile phase so that the workspace is not exceeded. */ - -length = 2 + 2*LINK_SIZE + skipunits; - -/* Remember if this is a lookbehind assertion, and if it is, save its length -and skip over the pattern offset. */ - -lookbehind = *code == OP_ASSERTBACK || - *code == OP_ASSERTBACK_NOT || - *code == OP_ASSERTBACK_NA; - -if (lookbehind) - { - lookbehindlength = META_DATA(pptr[-1]); - pptr += SIZEOFFSET; - } -else lookbehindlength = 0; - -/* If this is a capturing subpattern, add to the chain of open capturing items -so that we can detect them if (*ACCEPT) is encountered. Note that only OP_CBRA -need be tested here; changing this opcode to one of its variants, e.g. -OP_SCBRAPOS, happens later, after the group has been compiled. */ - -if (*code == OP_CBRA) - { - capnumber = GET2(code, 1 + LINK_SIZE); - capitem.number = capnumber; - capitem.next = cb->open_caps; - capitem.assert_depth = cb->assert_depth; - cb->open_caps = &capitem; - } - -/* Offset is set zero to mark that this bracket is still open */ - -PUT(code, 1, 0); -code += 1 + LINK_SIZE + skipunits; - -/* Loop for each alternative branch */ - -for (;;) - { - int branch_return; - - /* Insert OP_REVERSE if this is as lookbehind assertion. */ - - if (lookbehind && lookbehindlength > 0) - { - *code++ = OP_REVERSE; - PUTINC(code, 0, lookbehindlength); - length += 1 + LINK_SIZE; - } - - /* Now compile the branch; in the pre-compile phase its length gets added - into the length. */ - - if ((branch_return = - compile_branch(&options, &code, &pptr, errorcodeptr, &branchfirstcu, - &branchfirstcuflags, &branchreqcu, &branchreqcuflags, &bc, - cb, (lengthptr == NULL)? NULL : &length)) == 0) - return 0; - - /* If a branch can match an empty string, so can the whole group. */ - - if (branch_return < 0) okreturn = -1; - - /* In the real compile phase, there is some post-processing to be done. */ - - if (lengthptr == NULL) - { - /* If this is the first branch, the firstcu and reqcu values for the - branch become the values for the regex. */ - - if (*last_branch != OP_ALT) - { - firstcu = branchfirstcu; - firstcuflags = branchfirstcuflags; - reqcu = branchreqcu; - reqcuflags = branchreqcuflags; - } - - /* If this is not the first branch, the first char and reqcu have to - match the values from all the previous branches, except that if the - previous value for reqcu didn't have REQ_VARY set, it can still match, - and we set REQ_VARY for the group from this branch's value. */ - - else - { - /* If we previously had a firstcu, but it doesn't match the new branch, - we have to abandon the firstcu for the regex, but if there was - previously no reqcu, it takes on the value of the old firstcu. */ - - if (firstcuflags != branchfirstcuflags || firstcu != branchfirstcu) - { - if (firstcuflags < REQ_NONE) - { - if (reqcuflags >= REQ_NONE) - { - reqcu = firstcu; - reqcuflags = firstcuflags; - } - } - firstcuflags = REQ_NONE; - } - - /* If we (now or from before) have no firstcu, a firstcu from the - branch becomes a reqcu if there isn't a branch reqcu. */ - - if (firstcuflags >= REQ_NONE && branchfirstcuflags < REQ_NONE && - branchreqcuflags >= REQ_NONE) - { - branchreqcu = branchfirstcu; - branchreqcuflags = branchfirstcuflags; - } - - /* Now ensure that the reqcus match */ - - if (((reqcuflags & ~REQ_VARY) != (branchreqcuflags & ~REQ_VARY)) || - reqcu != branchreqcu) - reqcuflags = REQ_NONE; - else - { - reqcu = branchreqcu; - reqcuflags |= branchreqcuflags; /* To "or" REQ_VARY if present */ - } - } - } - - /* Handle reaching the end of the expression, either ')' or end of pattern. - In the real compile phase, go back through the alternative branches and - reverse the chain of offsets, with the field in the BRA item now becoming an - offset to the first alternative. If there are no alternatives, it points to - the end of the group. The length in the terminating ket is always the length - of the whole bracketed item. Return leaving the pointer at the terminating - char. */ - - if (META_CODE(*pptr) != META_ALT) - { - if (lengthptr == NULL) - { - PCRE2_SIZE branch_length = code - last_branch; - do - { - PCRE2_SIZE prev_length = GET(last_branch, 1); - PUT(last_branch, 1, branch_length); - branch_length = prev_length; - last_branch -= branch_length; - } - while (branch_length > 0); - } - - /* Fill in the ket */ - - *code = OP_KET; - PUT(code, 1, (int)(code - start_bracket)); - code += 1 + LINK_SIZE; - - /* If it was a capturing subpattern, remove the block from the chain. */ - - if (capnumber > 0) cb->open_caps = cb->open_caps->next; - - /* Set values to pass back */ - - *codeptr = code; - *pptrptr = pptr; - *firstcuptr = firstcu; - *firstcuflagsptr = firstcuflags; - *reqcuptr = reqcu; - *reqcuflagsptr = reqcuflags; - if (lengthptr != NULL) - { - if (OFLOW_MAX - *lengthptr < length) - { - *errorcodeptr = ERR20; - return 0; - } - *lengthptr += length; - } - return okreturn; - } - - /* Another branch follows. In the pre-compile phase, we can move the code - pointer back to where it was for the start of the first branch. (That is, - pretend that each branch is the only one.) - - In the real compile phase, insert an ALT node. Its length field points back - to the previous branch while the bracket remains open. At the end the chain - is reversed. It's done like this so that the start of the bracket has a - zero offset until it is closed, making it possible to detect recursion. */ - - if (lengthptr != NULL) - { - code = *codeptr + 1 + LINK_SIZE + skipunits; - length += 1 + LINK_SIZE; - } - else - { - *code = OP_ALT; - PUT(code, 1, (int)(code - last_branch)); - bc.current_branch = last_branch = code; - code += 1 + LINK_SIZE; - } - - /* Set the lookbehind length (if not in a lookbehind the value will be zero) - and then advance past the vertical bar. */ - - lookbehindlength = META_DATA(*pptr); - pptr++; - } -/* Control never reaches here */ -} - - - -/************************************************* -* Check for anchored pattern * -*************************************************/ - -/* Try to find out if this is an anchored regular expression. Consider each -alternative branch. If they all start with OP_SOD or OP_CIRC, or with a bracket -all of whose alternatives start with OP_SOD or OP_CIRC (recurse ad lib), then -it's anchored. However, if this is a multiline pattern, then only OP_SOD will -be found, because ^ generates OP_CIRCM in that mode. - -We can also consider a regex to be anchored if OP_SOM starts all its branches. -This is the code for \G, which means "match at start of match position, taking -into account the match offset". - -A branch is also implicitly anchored if it starts with .* and DOTALL is set, -because that will try the rest of the pattern at all possible matching points, -so there is no point trying again.... er .... - -.... except when the .* appears inside capturing parentheses, and there is a -subsequent back reference to those parentheses. We haven't enough information -to catch that case precisely. - -At first, the best we could do was to detect when .* was in capturing brackets -and the highest back reference was greater than or equal to that level. -However, by keeping a bitmap of the first 31 back references, we can catch some -of the more common cases more precisely. - -... A second exception is when the .* appears inside an atomic group, because -this prevents the number of characters it matches from being adjusted. - -Arguments: - code points to start of the compiled pattern - bracket_map a bitmap of which brackets we are inside while testing; this - handles up to substring 31; after that we just have to take - the less precise approach - cb points to the compile data block - atomcount atomic group level - inassert TRUE if in an assertion - -Returns: TRUE or FALSE -*/ - -static BOOL -is_anchored(PCRE2_SPTR code, uint32_t bracket_map, compile_block *cb, - int atomcount, BOOL inassert) -{ -do { - PCRE2_SPTR scode = first_significant_code( - code + PRIV(OP_lengths)[*code], FALSE); - int op = *scode; - - /* Non-capturing brackets */ - - if (op == OP_BRA || op == OP_BRAPOS || - op == OP_SBRA || op == OP_SBRAPOS) - { - if (!is_anchored(scode, bracket_map, cb, atomcount, inassert)) - return FALSE; - } - - /* Capturing brackets */ - - else if (op == OP_CBRA || op == OP_CBRAPOS || - op == OP_SCBRA || op == OP_SCBRAPOS) - { - int n = GET2(scode, 1+LINK_SIZE); - uint32_t new_map = bracket_map | ((n < 32)? (1u << n) : 1); - if (!is_anchored(scode, new_map, cb, atomcount, inassert)) return FALSE; - } - - /* Positive forward assertion */ - - else if (op == OP_ASSERT || op == OP_ASSERT_NA) - { - if (!is_anchored(scode, bracket_map, cb, atomcount, TRUE)) return FALSE; - } - - /* Condition. If there is no second branch, it can't be anchored. */ - - else if (op == OP_COND || op == OP_SCOND) - { - if (scode[GET(scode,1)] != OP_ALT) return FALSE; - if (!is_anchored(scode, bracket_map, cb, atomcount, inassert)) - return FALSE; - } - - /* Atomic groups */ - - else if (op == OP_ONCE) - { - if (!is_anchored(scode, bracket_map, cb, atomcount + 1, inassert)) - return FALSE; - } - - /* .* is not anchored unless DOTALL is set (which generates OP_ALLANY) and - it isn't in brackets that are or may be referenced or inside an atomic - group or an assertion. Also the pattern must not contain *PRUNE or *SKIP, - because these break the feature. Consider, for example, /(?s).*?(*PRUNE)b/ - with the subject "aab", which matches "b", i.e. not at the start of a line. - There is also an option that disables auto-anchoring. */ - - else if ((op == OP_TYPESTAR || op == OP_TYPEMINSTAR || - op == OP_TYPEPOSSTAR)) - { - if (scode[1] != OP_ALLANY || (bracket_map & cb->backref_map) != 0 || - atomcount > 0 || cb->had_pruneorskip || inassert || - (cb->external_options & PCRE2_NO_DOTSTAR_ANCHOR) != 0) - return FALSE; - } - - /* Check for explicit anchoring */ - - else if (op != OP_SOD && op != OP_SOM && op != OP_CIRC) return FALSE; - - code += GET(code, 1); - } -while (*code == OP_ALT); /* Loop for each alternative */ -return TRUE; -} - - - -/************************************************* -* Check for starting with ^ or .* * -*************************************************/ - -/* This is called to find out if every branch starts with ^ or .* so that -"first char" processing can be done to speed things up in multiline -matching and for non-DOTALL patterns that start with .* (which must start at -the beginning or after \n). As in the case of is_anchored() (see above), we -have to take account of back references to capturing brackets that contain .* -because in that case we can't make the assumption. Also, the appearance of .* -inside atomic brackets or in an assertion, or in a pattern that contains *PRUNE -or *SKIP does not count, because once again the assumption no longer holds. - -Arguments: - code points to start of the compiled pattern or a group - bracket_map a bitmap of which brackets we are inside while testing; this - handles up to substring 31; after that we just have to take - the less precise approach - cb points to the compile data - atomcount atomic group level - inassert TRUE if in an assertion - -Returns: TRUE or FALSE -*/ - -static BOOL -is_startline(PCRE2_SPTR code, unsigned int bracket_map, compile_block *cb, - int atomcount, BOOL inassert) -{ -do { - PCRE2_SPTR scode = first_significant_code( - code + PRIV(OP_lengths)[*code], FALSE); - int op = *scode; - - /* If we are at the start of a conditional assertion group, *both* the - conditional assertion *and* what follows the condition must satisfy the test - for start of line. Other kinds of condition fail. Note that there may be an - auto-callout at the start of a condition. */ - - if (op == OP_COND) - { - scode += 1 + LINK_SIZE; - - if (*scode == OP_CALLOUT) scode += PRIV(OP_lengths)[OP_CALLOUT]; - else if (*scode == OP_CALLOUT_STR) scode += GET(scode, 1 + 2*LINK_SIZE); - - switch (*scode) - { - case OP_CREF: - case OP_DNCREF: - case OP_RREF: - case OP_DNRREF: - case OP_FAIL: - case OP_FALSE: - case OP_TRUE: - return FALSE; - - default: /* Assertion */ - if (!is_startline(scode, bracket_map, cb, atomcount, TRUE)) return FALSE; - do scode += GET(scode, 1); while (*scode == OP_ALT); - scode += 1 + LINK_SIZE; - break; - } - scode = first_significant_code(scode, FALSE); - op = *scode; - } - - /* Non-capturing brackets */ - - if (op == OP_BRA || op == OP_BRAPOS || - op == OP_SBRA || op == OP_SBRAPOS) - { - if (!is_startline(scode, bracket_map, cb, atomcount, inassert)) - return FALSE; - } - - /* Capturing brackets */ - - else if (op == OP_CBRA || op == OP_CBRAPOS || - op == OP_SCBRA || op == OP_SCBRAPOS) - { - int n = GET2(scode, 1+LINK_SIZE); - unsigned int new_map = bracket_map | ((n < 32)? (1u << n) : 1); - if (!is_startline(scode, new_map, cb, atomcount, inassert)) return FALSE; - } - - /* Positive forward assertions */ - - else if (op == OP_ASSERT || op == OP_ASSERT_NA) - { - if (!is_startline(scode, bracket_map, cb, atomcount, TRUE)) - return FALSE; - } - - /* Atomic brackets */ - - else if (op == OP_ONCE) - { - if (!is_startline(scode, bracket_map, cb, atomcount + 1, inassert)) - return FALSE; - } - - /* .* means "start at start or after \n" if it isn't in atomic brackets or - brackets that may be referenced or an assertion, and as long as the pattern - does not contain *PRUNE or *SKIP, because these break the feature. Consider, - for example, /.*?a(*PRUNE)b/ with the subject "aab", which matches "ab", - i.e. not at the start of a line. There is also an option that disables this - optimization. */ - - else if (op == OP_TYPESTAR || op == OP_TYPEMINSTAR || op == OP_TYPEPOSSTAR) - { - if (scode[1] != OP_ANY || (bracket_map & cb->backref_map) != 0 || - atomcount > 0 || cb->had_pruneorskip || inassert || - (cb->external_options & PCRE2_NO_DOTSTAR_ANCHOR) != 0) - return FALSE; - } - - /* Check for explicit circumflex; anything else gives a FALSE result. Note - in particular that this includes atomic brackets OP_ONCE because the number - of characters matched by .* cannot be adjusted inside them. */ - - else if (op != OP_CIRC && op != OP_CIRCM) return FALSE; - - /* Move on to the next alternative */ - - code += GET(code, 1); - } -while (*code == OP_ALT); /* Loop for each alternative */ -return TRUE; -} - - - -/************************************************* -* Scan compiled regex for recursion reference * -*************************************************/ - -/* This function scans through a compiled pattern until it finds an instance of -OP_RECURSE. - -Arguments: - code points to start of expression - utf TRUE in UTF mode - -Returns: pointer to the opcode for OP_RECURSE, or NULL if not found -*/ - -static PCRE2_SPTR -find_recurse(PCRE2_SPTR code, BOOL utf) -{ -for (;;) - { - PCRE2_UCHAR c = *code; - if (c == OP_END) return NULL; - if (c == OP_RECURSE) return code; - - /* XCLASS is used for classes that cannot be represented just by a bit map. - This includes negated single high-valued characters. CALLOUT_STR is used for - callouts with string arguments. In both cases the length in the table is - zero; the actual length is stored in the compiled code. */ - - if (c == OP_XCLASS) code += GET(code, 1); - else if (c == OP_CALLOUT_STR) code += GET(code, 1 + 2*LINK_SIZE); - - /* Otherwise, we can get the item's length from the table, except that for - repeated character types, we have to test for \p and \P, which have an extra - two code units of parameters, and for MARK/PRUNE/SKIP/THEN with an argument, - we must add in its length. */ - - else - { - switch(c) - { - case OP_TYPESTAR: - case OP_TYPEMINSTAR: - case OP_TYPEPLUS: - case OP_TYPEMINPLUS: - case OP_TYPEQUERY: - case OP_TYPEMINQUERY: - case OP_TYPEPOSSTAR: - case OP_TYPEPOSPLUS: - case OP_TYPEPOSQUERY: - if (code[1] == OP_PROP || code[1] == OP_NOTPROP) code += 2; - break; - - case OP_TYPEPOSUPTO: - case OP_TYPEUPTO: - case OP_TYPEMINUPTO: - case OP_TYPEEXACT: - if (code[1 + IMM2_SIZE] == OP_PROP || code[1 + IMM2_SIZE] == OP_NOTPROP) - code += 2; - break; - - case OP_MARK: - case OP_COMMIT_ARG: - case OP_PRUNE_ARG: - case OP_SKIP_ARG: - case OP_THEN_ARG: - code += code[1]; - break; - } - - /* Add in the fixed length from the table */ - - code += PRIV(OP_lengths)[c]; - - /* In UTF-8 and UTF-16 modes, opcodes that are followed by a character may - be followed by a multi-unit character. The length in the table is a - minimum, so we have to arrange to skip the extra units. */ - -#ifdef MAYBE_UTF_MULTI - if (utf) switch(c) - { - case OP_CHAR: - case OP_CHARI: - case OP_NOT: - case OP_NOTI: - case OP_EXACT: - case OP_EXACTI: - case OP_NOTEXACT: - case OP_NOTEXACTI: - case OP_UPTO: - case OP_UPTOI: - case OP_NOTUPTO: - case OP_NOTUPTOI: - case OP_MINUPTO: - case OP_MINUPTOI: - case OP_NOTMINUPTO: - case OP_NOTMINUPTOI: - case OP_POSUPTO: - case OP_POSUPTOI: - case OP_NOTPOSUPTO: - case OP_NOTPOSUPTOI: - case OP_STAR: - case OP_STARI: - case OP_NOTSTAR: - case OP_NOTSTARI: - case OP_MINSTAR: - case OP_MINSTARI: - case OP_NOTMINSTAR: - case OP_NOTMINSTARI: - case OP_POSSTAR: - case OP_POSSTARI: - case OP_NOTPOSSTAR: - case OP_NOTPOSSTARI: - case OP_PLUS: - case OP_PLUSI: - case OP_NOTPLUS: - case OP_NOTPLUSI: - case OP_MINPLUS: - case OP_MINPLUSI: - case OP_NOTMINPLUS: - case OP_NOTMINPLUSI: - case OP_POSPLUS: - case OP_POSPLUSI: - case OP_NOTPOSPLUS: - case OP_NOTPOSPLUSI: - case OP_QUERY: - case OP_QUERYI: - case OP_NOTQUERY: - case OP_NOTQUERYI: - case OP_MINQUERY: - case OP_MINQUERYI: - case OP_NOTMINQUERY: - case OP_NOTMINQUERYI: - case OP_POSQUERY: - case OP_POSQUERYI: - case OP_NOTPOSQUERY: - case OP_NOTPOSQUERYI: - if (HAS_EXTRALEN(code[-1])) code += GET_EXTRALEN(code[-1]); - break; - } -#else - (void)(utf); /* Keep compiler happy by referencing function argument */ -#endif /* MAYBE_UTF_MULTI */ - } - } -} - - - -/************************************************* -* Check for asserted fixed first code unit * -*************************************************/ - -/* During compilation, the "first code unit" settings from forward assertions -are discarded, because they can cause conflicts with actual literals that -follow. However, if we end up without a first code unit setting for an -unanchored pattern, it is worth scanning the regex to see if there is an -initial asserted first code unit. If all branches start with the same asserted -code unit, or with a non-conditional bracket all of whose alternatives start -with the same asserted code unit (recurse ad lib), then we return that code -unit, with the flags set to zero or REQ_CASELESS; otherwise return zero with -REQ_NONE in the flags. - -Arguments: - code points to start of compiled pattern - flags points to the first code unit flags - inassert non-zero if in an assertion - -Returns: the fixed first code unit, or 0 with REQ_NONE in flags -*/ - -static uint32_t -find_firstassertedcu(PCRE2_SPTR code, uint32_t *flags, uint32_t inassert) -{ -uint32_t c = 0; -uint32_t cflags = REQ_NONE; - -*flags = REQ_NONE; -do { - uint32_t d; - uint32_t dflags; - int xl = (*code == OP_CBRA || *code == OP_SCBRA || - *code == OP_CBRAPOS || *code == OP_SCBRAPOS)? IMM2_SIZE:0; - PCRE2_SPTR scode = first_significant_code(code + 1+LINK_SIZE + xl, TRUE); - PCRE2_UCHAR op = *scode; - - switch(op) - { - default: - return 0; - - case OP_BRA: - case OP_BRAPOS: - case OP_CBRA: - case OP_SCBRA: - case OP_CBRAPOS: - case OP_SCBRAPOS: - case OP_ASSERT: - case OP_ASSERT_NA: - case OP_ONCE: - case OP_SCRIPT_RUN: - d = find_firstassertedcu(scode, &dflags, inassert + - ((op == OP_ASSERT || op == OP_ASSERT_NA)?1:0)); - if (dflags >= REQ_NONE) return 0; - if (cflags >= REQ_NONE) { c = d; cflags = dflags; } - else if (c != d || cflags != dflags) return 0; - break; - - case OP_EXACT: - scode += IMM2_SIZE; - /* Fall through */ - - case OP_CHAR: - case OP_PLUS: - case OP_MINPLUS: - case OP_POSPLUS: - if (inassert == 0) return 0; - if (cflags >= REQ_NONE) { c = scode[1]; cflags = 0; } - else if (c != scode[1]) return 0; - break; - - case OP_EXACTI: - scode += IMM2_SIZE; - /* Fall through */ - - case OP_CHARI: - case OP_PLUSI: - case OP_MINPLUSI: - case OP_POSPLUSI: - if (inassert == 0) return 0; - - /* If the character is more than one code unit long, we cannot set its - first code unit when matching caselessly. Later scanning may pick up - multiple code units. */ - -#ifdef SUPPORT_UNICODE -#if PCRE2_CODE_UNIT_WIDTH == 8 - if (scode[1] >= 0x80) return 0; -#elif PCRE2_CODE_UNIT_WIDTH == 16 - if (scode[1] >= 0xd800 && scode[1] <= 0xdfff) return 0; -#endif -#endif - - if (cflags >= REQ_NONE) { c = scode[1]; cflags = REQ_CASELESS; } - else if (c != scode[1]) return 0; - break; - } - - code += GET(code, 1); - } -while (*code == OP_ALT); - -*flags = cflags; -return c; -} - - - -/************************************************* -* Add an entry to the name/number table * -*************************************************/ - -/* This function is called between compiling passes to add an entry to the -name/number table, maintaining alphabetical order. Checking for permitted -and forbidden duplicates has already been done. - -Arguments: - cb the compile data block - name the name to add - length the length of the name - groupno the group number - tablecount the count of names in the table so far - -Returns: nothing -*/ - -static void -add_name_to_table(compile_block *cb, PCRE2_SPTR name, int length, - unsigned int groupno, uint32_t tablecount) -{ -uint32_t i; -PCRE2_UCHAR *slot = cb->name_table; - -for (i = 0; i < tablecount; i++) - { - int crc = memcmp(name, slot+IMM2_SIZE, CU2BYTES(length)); - if (crc == 0 && slot[IMM2_SIZE+length] != 0) - crc = -1; /* Current name is a substring */ - - /* Make space in the table and break the loop for an earlier name. For a - duplicate or later name, carry on. We do this for duplicates so that in the - simple case (when ?(| is not used) they are in order of their numbers. In all - cases they are in the order in which they appear in the pattern. */ - - if (crc < 0) - { - (void)memmove(slot + cb->name_entry_size, slot, - CU2BYTES((tablecount - i) * cb->name_entry_size)); - break; - } - - /* Continue the loop for a later or duplicate name */ - - slot += cb->name_entry_size; - } - -PUT2(slot, 0, groupno); -memcpy(slot + IMM2_SIZE, name, CU2BYTES(length)); - -/* Add a terminating zero and fill the rest of the slot with zeroes so that -the memory is all initialized. Otherwise valgrind moans about uninitialized -memory when saving serialized compiled patterns. */ - -memset(slot + IMM2_SIZE + length, 0, - CU2BYTES(cb->name_entry_size - length - IMM2_SIZE)); -} - - - -/************************************************* -* Skip in parsed pattern * -*************************************************/ - -/* This function is called to skip parts of the parsed pattern when finding the -length of a lookbehind branch. It is called after (*ACCEPT) and (*FAIL) to find -the end of the branch, it is called to skip over an internal lookaround or -(DEFINE) group, and it is also called to skip to the end of a class, during -which it will never encounter nested groups (but there's no need to have -special code for that). - -When called to find the end of a branch or group, pptr must point to the first -meta code inside the branch, not the branch-starting code. In other cases it -can point to the item that causes the function to be called. - -Arguments: - pptr current pointer to skip from - skiptype PSKIP_CLASS when skipping to end of class - PSKIP_ALT when META_ALT ends the skip - PSKIP_KET when only META_KET ends the skip - -Returns: new value of pptr - NULL if META_END is reached - should never occur - or for an unknown meta value - likewise -*/ - -static uint32_t * -parsed_skip(uint32_t *pptr, uint32_t skiptype) -{ -uint32_t nestlevel = 0; - -for (;; pptr++) - { - uint32_t meta = META_CODE(*pptr); - - switch(meta) - { - default: /* Just skip over most items */ - if (meta < META_END) continue; /* Literal */ - break; - - /* This should never occur. */ - - case META_END: - return NULL; - - /* The data for these items is variable in length. */ - - case META_BACKREF: /* Offset is present only if group >= 10 */ - if (META_DATA(*pptr) >= 10) pptr += SIZEOFFSET; - break; - - case META_ESCAPE: /* A few escapes are followed by data items. */ - switch (META_DATA(*pptr)) - { - case ESC_P: - case ESC_p: - pptr += 1; - break; - - case ESC_g: - case ESC_k: - pptr += 1 + SIZEOFFSET; - break; - } - break; - - case META_MARK: /* Add the length of the name. */ - case META_COMMIT_ARG: - case META_PRUNE_ARG: - case META_SKIP_ARG: - case META_THEN_ARG: - pptr += pptr[1]; - break; - - /* These are the "active" items in this loop. */ - - case META_CLASS_END: - if (skiptype == PSKIP_CLASS) return pptr; - break; - - case META_ATOMIC: - case META_CAPTURE: - case META_COND_ASSERT: - case META_COND_DEFINE: - case META_COND_NAME: - case META_COND_NUMBER: - case META_COND_RNAME: - case META_COND_RNUMBER: - case META_COND_VERSION: - case META_LOOKAHEAD: - case META_LOOKAHEADNOT: - case META_LOOKAHEAD_NA: - case META_LOOKBEHIND: - case META_LOOKBEHINDNOT: - case META_LOOKBEHIND_NA: - case META_NOCAPTURE: - case META_SCRIPT_RUN: - nestlevel++; - break; - - case META_ALT: - if (nestlevel == 0 && skiptype == PSKIP_ALT) return pptr; - break; - - case META_KET: - if (nestlevel == 0) return pptr; - nestlevel--; - break; - } - - /* The extra data item length for each meta is in a table. */ - - meta = (meta >> 16) & 0x7fff; - if (meta >= sizeof(meta_extra_lengths)) return NULL; - pptr += meta_extra_lengths[meta]; - } -/* Control never reaches here */ -return pptr; -} - - - -/************************************************* -* Find length of a parsed group * -*************************************************/ - -/* This is called for nested groups within a branch of a lookbehind whose -length is being computed. If all the branches in the nested group have the same -length, that is OK. On entry, the pointer must be at the first element after -the group initializing code. On exit it points to OP_KET. Caching is used to -improve processing speed when the same capturing group occurs many times. - -Arguments: - pptrptr pointer to pointer in the parsed pattern - isinline FALSE if a reference or recursion; TRUE for inline group - errcodeptr pointer to the errorcode - lcptr pointer to the loop counter - group number of captured group or -1 for a non-capturing group - recurses chain of recurse_check to catch mutual recursion - cb pointer to the compile data - -Returns: the group length or a negative number -*/ - -static int -get_grouplength(uint32_t **pptrptr, BOOL isinline, int *errcodeptr, int *lcptr, - int group, parsed_recurse_check *recurses, compile_block *cb) -{ -int branchlength; -int grouplength = -1; - -/* The cache can be used only if there is no possibility of there being two -groups with the same number. We do not need to set the end pointer for a group -that is being processed as a back reference or recursion, but we must do so for -an inline group. */ - -if (group > 0 && (cb->external_flags & PCRE2_DUPCAPUSED) == 0) - { - uint32_t groupinfo = cb->groupinfo[group]; - if ((groupinfo & GI_NOT_FIXED_LENGTH) != 0) return -1; - if ((groupinfo & GI_SET_FIXED_LENGTH) != 0) - { - if (isinline) *pptrptr = parsed_skip(*pptrptr, PSKIP_KET); - return groupinfo & GI_FIXED_LENGTH_MASK; - } - } - -/* Scan the group. In this case we find the end pointer of necessity. */ - -for(;;) - { - branchlength = get_branchlength(pptrptr, errcodeptr, lcptr, recurses, cb); - if (branchlength < 0) goto ISNOTFIXED; - if (grouplength == -1) grouplength = branchlength; - else if (grouplength != branchlength) goto ISNOTFIXED; - if (**pptrptr == META_KET) break; - *pptrptr += 1; /* Skip META_ALT */ - } - -if (group > 0) - cb->groupinfo[group] |= (uint32_t)(GI_SET_FIXED_LENGTH | grouplength); -return grouplength; - -ISNOTFIXED: -if (group > 0) cb->groupinfo[group] |= GI_NOT_FIXED_LENGTH; -return -1; -} - - - -/************************************************* -* Find length of a parsed branch * -*************************************************/ - -/* Return a fixed length for a branch in a lookbehind, giving an error if the -length is not fixed. On entry, *pptrptr points to the first element inside the -branch. On exit it is set to point to the ALT or KET. - -Arguments: - pptrptr pointer to pointer in the parsed pattern - errcodeptr pointer to error code - lcptr pointer to loop counter - recurses chain of recurse_check to catch mutual recursion - cb pointer to compile block - -Returns: the length, or a negative value on error -*/ - -static int -get_branchlength(uint32_t **pptrptr, int *errcodeptr, int *lcptr, - parsed_recurse_check *recurses, compile_block *cb) -{ -int branchlength = 0; -int grouplength; -uint32_t lastitemlength = 0; -uint32_t *pptr = *pptrptr; -PCRE2_SIZE offset; -parsed_recurse_check this_recurse; - -/* A large and/or complex regex can take too long to process. This can happen -more often when (?| groups are present in the pattern because their length -cannot be cached. */ - -if ((*lcptr)++ > 2000) - { - *errcodeptr = ERR35; /* Lookbehind is too complicated */ - return -1; - } - -/* Scan the branch, accumulating the length. */ - -for (;; pptr++) - { - parsed_recurse_check *r; - uint32_t *gptr, *gptrend; - uint32_t escape; - uint32_t group = 0; - uint32_t itemlength = 0; - - if (*pptr < META_END) - { - itemlength = 1; - } - - else switch (META_CODE(*pptr)) - { - case META_KET: - case META_ALT: - goto EXIT; - - /* (*ACCEPT) and (*FAIL) terminate the branch, but we must skip to the - actual termination. */ - - case META_ACCEPT: - case META_FAIL: - pptr = parsed_skip(pptr, PSKIP_ALT); - if (pptr == NULL) goto PARSED_SKIP_FAILED; - goto EXIT; - - case META_MARK: - case META_COMMIT_ARG: - case META_PRUNE_ARG: - case META_SKIP_ARG: - case META_THEN_ARG: - pptr += pptr[1] + 1; - break; - - case META_CIRCUMFLEX: - case META_COMMIT: - case META_DOLLAR: - case META_PRUNE: - case META_SKIP: - case META_THEN: - break; - - case META_OPTIONS: - pptr += 1; - break; - - case META_BIGVALUE: - itemlength = 1; - pptr += 1; - break; - - case META_CLASS: - case META_CLASS_NOT: - itemlength = 1; - pptr = parsed_skip(pptr, PSKIP_CLASS); - if (pptr == NULL) goto PARSED_SKIP_FAILED; - break; - - case META_CLASS_EMPTY_NOT: - case META_DOT: - itemlength = 1; - break; - - case META_CALLOUT_NUMBER: - pptr += 3; - break; - - case META_CALLOUT_STRING: - pptr += 3 + SIZEOFFSET; - break; - - /* Only some escapes consume a character. Of those, \R and \X are never - allowed because they might match more than character. \C is allowed only in - 32-bit and non-UTF 8/16-bit modes. */ - - case META_ESCAPE: - escape = META_DATA(*pptr); - if (escape == ESC_R || escape == ESC_X) return -1; - if (escape > ESC_b && escape < ESC_Z) - { -#if PCRE2_CODE_UNIT_WIDTH != 32 - if ((cb->external_options & PCRE2_UTF) != 0 && escape == ESC_C) - { - *errcodeptr = ERR36; - return -1; - } -#endif - itemlength = 1; - if (escape == ESC_p || escape == ESC_P) pptr++; /* Skip prop data */ - } - break; - - /* Lookaheads do not contribute to the length of this branch, but they may - contain lookbehinds within them whose lengths need to be set. */ - - case META_LOOKAHEAD: - case META_LOOKAHEADNOT: - case META_LOOKAHEAD_NA: - *errcodeptr = check_lookbehinds(pptr + 1, &pptr, recurses, cb, lcptr); - if (*errcodeptr != 0) return -1; - - /* Ignore any qualifiers that follow a lookahead assertion. */ - - switch (pptr[1]) - { - case META_ASTERISK: - case META_ASTERISK_PLUS: - case META_ASTERISK_QUERY: - case META_PLUS: - case META_PLUS_PLUS: - case META_PLUS_QUERY: - case META_QUERY: - case META_QUERY_PLUS: - case META_QUERY_QUERY: - pptr++; - break; - - case META_MINMAX: - case META_MINMAX_PLUS: - case META_MINMAX_QUERY: - pptr += 3; - break; - - default: - break; - } - break; - - /* A nested lookbehind does not contribute any length to this lookbehind, - but must itself be checked and have its lengths set. */ - - case META_LOOKBEHIND: - case META_LOOKBEHINDNOT: - case META_LOOKBEHIND_NA: - if (!set_lookbehind_lengths(&pptr, errcodeptr, lcptr, recurses, cb)) - return -1; - break; - - /* Back references and recursions are handled by very similar code. At this - stage, the names generated in the parsing pass are available, but the main - name table has not yet been created. So for the named varieties, scan the - list of names in order to get the number of the first one in the pattern, - and whether or not this name is duplicated. */ - - case META_BACKREF_BYNAME: - if ((cb->external_options & PCRE2_MATCH_UNSET_BACKREF) != 0) - goto ISNOTFIXED; - /* Fall through */ - - case META_RECURSE_BYNAME: - { - int i; - PCRE2_SPTR name; - BOOL is_dupname = FALSE; - named_group *ng = cb->named_groups; - uint32_t meta_code = META_CODE(*pptr); - uint32_t length = *(++pptr); - - GETPLUSOFFSET(offset, pptr); - name = cb->start_pattern + offset; - for (i = 0; i < cb->names_found; i++, ng++) - { - if (length == ng->length && PRIV(strncmp)(name, ng->name, length) == 0) - { - group = ng->number; - is_dupname = ng->isdup; - break; - } - } - - if (group == 0) - { - *errcodeptr = ERR15; /* Non-existent subpattern */ - cb->erroroffset = offset; - return -1; - } - - /* A numerical back reference can be fixed length if duplicate capturing - groups are not being used. A non-duplicate named back reference can also - be handled. */ - - if (meta_code == META_RECURSE_BYNAME || - (!is_dupname && (cb->external_flags & PCRE2_DUPCAPUSED) == 0)) - goto RECURSE_OR_BACKREF_LENGTH; /* Handle as a numbered version. */ - } - goto ISNOTFIXED; /* Duplicate name or number */ - - /* The offset values for back references < 10 are in a separate vector - because otherwise they would use more than two parsed pattern elements on - 64-bit systems. */ - - case META_BACKREF: - if ((cb->external_options & PCRE2_MATCH_UNSET_BACKREF) != 0 || - (cb->external_flags & PCRE2_DUPCAPUSED) != 0) - goto ISNOTFIXED; - group = META_DATA(*pptr); - if (group < 10) - { - offset = cb->small_ref_offset[group]; - goto RECURSE_OR_BACKREF_LENGTH; - } - - /* Fall through */ - /* For groups >= 10 - picking up group twice does no harm. */ - - /* A true recursion implies not fixed length, but a subroutine call may - be OK. Back reference "recursions" are also failed. */ - - case META_RECURSE: - group = META_DATA(*pptr); - GETPLUSOFFSET(offset, pptr); - - RECURSE_OR_BACKREF_LENGTH: - if (group > cb->bracount) - { - cb->erroroffset = offset; - *errcodeptr = ERR15; /* Non-existent subpattern */ - return -1; - } - if (group == 0) goto ISNOTFIXED; /* Local recursion */ - for (gptr = cb->parsed_pattern; *gptr != META_END; gptr++) - { - if (META_CODE(*gptr) == META_BIGVALUE) gptr++; - else if (*gptr == (META_CAPTURE | group)) break; - } - - /* We must start the search for the end of the group at the first meta code - inside the group. Otherwise it will be treated as an enclosed group. */ - - gptrend = parsed_skip(gptr + 1, PSKIP_KET); - if (gptrend == NULL) goto PARSED_SKIP_FAILED; - if (pptr > gptr && pptr < gptrend) goto ISNOTFIXED; /* Local recursion */ - for (r = recurses; r != NULL; r = r->prev) if (r->groupptr == gptr) break; - if (r != NULL) goto ISNOTFIXED; /* Mutual recursion */ - this_recurse.prev = recurses; - this_recurse.groupptr = gptr; - - /* We do not need to know the position of the end of the group, that is, - gptr is not used after the call to get_grouplength(). Setting the second - argument FALSE stops it scanning for the end when the length can be found - in the cache. */ - - gptr++; - grouplength = get_grouplength(&gptr, FALSE, errcodeptr, lcptr, group, - &this_recurse, cb); - if (grouplength < 0) - { - if (*errcodeptr == 0) goto ISNOTFIXED; - return -1; /* Error already set */ - } - itemlength = grouplength; - break; - - /* A (DEFINE) group is never obeyed inline and so it does not contribute to - the length of this branch. Skip from the following item to the next - unpaired ket. */ - - case META_COND_DEFINE: - pptr = parsed_skip(pptr + 1, PSKIP_KET); - break; - - /* Check other nested groups - advance past the initial data for each type - and then seek a fixed length with get_grouplength(). */ - - case META_COND_NAME: - case META_COND_NUMBER: - case META_COND_RNAME: - case META_COND_RNUMBER: - pptr += 2 + SIZEOFFSET; - goto CHECK_GROUP; - - case META_COND_ASSERT: - pptr += 1; - goto CHECK_GROUP; - - case META_COND_VERSION: - pptr += 4; - goto CHECK_GROUP; - - case META_CAPTURE: - group = META_DATA(*pptr); - /* Fall through */ - - case META_ATOMIC: - case META_NOCAPTURE: - case META_SCRIPT_RUN: - pptr++; - CHECK_GROUP: - grouplength = get_grouplength(&pptr, TRUE, errcodeptr, lcptr, group, - recurses, cb); - if (grouplength < 0) return -1; - itemlength = grouplength; - break; - - /* Exact repetition is OK; variable repetition is not. A repetition of zero - must subtract the length that has already been added. */ - - case META_MINMAX: - case META_MINMAX_PLUS: - case META_MINMAX_QUERY: - if (pptr[1] == pptr[2]) - { - switch(pptr[1]) - { - case 0: - branchlength -= lastitemlength; - break; - - case 1: - itemlength = 0; - break; - - default: /* Check for integer overflow */ - if (lastitemlength != 0 && /* Should not occur, but just in case */ - INT_MAX/lastitemlength < pptr[1] - 1) - { - *errcodeptr = ERR87; /* Integer overflow; lookbehind too big */ - return -1; - } - itemlength = (pptr[1] - 1) * lastitemlength; - break; - } - pptr += 2; - break; - } - /* Fall through */ - - /* Any other item means this branch does not have a fixed length. */ - - default: - ISNOTFIXED: - *errcodeptr = ERR25; /* Not fixed length */ - return -1; - } - - /* Add the item length to the branchlength, checking for integer overflow and - for the branch length exceeding the limit. */ - - if (INT_MAX - branchlength < (int)itemlength || - (branchlength += itemlength) > LOOKBEHIND_MAX) - { - *errcodeptr = ERR87; - return -1; - } - - /* Save this item length for use if the next item is a quantifier. */ - - lastitemlength = itemlength; - } - -EXIT: -*pptrptr = pptr; -return branchlength; - -PARSED_SKIP_FAILED: -*errcodeptr = ERR90; -return -1; -} - - - -/************************************************* -* Set lengths in a lookbehind * -*************************************************/ - -/* This function is called for each lookbehind, to set the lengths in its -branches. An error occurs if any branch does not have a fixed length that is -less than the maximum (65535). On exit, the pointer must be left on the final -ket. - -The function also maintains the max_lookbehind value. Any lookbehind branch -that contains a nested lookbehind may actually look further back than the -length of the branch. The additional amount is passed back from -get_branchlength() as an "extra" value. - -Arguments: - pptrptr pointer to pointer in the parsed pattern - errcodeptr pointer to error code - lcptr pointer to loop counter - recurses chain of recurse_check to catch mutual recursion - cb pointer to compile block - -Returns: TRUE if all is well - FALSE otherwise, with error code and offset set -*/ - -static BOOL -set_lookbehind_lengths(uint32_t **pptrptr, int *errcodeptr, int *lcptr, - parsed_recurse_check *recurses, compile_block *cb) -{ -PCRE2_SIZE offset; -int branchlength; -uint32_t *bptr = *pptrptr; - -READPLUSOFFSET(offset, bptr); /* Offset for error messages */ -*pptrptr += SIZEOFFSET; - -do - { - *pptrptr += 1; - branchlength = get_branchlength(pptrptr, errcodeptr, lcptr, recurses, cb); - if (branchlength < 0) - { - /* The errorcode and offset may already be set from a nested lookbehind. */ - if (*errcodeptr == 0) *errcodeptr = ERR25; - if (cb->erroroffset == PCRE2_UNSET) cb->erroroffset = offset; - return FALSE; - } - if (branchlength > cb->max_lookbehind) cb->max_lookbehind = branchlength; - *bptr |= branchlength; /* branchlength never more than 65535 */ - bptr = *pptrptr; - } -while (*bptr == META_ALT); - -return TRUE; -} - - - -/************************************************* -* Check parsed pattern lookbehinds * -*************************************************/ - -/* This function is called at the end of parsing a pattern if any lookbehinds -were encountered. It scans the parsed pattern for them, calling -set_lookbehind_lengths() for each one. At the start, the errorcode is zero and -the error offset is marked unset. The enables the functions above not to -override settings from deeper nestings. - -This function is called recursively from get_branchlength() for lookaheads in -order to process any lookbehinds that they may contain. It stops when it hits a -non-nested closing parenthesis in this case, returning a pointer to it. - -Arguments - pptr points to where to start (start of pattern or start of lookahead) - retptr if not NULL, return the ket pointer here - recurses chain of recurse_check to catch mutual recursion - cb points to the compile block - lcptr points to loop counter - -Returns: 0 on success, or an errorcode (cb->erroroffset will be set) -*/ - -static int -check_lookbehinds(uint32_t *pptr, uint32_t **retptr, - parsed_recurse_check *recurses, compile_block *cb, int *lcptr) -{ -int errorcode = 0; -int nestlevel = 0; - -cb->erroroffset = PCRE2_UNSET; - -for (; *pptr != META_END; pptr++) - { - if (*pptr < META_END) continue; /* Literal */ - - switch (META_CODE(*pptr)) - { - default: - return ERR70; /* Unrecognized meta code */ - - case META_ESCAPE: - if (*pptr - META_ESCAPE == ESC_P || *pptr - META_ESCAPE == ESC_p) - pptr += 1; - break; - - case META_KET: - if (--nestlevel < 0) - { - if (retptr != NULL) *retptr = pptr; - return 0; - } - break; - - case META_ATOMIC: - case META_CAPTURE: - case META_COND_ASSERT: - case META_LOOKAHEAD: - case META_LOOKAHEADNOT: - case META_LOOKAHEAD_NA: - case META_NOCAPTURE: - case META_SCRIPT_RUN: - nestlevel++; - break; - - case META_ACCEPT: - case META_ALT: - case META_ASTERISK: - case META_ASTERISK_PLUS: - case META_ASTERISK_QUERY: - case META_BACKREF: - case META_CIRCUMFLEX: - case META_CLASS: - case META_CLASS_EMPTY: - case META_CLASS_EMPTY_NOT: - case META_CLASS_END: - case META_CLASS_NOT: - case META_COMMIT: - case META_DOLLAR: - case META_DOT: - case META_FAIL: - case META_PLUS: - case META_PLUS_PLUS: - case META_PLUS_QUERY: - case META_PRUNE: - case META_QUERY: - case META_QUERY_PLUS: - case META_QUERY_QUERY: - case META_RANGE_ESCAPED: - case META_RANGE_LITERAL: - case META_SKIP: - case META_THEN: - break; - - case META_RECURSE: - pptr += SIZEOFFSET; - break; - - case META_BACKREF_BYNAME: - case META_RECURSE_BYNAME: - pptr += 1 + SIZEOFFSET; - break; - - case META_COND_DEFINE: - pptr += SIZEOFFSET; - nestlevel++; - break; - - case META_COND_NAME: - case META_COND_NUMBER: - case META_COND_RNAME: - case META_COND_RNUMBER: - pptr += 1 + SIZEOFFSET; - nestlevel++; - break; - - case META_COND_VERSION: - pptr += 3; - nestlevel++; - break; - - case META_CALLOUT_STRING: - pptr += 3 + SIZEOFFSET; - break; - - case META_BIGVALUE: - case META_OPTIONS: - case META_POSIX: - case META_POSIX_NEG: - pptr += 1; - break; - - case META_MINMAX: - case META_MINMAX_QUERY: - case META_MINMAX_PLUS: - pptr += 2; - break; - - case META_CALLOUT_NUMBER: - pptr += 3; - break; - - case META_MARK: - case META_COMMIT_ARG: - case META_PRUNE_ARG: - case META_SKIP_ARG: - case META_THEN_ARG: - pptr += 1 + pptr[1]; - break; - - case META_LOOKBEHIND: - case META_LOOKBEHINDNOT: - case META_LOOKBEHIND_NA: - if (!set_lookbehind_lengths(&pptr, &errorcode, lcptr, recurses, cb)) - return errorcode; - break; - } - } - -return 0; -} - - - -/************************************************* -* External function to compile a pattern * -*************************************************/ - -/* This function reads a regular expression in the form of a string and returns -a pointer to a block of store holding a compiled version of the expression. - -Arguments: - pattern the regular expression - patlen the length of the pattern, or PCRE2_ZERO_TERMINATED - options option bits - errorptr pointer to errorcode - erroroffset pointer to error offset - ccontext points to a compile context or is NULL - -Returns: pointer to compiled data block, or NULL on error, - with errorcode and erroroffset set -*/ - -PCRE2_EXP_DEFN pcre2_code * PCRE2_CALL_CONVENTION -pcre2_compile(PCRE2_SPTR pattern, PCRE2_SIZE patlen, uint32_t options, - int *errorptr, PCRE2_SIZE *erroroffset, pcre2_compile_context *ccontext) -{ -BOOL utf; /* Set TRUE for UTF mode */ -BOOL ucp; /* Set TRUE for UCP mode */ -BOOL has_lookbehind = FALSE; /* Set TRUE if a lookbehind is found */ -BOOL zero_terminated; /* Set TRUE for zero-terminated pattern */ -pcre2_real_code *re = NULL; /* What we will return */ -compile_block cb; /* "Static" compile-time data */ -const uint8_t *tables; /* Char tables base pointer */ - -PCRE2_UCHAR *code; /* Current pointer in compiled code */ -PCRE2_SPTR codestart; /* Start of compiled code */ -PCRE2_SPTR ptr; /* Current pointer in pattern */ -uint32_t *pptr; /* Current pointer in parsed pattern */ - -PCRE2_SIZE length = 1; /* Allow for final END opcode */ -PCRE2_SIZE usedlength; /* Actual length used */ -PCRE2_SIZE re_blocksize; /* Size of memory block */ -PCRE2_SIZE big32count = 0; /* 32-bit literals >= 0x80000000 */ -PCRE2_SIZE parsed_size_needed; /* Needed for parsed pattern */ - -uint32_t firstcuflags, reqcuflags; /* Type of first/req code unit */ -uint32_t firstcu, reqcu; /* Value of first/req code unit */ -uint32_t setflags = 0; /* NL and BSR set flags */ - -uint32_t skipatstart; /* When checking (*UTF) etc */ -uint32_t limit_heap = UINT32_MAX; -uint32_t limit_match = UINT32_MAX; /* Unset match limits */ -uint32_t limit_depth = UINT32_MAX; - -int newline = 0; /* Unset; can be set by the pattern */ -int bsr = 0; /* Unset; can be set by the pattern */ -int errorcode = 0; /* Initialize to avoid compiler warn */ -int regexrc; /* Return from compile */ - -uint32_t i; /* Local loop counter */ - -/* Comments at the head of this file explain about these variables. */ - -uint32_t stack_groupinfo[GROUPINFO_DEFAULT_SIZE]; -uint32_t stack_parsed_pattern[PARSED_PATTERN_DEFAULT_SIZE]; -named_group named_groups[NAMED_GROUP_LIST_SIZE]; - -/* The workspace is used in different ways in the different compiling phases. -It needs to be 16-bit aligned for the preliminary parsing scan. */ - -uint32_t c16workspace[C16_WORK_SIZE]; -PCRE2_UCHAR *cworkspace = (PCRE2_UCHAR *)c16workspace; - - -/* -------------- Check arguments and set up the pattern ----------------- */ - -/* There must be error code and offset pointers. */ - -if (errorptr == NULL || erroroffset == NULL) return NULL; -*errorptr = ERR0; -*erroroffset = 0; - -/* There must be a pattern! */ - -if (pattern == NULL) - { - *errorptr = ERR16; - return NULL; - } - -/* A NULL compile context means "use a default context" */ - -if (ccontext == NULL) - ccontext = (pcre2_compile_context *)(&PRIV(default_compile_context)); - -/* PCRE2_MATCH_INVALID_UTF implies UTF */ - -if ((options & PCRE2_MATCH_INVALID_UTF) != 0) options |= PCRE2_UTF; - -/* Check that all undefined public option bits are zero. */ - -if ((options & ~PUBLIC_COMPILE_OPTIONS) != 0 || - (ccontext->extra_options & ~PUBLIC_COMPILE_EXTRA_OPTIONS) != 0) - { - *errorptr = ERR17; - return NULL; - } - -if ((options & PCRE2_LITERAL) != 0 && - ((options & ~PUBLIC_LITERAL_COMPILE_OPTIONS) != 0 || - (ccontext->extra_options & ~PUBLIC_LITERAL_COMPILE_EXTRA_OPTIONS) != 0)) - { - *errorptr = ERR92; - return NULL; - } - -/* A zero-terminated pattern is indicated by the special length value -PCRE2_ZERO_TERMINATED. Check for an overlong pattern. */ - -if ((zero_terminated = (patlen == PCRE2_ZERO_TERMINATED))) - patlen = PRIV(strlen)(pattern); - -if (patlen > ccontext->max_pattern_length) - { - *errorptr = ERR88; - return NULL; - } - -/* From here on, all returns from this function should end up going via the -EXIT label. */ - - -/* ------------ Initialize the "static" compile data -------------- */ - -tables = (ccontext->tables != NULL)? ccontext->tables : PRIV(default_tables); - -cb.lcc = tables + lcc_offset; /* Individual */ -cb.fcc = tables + fcc_offset; /* character */ -cb.cbits = tables + cbits_offset; /* tables */ -cb.ctypes = tables + ctypes_offset; - -cb.assert_depth = 0; -cb.bracount = 0; -cb.cx = ccontext; -cb.dupnames = FALSE; -cb.end_pattern = pattern + patlen; -cb.erroroffset = 0; -cb.external_flags = 0; -cb.external_options = options; -cb.groupinfo = stack_groupinfo; -cb.had_recurse = FALSE; -cb.lastcapture = 0; -cb.max_lookbehind = 0; -cb.name_entry_size = 0; -cb.name_table = NULL; -cb.named_groups = named_groups; -cb.named_group_list_size = NAMED_GROUP_LIST_SIZE; -cb.names_found = 0; -cb.open_caps = NULL; -cb.parens_depth = 0; -cb.parsed_pattern = stack_parsed_pattern; -cb.req_varyopt = 0; -cb.start_code = cworkspace; -cb.start_pattern = pattern; -cb.start_workspace = cworkspace; -cb.workspace_size = COMPILE_WORK_SIZE; - -/* Maximum back reference and backref bitmap. The bitmap records up to 31 back -references to help in deciding whether (.*) can be treated as anchored or not. -*/ - -cb.top_backref = 0; -cb.backref_map = 0; - -/* Escape sequences \1 to \9 are always back references, but as they are only -two characters long, only two elements can be used in the parsed_pattern -vector. The first contains the reference, and we'd like to use the second to -record the offset in the pattern, so that forward references to non-existent -groups can be diagnosed later with an offset. However, on 64-bit systems, -PCRE2_SIZE won't fit. Instead, we have a vector of offsets for the first -occurrence of \1 to \9, indexed by the second parsed_pattern value. All other -references have enough space for the offset to be put into the parsed pattern. -*/ - -for (i = 0; i < 10; i++) cb.small_ref_offset[i] = PCRE2_UNSET; - - -/* --------------- Start looking at the pattern --------------- */ - -/* Unless PCRE2_LITERAL is set, check for global one-time option settings at -the start of the pattern, and remember the offset to the actual regex. With -valgrind support, make the terminator of a zero-terminated pattern -inaccessible. This catches bugs that would otherwise only show up for -non-zero-terminated patterns. */ - -#ifdef SUPPORT_VALGRIND -if (zero_terminated) VALGRIND_MAKE_MEM_NOACCESS(pattern + patlen, CU2BYTES(1)); -#endif - -ptr = pattern; -skipatstart = 0; - -if ((options & PCRE2_LITERAL) == 0) - { - while (patlen - skipatstart >= 2 && - ptr[skipatstart] == CHAR_LEFT_PARENTHESIS && - ptr[skipatstart+1] == CHAR_ASTERISK) - { - for (i = 0; i < sizeof(pso_list)/sizeof(pso); i++) - { - uint32_t c, pp; - pso *p = pso_list + i; - - if (patlen - skipatstart - 2 >= p->length && - PRIV(strncmp_c8)(ptr + skipatstart + 2, (char *)(p->name), - p->length) == 0) - { - skipatstart += p->length + 2; - switch(p->type) - { - case PSO_OPT: - cb.external_options |= p->value; - break; - - case PSO_FLG: - setflags |= p->value; - break; - - case PSO_NL: - newline = p->value; - setflags |= PCRE2_NL_SET; - break; - - case PSO_BSR: - bsr = p->value; - setflags |= PCRE2_BSR_SET; - break; - - case PSO_LIMM: - case PSO_LIMD: - case PSO_LIMH: - c = 0; - pp = skipatstart; - if (!IS_DIGIT(ptr[pp])) - { - errorcode = ERR60; - ptr += pp; - goto HAD_EARLY_ERROR; - } - while (IS_DIGIT(ptr[pp])) - { - if (c > UINT32_MAX / 10 - 1) break; /* Integer overflow */ - c = c*10 + (ptr[pp++] - CHAR_0); - } - if (ptr[pp++] != CHAR_RIGHT_PARENTHESIS) - { - errorcode = ERR60; - ptr += pp; - goto HAD_EARLY_ERROR; - } - if (p->type == PSO_LIMH) limit_heap = c; - else if (p->type == PSO_LIMM) limit_match = c; - else limit_depth = c; - skipatstart += pp - skipatstart; - break; - } - break; /* Out of the table scan loop */ - } - } - if (i >= sizeof(pso_list)/sizeof(pso)) break; /* Out of pso loop */ - } - } - -/* End of pattern-start options; advance to start of real regex. */ - -ptr += skipatstart; - -/* Can't support UTF or UCP if PCRE2 was built without Unicode support. */ - -#ifndef SUPPORT_UNICODE -if ((cb.external_options & (PCRE2_UTF|PCRE2_UCP)) != 0) - { - errorcode = ERR32; - goto HAD_EARLY_ERROR; - } -#endif - -/* Check UTF. We have the original options in 'options', with that value as -modified by (*UTF) etc in cb->external_options. The extra option -PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES is not permitted in UTF-16 mode because the -surrogate code points cannot be represented in UTF-16. */ - -utf = (cb.external_options & PCRE2_UTF) != 0; -if (utf) - { - if ((options & PCRE2_NEVER_UTF) != 0) - { - errorcode = ERR74; - goto HAD_EARLY_ERROR; - } - if ((options & PCRE2_NO_UTF_CHECK) == 0 && - (errorcode = PRIV(valid_utf)(pattern, patlen, erroroffset)) != 0) - goto HAD_ERROR; /* Offset was set by valid_utf() */ - -#if PCRE2_CODE_UNIT_WIDTH == 16 - if ((ccontext->extra_options & PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES) != 0) - { - errorcode = ERR91; - goto HAD_EARLY_ERROR; - } -#endif - } - -/* Check UCP lockout. */ - -ucp = (cb.external_options & PCRE2_UCP) != 0; -if (ucp && (cb.external_options & PCRE2_NEVER_UCP) != 0) - { - errorcode = ERR75; - goto HAD_EARLY_ERROR; - } - -/* Process the BSR setting. */ - -if (bsr == 0) bsr = ccontext->bsr_convention; - -/* Process the newline setting. */ - -if (newline == 0) newline = ccontext->newline_convention; -cb.nltype = NLTYPE_FIXED; -switch(newline) - { - case PCRE2_NEWLINE_CR: - cb.nllen = 1; - cb.nl[0] = CHAR_CR; - break; - - case PCRE2_NEWLINE_LF: - cb.nllen = 1; - cb.nl[0] = CHAR_NL; - break; - - case PCRE2_NEWLINE_NUL: - cb.nllen = 1; - cb.nl[0] = CHAR_NUL; - break; - - case PCRE2_NEWLINE_CRLF: - cb.nllen = 2; - cb.nl[0] = CHAR_CR; - cb.nl[1] = CHAR_NL; - break; - - case PCRE2_NEWLINE_ANY: - cb.nltype = NLTYPE_ANY; - break; - - case PCRE2_NEWLINE_ANYCRLF: - cb.nltype = NLTYPE_ANYCRLF; - break; - - default: - errorcode = ERR56; - goto HAD_EARLY_ERROR; - } - -/* Pre-scan the pattern to do two things: (1) Discover the named groups and -their numerical equivalents, so that this information is always available for -the remaining processing. (2) At the same time, parse the pattern and put a -processed version into the parsed_pattern vector. This has escapes interpreted -and comments removed (amongst other things). - -In all but one case, when PCRE2_AUTO_CALLOUT is not set, the number of unsigned -32-bit ints in the parsed pattern is bounded by the length of the pattern plus -one (for the terminator) plus four if PCRE2_EXTRA_WORD or PCRE2_EXTRA_LINE is -set. The exceptional case is when running in 32-bit, non-UTF mode, when literal -characters greater than META_END (0x80000000) have to be coded as two units. In -this case, therefore, we scan the pattern to check for such values. */ - -#if PCRE2_CODE_UNIT_WIDTH == 32 -if (!utf) - { - PCRE2_SPTR p; - for (p = ptr; p < cb.end_pattern; p++) if (*p >= META_END) big32count++; - } -#endif - -/* Ensure that the parsed pattern buffer is big enough. When PCRE2_AUTO_CALLOUT -is set we have to assume a numerical callout (4 elements) for each character -plus one at the end. This is overkill, but memory is plentiful these days. For -many smaller patterns the vector on the stack (which was set up above) can be -used. */ - -parsed_size_needed = patlen - skipatstart + big32count; - -if ((ccontext->extra_options & - (PCRE2_EXTRA_MATCH_WORD|PCRE2_EXTRA_MATCH_LINE)) != 0) - parsed_size_needed += 4; - -if ((options & PCRE2_AUTO_CALLOUT) != 0) - parsed_size_needed = (parsed_size_needed + 1) * 5; - -if (parsed_size_needed >= PARSED_PATTERN_DEFAULT_SIZE) - { - uint32_t *heap_parsed_pattern = ccontext->memctl.malloc( - (parsed_size_needed + 1) * sizeof(uint32_t), ccontext->memctl.memory_data); - if (heap_parsed_pattern == NULL) - { - *errorptr = ERR21; - goto EXIT; - } - cb.parsed_pattern = heap_parsed_pattern; - } -cb.parsed_pattern_end = cb.parsed_pattern + parsed_size_needed + 1; - -/* Do the parsing scan. */ - -errorcode = parse_regex(ptr, cb.external_options, &has_lookbehind, &cb); -if (errorcode != 0) goto HAD_CB_ERROR; - -/* Workspace is needed to remember information about numbered groups: whether a -group can match an empty string and what its fixed length is. This is done to -avoid the possibility of recursive references causing very long compile times -when checking these features. Unnumbered groups do not have this exposure since -they cannot be referenced. We use an indexed vector for this purpose. If there -are sufficiently few groups, the default vector on the stack, as set up above, -can be used. Otherwise we have to get/free a special vector. The vector must be -initialized to zero. */ - -if (cb.bracount >= GROUPINFO_DEFAULT_SIZE) - { - cb.groupinfo = ccontext->memctl.malloc( - (cb.bracount + 1)*sizeof(uint32_t), ccontext->memctl.memory_data); - if (cb.groupinfo == NULL) - { - errorcode = ERR21; - cb.erroroffset = 0; - goto HAD_CB_ERROR; - } - } -memset(cb.groupinfo, 0, (cb.bracount + 1) * sizeof(uint32_t)); - -/* If there were any lookbehinds, scan the parsed pattern to figure out their -lengths. */ - -if (has_lookbehind) - { - int loopcount = 0; - errorcode = check_lookbehinds(cb.parsed_pattern, NULL, NULL, &cb, &loopcount); - if (errorcode != 0) goto HAD_CB_ERROR; - } - -/* For debugging, there is a function that shows the parsed data vector. */ - -#ifdef DEBUG_SHOW_PARSED -fprintf(stderr, "+++ Pre-scan complete:\n"); -show_parsed(&cb); -#endif - -/* For debugging capturing information this code can be enabled. */ - -#ifdef DEBUG_SHOW_CAPTURES - { - named_group *ng = cb.named_groups; - fprintf(stderr, "+++Captures: %d\n", cb.bracount); - for (i = 0; i < cb.names_found; i++, ng++) - { - fprintf(stderr, "+++%3d %.*s\n", ng->number, ng->length, ng->name); - } - } -#endif - -/* Pretend to compile the pattern while actually just accumulating the amount -of memory required in the 'length' variable. This behaviour is triggered by -passing a non-NULL final argument to compile_regex(). We pass a block of -workspace (cworkspace) for it to compile parts of the pattern into; the -compiled code is discarded when it is no longer needed, so hopefully this -workspace will never overflow, though there is a test for its doing so. - -On error, errorcode will be set non-zero, so we don't need to look at the -result of the function. The initial options have been put into the cb block, -but we still have to pass a separate options variable (the first argument) -because the options may change as the pattern is processed. */ - -cb.erroroffset = patlen; /* For any subsequent errors that do not set it */ -pptr = cb.parsed_pattern; -code = cworkspace; -*code = OP_BRA; - -(void)compile_regex(cb.external_options, &code, &pptr, &errorcode, 0, &firstcu, - &firstcuflags, &reqcu, &reqcuflags, NULL, &cb, &length); - -if (errorcode != 0) goto HAD_CB_ERROR; /* Offset is in cb.erroroffset */ - -/* This should be caught in compile_regex(), but just in case... */ - -if (length > MAX_PATTERN_SIZE) - { - errorcode = ERR20; - 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. */ - -re_blocksize = sizeof(pcre2_real_code) + - CU2BYTES(length + - (PCRE2_SIZE)cb.names_found * (PCRE2_SIZE)cb.name_entry_size); -re = (pcre2_real_code *) - ccontext->memctl.malloc(re_blocksize, ccontext->memctl.memory_data); -if (re == NULL) - { - errorcode = ERR21; - goto HAD_CB_ERROR; - } - -/* The compiler may put padding at the end of the pcre2_real_code structure in -order to round it up to a multiple of 4 or 8 bytes. This means that when a -compiled pattern is copied (for example, when serialized) undefined bytes are -read, and this annoys debuggers such as valgrind. To avoid this, we explicitly -write to the last 8 bytes of the structure before setting the fields. */ - -memset((char *)re + sizeof(pcre2_real_code) - 8, 0, 8); -re->memctl = ccontext->memctl; -re->tables = tables; -re->executable_jit = NULL; -memset(re->start_bitmap, 0, 32 * sizeof(uint8_t)); -re->blocksize = re_blocksize; -re->magic_number = MAGIC_NUMBER; -re->compile_options = options; -re->overall_options = cb.external_options; -re->extra_options = ccontext->extra_options; -re->flags = PCRE2_CODE_UNIT_WIDTH/8 | cb.external_flags | setflags; -re->limit_heap = limit_heap; -re->limit_match = limit_match; -re->limit_depth = limit_depth; -re->first_codeunit = 0; -re->last_codeunit = 0; -re->bsr_convention = bsr; -re->newline_convention = newline; -re->max_lookbehind = 0; -re->minlength = 0; -re->top_bracket = 0; -re->top_backref = 0; -re->name_entry_size = cb.name_entry_size; -re->name_count = cb.names_found; - -/* The basic block is immediately followed by the name table, and the compiled -code follows after that. */ - -codestart = (PCRE2_SPTR)((uint8_t *)re + sizeof(pcre2_real_code)) + - re->name_entry_size * re->name_count; - -/* Update the compile data block for the actual compile. The starting points of -the name/number translation table and of the code are passed around in the -compile data block. The start/end pattern and initial options are already set -from the pre-compile phase, as is the name_entry_size field. */ - -cb.parens_depth = 0; -cb.assert_depth = 0; -cb.lastcapture = 0; -cb.name_table = (PCRE2_UCHAR *)((uint8_t *)re + sizeof(pcre2_real_code)); -cb.start_code = codestart; -cb.req_varyopt = 0; -cb.had_accept = FALSE; -cb.had_pruneorskip = FALSE; -cb.open_caps = NULL; - -/* If any named groups were found, create the name/number table from the list -created in the pre-pass. */ - -if (cb.names_found > 0) - { - named_group *ng = cb.named_groups; - for (i = 0; i < cb.names_found; i++, ng++) - add_name_to_table(&cb, ng->name, ng->length, ng->number, i); - } - -/* Set up a starting, non-extracting bracket, then compile the expression. On -error, errorcode will be set non-zero, so we don't need to look at the result -of the function here. */ - -pptr = cb.parsed_pattern; -code = (PCRE2_UCHAR *)codestart; -*code = OP_BRA; -regexrc = compile_regex(re->overall_options, &code, &pptr, &errorcode, 0, - &firstcu, &firstcuflags, &reqcu, &reqcuflags, NULL, &cb, NULL); -if (regexrc < 0) re->flags |= PCRE2_MATCH_EMPTY; -re->top_bracket = cb.bracount; -re->top_backref = cb.top_backref; -re->max_lookbehind = cb.max_lookbehind; - -if (cb.had_accept) - { - reqcu = 0; /* Must disable after (*ACCEPT) */ - reqcuflags = REQ_NONE; - re->flags |= PCRE2_HASACCEPT; /* Disables minimum length */ - } - -/* Fill in the final opcode and check for disastrous overflow. If no overflow, -but the estimated length exceeds the really used length, adjust the value of -re->blocksize, and if valgrind support is configured, mark the extra allocated -memory as unaddressable, so that any out-of-bound reads can be detected. */ - -*code++ = OP_END; -usedlength = code - codestart; -if (usedlength > length) errorcode = ERR23; else - { - re->blocksize -= CU2BYTES(length - usedlength); -#ifdef SUPPORT_VALGRIND - VALGRIND_MAKE_MEM_NOACCESS(code, CU2BYTES(length - usedlength)); -#endif - } - -/* Scan the pattern for recursion/subroutine calls and convert the group -numbers into offsets. Maintain a small cache so that repeated groups containing -recursions are efficiently handled. */ - -#define RSCAN_CACHE_SIZE 8 - -if (errorcode == 0 && cb.had_recurse) - { - PCRE2_UCHAR *rcode; - PCRE2_SPTR rgroup; - unsigned int ccount = 0; - int start = RSCAN_CACHE_SIZE; - recurse_cache rc[RSCAN_CACHE_SIZE]; - - for (rcode = (PCRE2_UCHAR *)find_recurse(codestart, utf); - rcode != NULL; - rcode = (PCRE2_UCHAR *)find_recurse(rcode + 1 + LINK_SIZE, utf)) - { - int p, groupnumber; - - groupnumber = (int)GET(rcode, 1); - if (groupnumber == 0) rgroup = codestart; else - { - PCRE2_SPTR search_from = codestart; - rgroup = NULL; - for (i = 0, p = start; i < ccount; i++, p = (p + 1) & 7) - { - if (groupnumber == rc[p].groupnumber) - { - rgroup = rc[p].group; - break; - } - - /* Group n+1 must always start to the right of group n, so we can save - search time below when the new group number is greater than any of the - previously found groups. */ - - if (groupnumber > rc[p].groupnumber) search_from = rc[p].group; - } - - if (rgroup == NULL) - { - rgroup = PRIV(find_bracket)(search_from, utf, groupnumber); - if (rgroup == NULL) - { - errorcode = ERR53; - break; - } - if (--start < 0) start = RSCAN_CACHE_SIZE - 1; - rc[start].groupnumber = groupnumber; - rc[start].group = rgroup; - if (ccount < RSCAN_CACHE_SIZE) ccount++; - } - } - - PUT(rcode, 1, rgroup - codestart); - } - } - -/* In rare debugging situations we sometimes need to look at the compiled code -at this stage. */ - -#ifdef DEBUG_CALL_PRINTINT -pcre2_printint(re, stderr, TRUE); -fprintf(stderr, "Length=%lu Used=%lu\n", length, usedlength); -#endif - -/* Unless disabled, check whether any single character iterators can be -auto-possessified. The function overwrites the appropriate opcode values, so -the type of the pointer must be cast. NOTE: the intermediate variable "temp" is -used in this code because at least one compiler gives a warning about loss of -"const" attribute if the cast (PCRE2_UCHAR *)codestart is used directly in the -function call. */ - -if (errorcode == 0 && (re->overall_options & PCRE2_NO_AUTO_POSSESS) == 0) - { - PCRE2_UCHAR *temp = (PCRE2_UCHAR *)codestart; - if (PRIV(auto_possessify)(temp, &cb) != 0) errorcode = ERR80; - } - -/* Failed to compile, or error while post-processing. */ - -if (errorcode != 0) goto HAD_CB_ERROR; - -/* Successful compile. If the anchored option was not passed, set it if -we can determine that the pattern is anchored by virtue of ^ characters or \A -or anything else, such as starting with non-atomic .* when DOTALL is set and -there are no occurrences of *PRUNE or *SKIP (though there is an option to -disable this case). */ - -if ((re->overall_options & PCRE2_ANCHORED) == 0 && - is_anchored(codestart, 0, &cb, 0, FALSE)) - re->overall_options |= PCRE2_ANCHORED; - -/* Set up the first code unit or startline flag, the required code unit, and -then study the pattern. This code need not be obeyed if PCRE2_NO_START_OPTIMIZE -is set, as the data it would create will not be used. Note that a first code -unit (but not the startline flag) is useful for anchored patterns because it -can still give a quick "no match" and also avoid searching for a last code -unit. */ - -if ((re->overall_options & PCRE2_NO_START_OPTIMIZE) == 0) - { - int minminlength = 0; /* For minimal minlength from first/required CU */ - - /* If we do not have a first code unit, see if there is one that is asserted - (these are not saved during the compile because they can cause conflicts with - actual literals that follow). */ - - if (firstcuflags >= REQ_NONE) - firstcu = find_firstassertedcu(codestart, &firstcuflags, 0); - - /* Save the data for a first code unit. The existence of one means the - minimum length must be at least 1. */ - - if (firstcuflags < REQ_NONE) - { - re->first_codeunit = firstcu; - re->flags |= PCRE2_FIRSTSET; - minminlength++; - - /* Handle caseless first code units. */ - - if ((firstcuflags & REQ_CASELESS) != 0) - { - if (firstcu < 128 || (!utf && !ucp && firstcu < 255)) - { - if (cb.fcc[firstcu] != firstcu) re->flags |= PCRE2_FIRSTCASELESS; - } - - /* The first code unit is > 128 in UTF or UCP mode, or > 255 otherwise. - In 8-bit UTF mode, codepoints in the range 128-255 are introductory code - points and cannot have another case, but if UCP is set they may do. */ - -#ifdef SUPPORT_UNICODE -#if PCRE2_CODE_UNIT_WIDTH == 8 - else if (ucp && !utf && UCD_OTHERCASE(firstcu) != firstcu) - re->flags |= PCRE2_FIRSTCASELESS; -#else - else if ((utf || ucp) && firstcu <= MAX_UTF_CODE_POINT && - UCD_OTHERCASE(firstcu) != firstcu) - re->flags |= PCRE2_FIRSTCASELESS; -#endif -#endif /* SUPPORT_UNICODE */ - } - } - - /* When there is no first code unit, for non-anchored patterns, see if we can - set the PCRE2_STARTLINE flag. This is helpful for multiline matches when all - branches start with ^ and also when all branches start with non-atomic .* for - non-DOTALL matches when *PRUNE and SKIP are not present. (There is an option - that disables this case.) */ - - else if ((re->overall_options & PCRE2_ANCHORED) == 0 && - is_startline(codestart, 0, &cb, 0, FALSE)) - re->flags |= PCRE2_STARTLINE; - - /* Handle the "required code unit", if one is set. In the UTF case we can - increment the minimum minimum length only if we are sure this really is a - different character and not a non-starting code unit of the first character, - because the minimum length count is in characters, not code units. */ - - if (reqcuflags < REQ_NONE) - { -#if PCRE2_CODE_UNIT_WIDTH == 16 - if ((re->overall_options & PCRE2_UTF) == 0 || /* Not UTF */ - firstcuflags >= REQ_NONE || /* First not set */ - (firstcu & 0xf800) != 0xd800 || /* First not surrogate */ - (reqcu & 0xfc00) != 0xdc00) /* Req not low surrogate */ -#elif PCRE2_CODE_UNIT_WIDTH == 8 - if ((re->overall_options & PCRE2_UTF) == 0 || /* Not UTF */ - firstcuflags >= REQ_NONE || /* First not set */ - (firstcu & 0x80) == 0 || /* First is ASCII */ - (reqcu & 0x80) == 0) /* Req is ASCII */ -#endif - { - minminlength++; - } - - /* In the case of an anchored pattern, set up the value only if it follows - a variable length item in the pattern. */ - - if ((re->overall_options & PCRE2_ANCHORED) == 0 || - (reqcuflags & REQ_VARY) != 0) - { - re->last_codeunit = reqcu; - re->flags |= PCRE2_LASTSET; - - /* Handle caseless required code units as for first code units (above). */ - - if ((reqcuflags & REQ_CASELESS) != 0) - { - if (reqcu < 128 || (!utf && !ucp && reqcu < 255)) - { - if (cb.fcc[reqcu] != reqcu) re->flags |= PCRE2_LASTCASELESS; - } -#ifdef SUPPORT_UNICODE -#if PCRE2_CODE_UNIT_WIDTH == 8 - else if (ucp && !utf && UCD_OTHERCASE(reqcu) != reqcu) - re->flags |= PCRE2_LASTCASELESS; -#else - else if ((utf || ucp) && reqcu <= MAX_UTF_CODE_POINT && - UCD_OTHERCASE(reqcu) != reqcu) - re->flags |= PCRE2_LASTCASELESS; -#endif -#endif /* SUPPORT_UNICODE */ - } - } - } - - /* Study the compiled pattern to set up information such as a bitmap of - starting code units and a minimum matching length. */ - - if (PRIV(study)(re) != 0) - { - errorcode = ERR31; - goto HAD_CB_ERROR; - } - - /* If study() set a bitmap of starting code units, it implies a minimum - length of at least one. */ - - if ((re->flags & PCRE2_FIRSTMAPSET) != 0 && minminlength == 0) - minminlength = 1; - - /* If the minimum length set (or not set) by study() is less than the minimum - implied by required code units, override it. */ - - if (re->minlength < minminlength) re->minlength = minminlength; - } /* End of start-of-match optimizations. */ - -/* Control ends up here in all cases. When running under valgrind, make a -pattern's terminating zero defined again. If memory was obtained for the parsed -version of the pattern, free it before returning. Also free the list of named -groups if a larger one had to be obtained, and likewise the group information -vector. */ - -EXIT: -#ifdef SUPPORT_VALGRIND -if (zero_terminated) VALGRIND_MAKE_MEM_DEFINED(pattern + patlen, CU2BYTES(1)); -#endif -if (cb.parsed_pattern != stack_parsed_pattern) - ccontext->memctl.free(cb.parsed_pattern, ccontext->memctl.memory_data); -if (cb.named_group_list_size > NAMED_GROUP_LIST_SIZE) - ccontext->memctl.free((void *)cb.named_groups, ccontext->memctl.memory_data); -if (cb.groupinfo != stack_groupinfo) - ccontext->memctl.free((void *)cb.groupinfo, ccontext->memctl.memory_data); -return re; /* Will be NULL after an error */ - -/* Errors discovered in parse_regex() set the offset value in the compile -block. Errors discovered before it is called must compute it from the ptr -value. After parse_regex() is called, the offset in the compile block is set to -the end of the pattern, but certain errors in compile_regex() may reset it if -an offset is available in the parsed pattern. */ - -HAD_CB_ERROR: -ptr = pattern + cb.erroroffset; - -HAD_EARLY_ERROR: -*erroroffset = ptr - pattern; - -HAD_ERROR: -*errorptr = errorcode; -pcre2_code_free(re); -re = NULL; -goto EXIT; -} - -/* These #undefs are here to enable unity builds with CMake. */ - -#undef NLBLOCK /* Block containing newline information */ -#undef PSSTART /* Field containing processed string start */ -#undef PSEND /* Field containing processed string end */ - -/* End of pcre2_compile.c */ diff --git a/modules/regex/pcre2/src/pcre2_config.c b/modules/regex/pcre2/src/pcre2_config.c deleted file mode 100644 index 5ef103c..0000000 --- a/modules/regex/pcre2/src/pcre2_config.c +++ /dev/null @@ -1,252 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -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-2020 University of Cambridge - ------------------------------------------------------------------------------ -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 OWNER 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. ------------------------------------------------------------------------------ -*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -/* Save the configured link size, which is in bytes. In 16-bit and 32-bit modes -its value gets changed by pcre2_intmodedep.h (included by pcre2_internal.h) to -be in code units. */ - -static int configured_link_size = LINK_SIZE; - -#include "pcre2_internal.h" - -/* These macros are the standard way of turning unquoted text into C strings. -They allow macros like PCRE2_MAJOR to be defined without quotes, which is -convenient for user programs that want to test their values. */ - -#define STRING(a) # a -#define XSTRING(s) STRING(s) - - -/************************************************* -* Return info about what features are configured * -*************************************************/ - -/* If where is NULL, the length of memory required is returned. - -Arguments: - what what information is required - where where to put the information - -Returns: 0 if a numerical value is returned - >= 0 if a string value - PCRE2_ERROR_BADOPTION if "where" not recognized - or JIT target requested when JIT not enabled -*/ - -PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION -pcre2_config(uint32_t what, void *where) -{ -if (where == NULL) /* Requests a length */ - { - switch(what) - { - default: - return PCRE2_ERROR_BADOPTION; - - case PCRE2_CONFIG_BSR: - case PCRE2_CONFIG_COMPILED_WIDTHS: - case PCRE2_CONFIG_DEPTHLIMIT: - case PCRE2_CONFIG_HEAPLIMIT: - case PCRE2_CONFIG_JIT: - case PCRE2_CONFIG_LINKSIZE: - case PCRE2_CONFIG_MATCHLIMIT: - case PCRE2_CONFIG_NEVER_BACKSLASH_C: - case PCRE2_CONFIG_NEWLINE: - case PCRE2_CONFIG_PARENSLIMIT: - case PCRE2_CONFIG_STACKRECURSE: /* Obsolete */ - case PCRE2_CONFIG_TABLES_LENGTH: - case PCRE2_CONFIG_UNICODE: - return sizeof(uint32_t); - - /* These are handled below */ - - case PCRE2_CONFIG_JITTARGET: - case PCRE2_CONFIG_UNICODE_VERSION: - case PCRE2_CONFIG_VERSION: - break; - } - } - -switch (what) - { - default: - return PCRE2_ERROR_BADOPTION; - - case PCRE2_CONFIG_BSR: -#ifdef BSR_ANYCRLF - *((uint32_t *)where) = PCRE2_BSR_ANYCRLF; -#else - *((uint32_t *)where) = PCRE2_BSR_UNICODE; -#endif - break; - - case PCRE2_CONFIG_COMPILED_WIDTHS: - *((uint32_t *)where) = 0 -#ifdef SUPPORT_PCRE2_8 - + 1 -#endif -#ifdef SUPPORT_PCRE2_16 - + 2 -#endif -#ifdef SUPPORT_PCRE2_32 - + 4 -#endif - ; - break; - - case PCRE2_CONFIG_DEPTHLIMIT: - *((uint32_t *)where) = MATCH_LIMIT_DEPTH; - break; - - case PCRE2_CONFIG_HEAPLIMIT: - *((uint32_t *)where) = HEAP_LIMIT; - break; - - case PCRE2_CONFIG_JIT: -#ifdef SUPPORT_JIT - *((uint32_t *)where) = 1; -#else - *((uint32_t *)where) = 0; -#endif - break; - - case PCRE2_CONFIG_JITTARGET: -#ifdef SUPPORT_JIT - { - const char *v = PRIV(jit_get_target)(); - return (int)(1 + ((where == NULL)? - strlen(v) : PRIV(strcpy_c8)((PCRE2_UCHAR *)where, v))); - } -#else - return PCRE2_ERROR_BADOPTION; -#endif - - case PCRE2_CONFIG_LINKSIZE: - *((uint32_t *)where) = (uint32_t)configured_link_size; - break; - - case PCRE2_CONFIG_MATCHLIMIT: - *((uint32_t *)where) = MATCH_LIMIT; - break; - - case PCRE2_CONFIG_NEWLINE: - *((uint32_t *)where) = NEWLINE_DEFAULT; - break; - - case PCRE2_CONFIG_NEVER_BACKSLASH_C: -#ifdef NEVER_BACKSLASH_C - *((uint32_t *)where) = 1; -#else - *((uint32_t *)where) = 0; -#endif - break; - - case PCRE2_CONFIG_PARENSLIMIT: - *((uint32_t *)where) = PARENS_NEST_LIMIT; - break; - - /* This is now obsolete. The stack is no longer used via recursion for - handling backtracking in pcre2_match(). */ - - case PCRE2_CONFIG_STACKRECURSE: - *((uint32_t *)where) = 0; - break; - - case PCRE2_CONFIG_TABLES_LENGTH: - *((uint32_t *)where) = TABLES_LENGTH; - break; - - case PCRE2_CONFIG_UNICODE_VERSION: - { -#if defined SUPPORT_UNICODE - const char *v = PRIV(unicode_version); -#else - const char *v = "Unicode not supported"; -#endif - return (int)(1 + ((where == NULL)? - strlen(v) : PRIV(strcpy_c8)((PCRE2_UCHAR *)where, v))); - } - break; - - case PCRE2_CONFIG_UNICODE: -#if defined SUPPORT_UNICODE - *((uint32_t *)where) = 1; -#else - *((uint32_t *)where) = 0; -#endif - break; - - /* The hackery in setting "v" below is to cope with the case when - PCRE2_PRERELEASE is set to an empty string (which it is for real releases). - If the second alternative is used in this case, it does not leave a space - before the date. On the other hand, if all four macros are put into a single - XSTRING when PCRE2_PRERELEASE is not empty, an unwanted space is inserted. - There are problems using an "obvious" approach like this: - - XSTRING(PCRE2_MAJOR) "." XSTRING(PCRE_MINOR) - XSTRING(PCRE2_PRERELEASE) " " XSTRING(PCRE_DATE) - - because, when PCRE2_PRERELEASE is empty, this leads to an attempted expansion - of STRING(). The C standard states: "If (before argument substitution) any - argument consists of no preprocessing tokens, the behavior is undefined." It - turns out the gcc treats this case as a single empty string - which is what - we really want - but Visual C grumbles about the lack of an argument for the - macro. Unfortunately, both are within their rights. As there seems to be no - way to test for a macro's value being empty at compile time, we have to - resort to a runtime test. */ - - case PCRE2_CONFIG_VERSION: - { - const char *v = (XSTRING(Z PCRE2_PRERELEASE)[1] == 0)? - XSTRING(PCRE2_MAJOR.PCRE2_MINOR PCRE2_DATE) : - XSTRING(PCRE2_MAJOR.PCRE2_MINOR) XSTRING(PCRE2_PRERELEASE PCRE2_DATE); - return (int)(1 + ((where == NULL)? - strlen(v) : PRIV(strcpy_c8)((PCRE2_UCHAR *)where, v))); - } - } - -return 0; -} - -/* End of pcre2_config.c */ diff --git a/modules/regex/pcre2/src/pcre2_context.c b/modules/regex/pcre2/src/pcre2_context.c deleted file mode 100644 index 8e05ede..0000000 --- a/modules/regex/pcre2/src/pcre2_context.c +++ /dev/null @@ -1,494 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -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-2022 University of Cambridge - ------------------------------------------------------------------------------ -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 OWNER 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. ------------------------------------------------------------------------------ -*/ - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "pcre2_internal.h" - - - -/************************************************* -* Default malloc/free functions * -*************************************************/ - -/* Ignore the "user data" argument in each case. */ - -static void *default_malloc(size_t size, void *data) -{ -(void)data; -return malloc(size); -} - - -static void default_free(void *block, void *data) -{ -(void)data; -free(block); -} - - - -/************************************************* -* Get a block and save memory control * -*************************************************/ - -/* This internal function is called to get a block of memory in which the -memory control data is to be stored at the start for future use. - -Arguments: - size amount of memory required - memctl pointer to a memctl block or NULL - -Returns: pointer to memory or NULL on failure -*/ - -extern void * -PRIV(memctl_malloc)(size_t size, pcre2_memctl *memctl) -{ -pcre2_memctl *newmemctl; -void *yield = (memctl == NULL)? malloc(size) : - memctl->malloc(size, memctl->memory_data); -if (yield == NULL) return NULL; -newmemctl = (pcre2_memctl *)yield; -if (memctl == NULL) - { - newmemctl->malloc = default_malloc; - newmemctl->free = default_free; - newmemctl->memory_data = NULL; - } -else *newmemctl = *memctl; -return yield; -} - - - -/************************************************* -* Create and initialize contexts * -*************************************************/ - -/* Initializing for compile and match contexts is done in separate, private -functions so that these can be called from functions such as pcre2_compile() -when an external context is not supplied. The initializing functions have an -option to set up default memory management. */ - -PCRE2_EXP_DEFN pcre2_general_context * PCRE2_CALL_CONVENTION -pcre2_general_context_create(void *(*private_malloc)(size_t, void *), - void (*private_free)(void *, void *), void *memory_data) -{ -pcre2_general_context *gcontext; -if (private_malloc == NULL) private_malloc = default_malloc; -if (private_free == NULL) private_free = default_free; -gcontext = private_malloc(sizeof(pcre2_real_general_context), memory_data); -if (gcontext == NULL) return NULL; -gcontext->memctl.malloc = private_malloc; -gcontext->memctl.free = private_free; -gcontext->memctl.memory_data = memory_data; -return gcontext; -} - - -/* A default compile context is set up to save having to initialize at run time -when no context is supplied to the compile function. */ - -const pcre2_compile_context PRIV(default_compile_context) = { - { default_malloc, default_free, NULL }, /* Default memory handling */ - NULL, /* Stack guard */ - NULL, /* Stack guard data */ - PRIV(default_tables), /* Character tables */ - PCRE2_UNSET, /* Max pattern length */ - BSR_DEFAULT, /* Backslash R default */ - NEWLINE_DEFAULT, /* Newline convention */ - PARENS_NEST_LIMIT, /* As it says */ - 0 }; /* Extra options */ - -/* The create function copies the default into the new memory, but must -override the default memory handling functions if a gcontext was provided. */ - -PCRE2_EXP_DEFN pcre2_compile_context * PCRE2_CALL_CONVENTION -pcre2_compile_context_create(pcre2_general_context *gcontext) -{ -pcre2_compile_context *ccontext = PRIV(memctl_malloc)( - sizeof(pcre2_real_compile_context), (pcre2_memctl *)gcontext); -if (ccontext == NULL) return NULL; -*ccontext = PRIV(default_compile_context); -if (gcontext != NULL) - *((pcre2_memctl *)ccontext) = *((pcre2_memctl *)gcontext); -return ccontext; -} - - -/* A default match context is set up to save having to initialize at run time -when no context is supplied to a match function. */ - -const pcre2_match_context PRIV(default_match_context) = { - { default_malloc, default_free, NULL }, -#ifdef SUPPORT_JIT - NULL, /* JIT callback */ - NULL, /* JIT callback data */ -#endif - NULL, /* Callout function */ - NULL, /* Callout data */ - NULL, /* Substitute callout function */ - NULL, /* Substitute callout data */ - PCRE2_UNSET, /* Offset limit */ - HEAP_LIMIT, - MATCH_LIMIT, - MATCH_LIMIT_DEPTH }; - -/* The create function copies the default into the new memory, but must -override the default memory handling functions if a gcontext was provided. */ - -PCRE2_EXP_DEFN pcre2_match_context * PCRE2_CALL_CONVENTION -pcre2_match_context_create(pcre2_general_context *gcontext) -{ -pcre2_match_context *mcontext = PRIV(memctl_malloc)( - sizeof(pcre2_real_match_context), (pcre2_memctl *)gcontext); -if (mcontext == NULL) return NULL; -*mcontext = PRIV(default_match_context); -if (gcontext != NULL) - *((pcre2_memctl *)mcontext) = *((pcre2_memctl *)gcontext); -return mcontext; -} - - -/* A default convert context is set up to save having to initialize at run time -when no context is supplied to the convert function. */ - -const pcre2_convert_context PRIV(default_convert_context) = { - { default_malloc, default_free, NULL }, /* Default memory handling */ -#ifdef _WIN32 - CHAR_BACKSLASH, /* Default path separator */ - CHAR_GRAVE_ACCENT /* Default escape character */ -#else /* Not Windows */ - CHAR_SLASH, /* Default path separator */ - CHAR_BACKSLASH /* Default escape character */ -#endif - }; - -/* The create function copies the default into the new memory, but must -override the default memory handling functions if a gcontext was provided. */ - -PCRE2_EXP_DEFN pcre2_convert_context * PCRE2_CALL_CONVENTION -pcre2_convert_context_create(pcre2_general_context *gcontext) -{ -pcre2_convert_context *ccontext = PRIV(memctl_malloc)( - sizeof(pcre2_real_convert_context), (pcre2_memctl *)gcontext); -if (ccontext == NULL) return NULL; -*ccontext = PRIV(default_convert_context); -if (gcontext != NULL) - *((pcre2_memctl *)ccontext) = *((pcre2_memctl *)gcontext); -return ccontext; -} - - -/************************************************* -* Context copy functions * -*************************************************/ - -PCRE2_EXP_DEFN pcre2_general_context * PCRE2_CALL_CONVENTION -pcre2_general_context_copy(pcre2_general_context *gcontext) -{ -pcre2_general_context *new = - gcontext->memctl.malloc(sizeof(pcre2_real_general_context), - gcontext->memctl.memory_data); -if (new == NULL) return NULL; -memcpy(new, gcontext, sizeof(pcre2_real_general_context)); -return new; -} - - -PCRE2_EXP_DEFN pcre2_compile_context * PCRE2_CALL_CONVENTION -pcre2_compile_context_copy(pcre2_compile_context *ccontext) -{ -pcre2_compile_context *new = - ccontext->memctl.malloc(sizeof(pcre2_real_compile_context), - ccontext->memctl.memory_data); -if (new == NULL) return NULL; -memcpy(new, ccontext, sizeof(pcre2_real_compile_context)); -return new; -} - - -PCRE2_EXP_DEFN pcre2_match_context * PCRE2_CALL_CONVENTION -pcre2_match_context_copy(pcre2_match_context *mcontext) -{ -pcre2_match_context *new = - mcontext->memctl.malloc(sizeof(pcre2_real_match_context), - mcontext->memctl.memory_data); -if (new == NULL) return NULL; -memcpy(new, mcontext, sizeof(pcre2_real_match_context)); -return new; -} - - - -PCRE2_EXP_DEFN pcre2_convert_context * PCRE2_CALL_CONVENTION -pcre2_convert_context_copy(pcre2_convert_context *ccontext) -{ -pcre2_convert_context *new = - ccontext->memctl.malloc(sizeof(pcre2_real_convert_context), - ccontext->memctl.memory_data); -if (new == NULL) return NULL; -memcpy(new, ccontext, sizeof(pcre2_real_convert_context)); -return new; -} - - -/************************************************* -* Context free functions * -*************************************************/ - -PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION -pcre2_general_context_free(pcre2_general_context *gcontext) -{ -if (gcontext != NULL) - gcontext->memctl.free(gcontext, gcontext->memctl.memory_data); -} - - -PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION -pcre2_compile_context_free(pcre2_compile_context *ccontext) -{ -if (ccontext != NULL) - ccontext->memctl.free(ccontext, ccontext->memctl.memory_data); -} - - -PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION -pcre2_match_context_free(pcre2_match_context *mcontext) -{ -if (mcontext != NULL) - mcontext->memctl.free(mcontext, mcontext->memctl.memory_data); -} - - -PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION -pcre2_convert_context_free(pcre2_convert_context *ccontext) -{ -if (ccontext != NULL) - ccontext->memctl.free(ccontext, ccontext->memctl.memory_data); -} - - -/************************************************* -* Set values in contexts * -*************************************************/ - -/* All these functions return 0 for success or PCRE2_ERROR_BADDATA if invalid -data is given. Only some of the functions are able to test the validity of the -data. */ - - -/* ------------ Compile context ------------ */ - -PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION -pcre2_set_character_tables(pcre2_compile_context *ccontext, - const uint8_t *tables) -{ -ccontext->tables = tables; -return 0; -} - -PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION -pcre2_set_bsr(pcre2_compile_context *ccontext, uint32_t value) -{ -switch(value) - { - case PCRE2_BSR_ANYCRLF: - case PCRE2_BSR_UNICODE: - ccontext->bsr_convention = value; - return 0; - - default: - return PCRE2_ERROR_BADDATA; - } -} - -PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION -pcre2_set_max_pattern_length(pcre2_compile_context *ccontext, PCRE2_SIZE length) -{ -ccontext->max_pattern_length = length; -return 0; -} - -PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION -pcre2_set_newline(pcre2_compile_context *ccontext, uint32_t newline) -{ -switch(newline) - { - case PCRE2_NEWLINE_CR: - case PCRE2_NEWLINE_LF: - case PCRE2_NEWLINE_CRLF: - case PCRE2_NEWLINE_ANY: - case PCRE2_NEWLINE_ANYCRLF: - case PCRE2_NEWLINE_NUL: - ccontext->newline_convention = newline; - return 0; - - default: - return PCRE2_ERROR_BADDATA; - } -} - -PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION -pcre2_set_parens_nest_limit(pcre2_compile_context *ccontext, uint32_t limit) -{ -ccontext->parens_nest_limit = limit; -return 0; -} - -PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION -pcre2_set_compile_extra_options(pcre2_compile_context *ccontext, uint32_t options) -{ -ccontext->extra_options = options; -return 0; -} - -PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION -pcre2_set_compile_recursion_guard(pcre2_compile_context *ccontext, - int (*guard)(uint32_t, void *), void *user_data) -{ -ccontext->stack_guard = guard; -ccontext->stack_guard_data = user_data; -return 0; -} - - -/* ------------ Match context ------------ */ - -PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION -pcre2_set_callout(pcre2_match_context *mcontext, - int (*callout)(pcre2_callout_block *, void *), void *callout_data) -{ -mcontext->callout = callout; -mcontext->callout_data = callout_data; -return 0; -} - -PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION -pcre2_set_substitute_callout(pcre2_match_context *mcontext, - int (*substitute_callout)(pcre2_substitute_callout_block *, void *), - void *substitute_callout_data) -{ -mcontext->substitute_callout = substitute_callout; -mcontext->substitute_callout_data = substitute_callout_data; -return 0; -} - -PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION -pcre2_set_heap_limit(pcre2_match_context *mcontext, uint32_t limit) -{ -mcontext->heap_limit = limit; -return 0; -} - -PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION -pcre2_set_match_limit(pcre2_match_context *mcontext, uint32_t limit) -{ -mcontext->match_limit = limit; -return 0; -} - -PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION -pcre2_set_depth_limit(pcre2_match_context *mcontext, uint32_t limit) -{ -mcontext->depth_limit = limit; -return 0; -} - -PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION -pcre2_set_offset_limit(pcre2_match_context *mcontext, PCRE2_SIZE limit) -{ -mcontext->offset_limit = limit; -return 0; -} - -/* These functions became obsolete at release 10.30. The first is kept as a -synonym for backwards compatibility. The second now does nothing. Exclude both -from coverage reports. */ - -/* LCOV_EXCL_START */ - -PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION -pcre2_set_recursion_limit(pcre2_match_context *mcontext, uint32_t limit) -{ -return pcre2_set_depth_limit(mcontext, limit); -} - -PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION -pcre2_set_recursion_memory_management(pcre2_match_context *mcontext, - void *(*mymalloc)(size_t, void *), void (*myfree)(void *, void *), - void *mydata) -{ -(void)mcontext; -(void)mymalloc; -(void)myfree; -(void)mydata; -return 0; -} - -/* LCOV_EXCL_STOP */ - - -/* ------------ Convert context ------------ */ - -PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION -pcre2_set_glob_separator(pcre2_convert_context *ccontext, uint32_t separator) -{ -if (separator != CHAR_SLASH && separator != CHAR_BACKSLASH && - separator != CHAR_DOT) return PCRE2_ERROR_BADDATA; -ccontext->glob_separator = separator; -return 0; -} - -PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION -pcre2_set_glob_escape(pcre2_convert_context *ccontext, uint32_t escape) -{ -if (escape > 255 || (escape != 0 && !ispunct(escape))) - return PCRE2_ERROR_BADDATA; -ccontext->glob_escape = escape; -return 0; -} - -/* End of pcre2_context.c */ - diff --git a/modules/regex/pcre2/src/pcre2_convert.c b/modules/regex/pcre2/src/pcre2_convert.c deleted file mode 100644 index 36466e4..0000000 --- a/modules/regex/pcre2/src/pcre2_convert.c +++ /dev/null @@ -1,1181 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -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-2022 University of Cambridge - ------------------------------------------------------------------------------ -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 OWNER 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. ------------------------------------------------------------------------------ -*/ - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "pcre2_internal.h" - -#define TYPE_OPTIONS (PCRE2_CONVERT_GLOB| \ - PCRE2_CONVERT_POSIX_BASIC|PCRE2_CONVERT_POSIX_EXTENDED) - -#define ALL_OPTIONS (PCRE2_CONVERT_UTF|PCRE2_CONVERT_NO_UTF_CHECK| \ - PCRE2_CONVERT_GLOB_NO_WILD_SEPARATOR| \ - PCRE2_CONVERT_GLOB_NO_STARSTAR| \ - TYPE_OPTIONS) - -#define DUMMY_BUFFER_SIZE 100 - -/* Generated pattern fragments */ - -#define STR_BACKSLASH_A STR_BACKSLASH STR_A -#define STR_BACKSLASH_z STR_BACKSLASH STR_z -#define STR_COLON_RIGHT_SQUARE_BRACKET STR_COLON STR_RIGHT_SQUARE_BRACKET -#define STR_DOT_STAR_LOOKBEHIND STR_DOT STR_ASTERISK STR_LEFT_PARENTHESIS STR_QUESTION_MARK STR_LESS_THAN_SIGN STR_EQUALS_SIGN -#define STR_LOOKAHEAD_NOT_DOT STR_LEFT_PARENTHESIS STR_QUESTION_MARK STR_EXCLAMATION_MARK STR_BACKSLASH STR_DOT STR_RIGHT_PARENTHESIS -#define STR_QUERY_s STR_LEFT_PARENTHESIS STR_QUESTION_MARK STR_s STR_RIGHT_PARENTHESIS -#define STR_STAR_NUL STR_LEFT_PARENTHESIS STR_ASTERISK STR_N STR_U STR_L STR_RIGHT_PARENTHESIS - -/* States for POSIX processing */ - -enum { POSIX_START_REGEX, POSIX_ANCHORED, POSIX_NOT_BRACKET, - POSIX_CLASS_NOT_STARTED, POSIX_CLASS_STARTING, POSIX_CLASS_STARTED }; - -/* Macro to add a character string to the output buffer, checking for overflow. */ - -#define PUTCHARS(string) \ - { \ - for (s = (char *)(string); *s != 0; s++) \ - { \ - if (p >= endp) return PCRE2_ERROR_NOMEMORY; \ - *p++ = *s; \ - } \ - } - -/* Literals that must be escaped: \ ? * + | . ^ $ { } [ ] ( ) */ - -static const char *pcre2_escaped_literals = - STR_BACKSLASH STR_QUESTION_MARK STR_ASTERISK STR_PLUS - STR_VERTICAL_LINE STR_DOT STR_CIRCUMFLEX_ACCENT STR_DOLLAR_SIGN - STR_LEFT_CURLY_BRACKET STR_RIGHT_CURLY_BRACKET - STR_LEFT_SQUARE_BRACKET STR_RIGHT_SQUARE_BRACKET - STR_LEFT_PARENTHESIS STR_RIGHT_PARENTHESIS; - -/* Recognized escaped metacharacters in POSIX basic patterns. */ - -static const char *posix_meta_escapes = - STR_LEFT_PARENTHESIS STR_RIGHT_PARENTHESIS - STR_LEFT_CURLY_BRACKET STR_RIGHT_CURLY_BRACKET - STR_1 STR_2 STR_3 STR_4 STR_5 STR_6 STR_7 STR_8 STR_9; - - - -/************************************************* -* Convert a POSIX pattern * -*************************************************/ - -/* This function handles both basic and extended POSIX patterns. - -Arguments: - pattype the pattern type - pattern the pattern - plength length in code units - utf TRUE if UTF - use_buffer where to put the output - use_length length of use_buffer - bufflenptr where to put the used length - dummyrun TRUE if a dummy run - ccontext the convert context - -Returns: 0 => success - !0 => error code -*/ - -static int -convert_posix(uint32_t pattype, PCRE2_SPTR pattern, PCRE2_SIZE plength, - BOOL utf, PCRE2_UCHAR *use_buffer, PCRE2_SIZE use_length, - PCRE2_SIZE *bufflenptr, BOOL dummyrun, pcre2_convert_context *ccontext) -{ -char *s; -PCRE2_SPTR posix = pattern; -PCRE2_UCHAR *p = use_buffer; -PCRE2_UCHAR *pp = p; -PCRE2_UCHAR *endp = p + use_length - 1; /* Allow for trailing zero */ -PCRE2_SIZE convlength = 0; - -uint32_t bracount = 0; -uint32_t posix_state = POSIX_START_REGEX; -uint32_t lastspecial = 0; -BOOL extended = (pattype & PCRE2_CONVERT_POSIX_EXTENDED) != 0; -BOOL nextisliteral = FALSE; - -(void)utf; /* Not used when Unicode not supported */ -(void)ccontext; /* Not currently used */ - -/* Initialize default for error offset as end of input. */ - -*bufflenptr = plength; -PUTCHARS(STR_STAR_NUL); - -/* Now scan the input. */ - -while (plength > 0) - { - uint32_t c, sc; - int clength = 1; - - /* Add in the length of the last item, then, if in the dummy run, pull the - pointer back to the start of the (temporary) buffer and then remember the - start of the next item. */ - - convlength += p - pp; - if (dummyrun) p = use_buffer; - pp = p; - - /* Pick up the next character */ - -#ifndef SUPPORT_UNICODE - c = *posix; -#else - GETCHARLENTEST(c, posix, clength); -#endif - posix += clength; - plength -= clength; - - sc = nextisliteral? 0 : c; - nextisliteral = FALSE; - - /* Handle a character within a class. */ - - if (posix_state >= POSIX_CLASS_NOT_STARTED) - { - if (c == CHAR_RIGHT_SQUARE_BRACKET) - { - PUTCHARS(STR_RIGHT_SQUARE_BRACKET); - posix_state = POSIX_NOT_BRACKET; - } - - /* Not the end of the class */ - - else - { - switch (posix_state) - { - case POSIX_CLASS_STARTED: - if (c <= 127 && islower(c)) break; /* Remain in started state */ - posix_state = POSIX_CLASS_NOT_STARTED; - if (c == CHAR_COLON && plength > 0 && - *posix == CHAR_RIGHT_SQUARE_BRACKET) - { - PUTCHARS(STR_COLON_RIGHT_SQUARE_BRACKET); - plength--; - posix++; - continue; /* With next character after :] */ - } - /* Fall through */ - - case POSIX_CLASS_NOT_STARTED: - if (c == CHAR_LEFT_SQUARE_BRACKET) - posix_state = POSIX_CLASS_STARTING; - break; - - case POSIX_CLASS_STARTING: - if (c == CHAR_COLON) posix_state = POSIX_CLASS_STARTED; - break; - } - - if (c == CHAR_BACKSLASH) PUTCHARS(STR_BACKSLASH); - if (p + clength > endp) return PCRE2_ERROR_NOMEMORY; - memcpy(p, posix - clength, CU2BYTES(clength)); - p += clength; - } - } - - /* Handle a character not within a class. */ - - else switch(sc) - { - case CHAR_LEFT_SQUARE_BRACKET: - PUTCHARS(STR_LEFT_SQUARE_BRACKET); - -#ifdef NEVER - /* We could handle special cases [[:<:]] and [[:>:]] (which PCRE does - support) but they are not part of POSIX 1003.1. */ - - if (plength >= 6) - { - if (posix[0] == CHAR_LEFT_SQUARE_BRACKET && - posix[1] == CHAR_COLON && - (posix[2] == CHAR_LESS_THAN_SIGN || - posix[2] == CHAR_GREATER_THAN_SIGN) && - posix[3] == CHAR_COLON && - posix[4] == CHAR_RIGHT_SQUARE_BRACKET && - posix[5] == CHAR_RIGHT_SQUARE_BRACKET) - { - if (p + 6 > endp) return PCRE2_ERROR_NOMEMORY; - memcpy(p, posix, CU2BYTES(6)); - p += 6; - posix += 6; - plength -= 6; - continue; /* With next character */ - } - } -#endif - - /* Handle start of "normal" character classes */ - - posix_state = POSIX_CLASS_NOT_STARTED; - - /* Handle ^ and ] as first characters */ - - if (plength > 0) - { - if (*posix == CHAR_CIRCUMFLEX_ACCENT) - { - posix++; - plength--; - PUTCHARS(STR_CIRCUMFLEX_ACCENT); - } - if (plength > 0 && *posix == CHAR_RIGHT_SQUARE_BRACKET) - { - posix++; - plength--; - PUTCHARS(STR_RIGHT_SQUARE_BRACKET); - } - } - break; - - case CHAR_BACKSLASH: - if (plength == 0) return PCRE2_ERROR_END_BACKSLASH; - if (extended) nextisliteral = TRUE; else - { - if (*posix < 127 && strchr(posix_meta_escapes, *posix) != NULL) - { - if (isdigit(*posix)) PUTCHARS(STR_BACKSLASH); - if (p + 1 > endp) return PCRE2_ERROR_NOMEMORY; - lastspecial = *p++ = *posix++; - plength--; - } - else nextisliteral = TRUE; - } - break; - - case CHAR_RIGHT_PARENTHESIS: - if (!extended || bracount == 0) goto ESCAPE_LITERAL; - bracount--; - goto COPY_SPECIAL; - - case CHAR_LEFT_PARENTHESIS: - bracount++; - /* Fall through */ - - case CHAR_QUESTION_MARK: - case CHAR_PLUS: - case CHAR_LEFT_CURLY_BRACKET: - case CHAR_RIGHT_CURLY_BRACKET: - case CHAR_VERTICAL_LINE: - if (!extended) goto ESCAPE_LITERAL; - /* Fall through */ - - case CHAR_DOT: - case CHAR_DOLLAR_SIGN: - posix_state = POSIX_NOT_BRACKET; - COPY_SPECIAL: - lastspecial = c; - if (p + 1 > endp) return PCRE2_ERROR_NOMEMORY; - *p++ = c; - break; - - case CHAR_ASTERISK: - if (lastspecial != CHAR_ASTERISK) - { - if (!extended && (posix_state < POSIX_NOT_BRACKET || - lastspecial == CHAR_LEFT_PARENTHESIS)) - goto ESCAPE_LITERAL; - goto COPY_SPECIAL; - } - break; /* Ignore second and subsequent asterisks */ - - case CHAR_CIRCUMFLEX_ACCENT: - if (extended) goto COPY_SPECIAL; - if (posix_state == POSIX_START_REGEX || - lastspecial == CHAR_LEFT_PARENTHESIS) - { - posix_state = POSIX_ANCHORED; - goto COPY_SPECIAL; - } - /* Fall through */ - - default: - if (c < 128 && strchr(pcre2_escaped_literals, c) != NULL) - { - ESCAPE_LITERAL: - PUTCHARS(STR_BACKSLASH); - } - lastspecial = 0xff; /* Indicates nothing special */ - if (p + clength > endp) return PCRE2_ERROR_NOMEMORY; - memcpy(p, posix - clength, CU2BYTES(clength)); - p += clength; - posix_state = POSIX_NOT_BRACKET; - break; - } - } - -if (posix_state >= POSIX_CLASS_NOT_STARTED) - return PCRE2_ERROR_MISSING_SQUARE_BRACKET; -convlength += p - pp; /* Final segment */ -*bufflenptr = convlength; -*p++ = 0; -return 0; -} - - -/************************************************* -* Convert a glob pattern * -*************************************************/ - -/* Context for writing the output into a buffer. */ - -typedef struct pcre2_output_context { - PCRE2_UCHAR *output; /* current output position */ - PCRE2_SPTR output_end; /* output end */ - PCRE2_SIZE output_size; /* size of the output */ - uint8_t out_str[8]; /* string copied to the output */ -} pcre2_output_context; - - -/* Write a character into the output. - -Arguments: - out output context - chr the next character -*/ - -static void -convert_glob_write(pcre2_output_context *out, PCRE2_UCHAR chr) -{ -out->output_size++; - -if (out->output < out->output_end) - *out->output++ = chr; -} - - -/* Write a string into the output. - -Arguments: - out output context - length length of out->out_str -*/ - -static void -convert_glob_write_str(pcre2_output_context *out, PCRE2_SIZE length) -{ -uint8_t *out_str = out->out_str; -PCRE2_UCHAR *output = out->output; -PCRE2_SPTR output_end = out->output_end; -PCRE2_SIZE output_size = out->output_size; - -do - { - output_size++; - - if (output < output_end) - *output++ = *out_str++; - } -while (--length != 0); - -out->output = output; -out->output_size = output_size; -} - - -/* Prints the separator into the output. - -Arguments: - out output context - separator glob separator - with_escape backslash is needed before separator -*/ - -static void -convert_glob_print_separator(pcre2_output_context *out, - PCRE2_UCHAR separator, BOOL with_escape) -{ -if (with_escape) - convert_glob_write(out, CHAR_BACKSLASH); - -convert_glob_write(out, separator); -} - - -/* Prints a wildcard into the output. - -Arguments: - out output context - separator glob separator - with_escape backslash is needed before separator -*/ - -static void -convert_glob_print_wildcard(pcre2_output_context *out, - PCRE2_UCHAR separator, BOOL with_escape) -{ -out->out_str[0] = CHAR_LEFT_SQUARE_BRACKET; -out->out_str[1] = CHAR_CIRCUMFLEX_ACCENT; -convert_glob_write_str(out, 2); - -convert_glob_print_separator(out, separator, with_escape); - -convert_glob_write(out, CHAR_RIGHT_SQUARE_BRACKET); -} - - -/* Parse a posix class. - -Arguments: - from starting point of scanning the range - pattern_end end of pattern - out output context - -Returns: >0 => class index - 0 => malformed class -*/ - -static int -convert_glob_parse_class(PCRE2_SPTR *from, PCRE2_SPTR pattern_end, - pcre2_output_context *out) -{ -static const char *posix_classes = "alnum:alpha:ascii:blank:cntrl:digit:" - "graph:lower:print:punct:space:upper:word:xdigit:"; -PCRE2_SPTR start = *from + 1; -PCRE2_SPTR pattern = start; -const char *class_ptr; -PCRE2_UCHAR c; -int class_index; - -while (TRUE) - { - if (pattern >= pattern_end) return 0; - - c = *pattern++; - - if (c < CHAR_a || c > CHAR_z) break; - } - -if (c != CHAR_COLON || pattern >= pattern_end || - *pattern != CHAR_RIGHT_SQUARE_BRACKET) - return 0; - -class_ptr = posix_classes; -class_index = 1; - -while (TRUE) - { - if (*class_ptr == CHAR_NUL) return 0; - - pattern = start; - - while (*pattern == (PCRE2_UCHAR) *class_ptr) - { - if (*pattern == CHAR_COLON) - { - pattern += 2; - start -= 2; - - do convert_glob_write(out, *start++); while (start < pattern); - - *from = pattern; - return class_index; - } - pattern++; - class_ptr++; - } - - while (*class_ptr != CHAR_COLON) class_ptr++; - class_ptr++; - class_index++; - } -} - -/* Checks whether the character is in the class. - -Arguments: - class_index class index - c character - -Returns: !0 => character is found in the class - 0 => otherwise -*/ - -static BOOL -convert_glob_char_in_class(int class_index, PCRE2_UCHAR c) -{ -switch (class_index) - { - case 1: return isalnum(c); - case 2: return isalpha(c); - case 3: return 1; - case 4: return c == CHAR_HT || c == CHAR_SPACE; - case 5: return iscntrl(c); - case 6: return isdigit(c); - case 7: return isgraph(c); - case 8: return islower(c); - case 9: return isprint(c); - case 10: return ispunct(c); - case 11: return isspace(c); - case 12: return isupper(c); - case 13: return isalnum(c) || c == CHAR_UNDERSCORE; - default: return isxdigit(c); - } -} - -/* Parse a range of characters. - -Arguments: - from starting point of scanning the range - pattern_end end of pattern - out output context - separator glob separator - with_escape backslash is needed before separator - -Returns: 0 => success - !0 => error code -*/ - -static int -convert_glob_parse_range(PCRE2_SPTR *from, PCRE2_SPTR pattern_end, - pcre2_output_context *out, BOOL utf, PCRE2_UCHAR separator, - BOOL with_escape, PCRE2_UCHAR escape, BOOL no_wildsep) -{ -BOOL is_negative = FALSE; -BOOL separator_seen = FALSE; -BOOL has_prev_c; -PCRE2_SPTR pattern = *from; -PCRE2_SPTR char_start = NULL; -uint32_t c, prev_c; -int len, class_index; - -(void)utf; /* Avoid compiler warning. */ - -if (pattern >= pattern_end) - { - *from = pattern; - return PCRE2_ERROR_MISSING_SQUARE_BRACKET; - } - -if (*pattern == CHAR_EXCLAMATION_MARK - || *pattern == CHAR_CIRCUMFLEX_ACCENT) - { - pattern++; - - if (pattern >= pattern_end) - { - *from = pattern; - return PCRE2_ERROR_MISSING_SQUARE_BRACKET; - } - - is_negative = TRUE; - - out->out_str[0] = CHAR_LEFT_SQUARE_BRACKET; - out->out_str[1] = CHAR_CIRCUMFLEX_ACCENT; - len = 2; - - if (!no_wildsep) - { - if (with_escape) - { - out->out_str[len] = CHAR_BACKSLASH; - len++; - } - out->out_str[len] = (uint8_t) separator; - } - - convert_glob_write_str(out, len + 1); - } -else - convert_glob_write(out, CHAR_LEFT_SQUARE_BRACKET); - -has_prev_c = FALSE; -prev_c = 0; - -if (*pattern == CHAR_RIGHT_SQUARE_BRACKET) - { - out->out_str[0] = CHAR_BACKSLASH; - out->out_str[1] = CHAR_RIGHT_SQUARE_BRACKET; - convert_glob_write_str(out, 2); - has_prev_c = TRUE; - prev_c = CHAR_RIGHT_SQUARE_BRACKET; - pattern++; - } - -while (pattern < pattern_end) - { - char_start = pattern; - GETCHARINCTEST(c, pattern); - - if (c == CHAR_RIGHT_SQUARE_BRACKET) - { - convert_glob_write(out, c); - - if (!is_negative && !no_wildsep && separator_seen) - { - out->out_str[0] = CHAR_LEFT_PARENTHESIS; - out->out_str[1] = CHAR_QUESTION_MARK; - out->out_str[2] = CHAR_LESS_THAN_SIGN; - out->out_str[3] = CHAR_EXCLAMATION_MARK; - convert_glob_write_str(out, 4); - - convert_glob_print_separator(out, separator, with_escape); - convert_glob_write(out, CHAR_RIGHT_PARENTHESIS); - } - - *from = pattern; - return 0; - } - - if (pattern >= pattern_end) break; - - if (c == CHAR_LEFT_SQUARE_BRACKET && *pattern == CHAR_COLON) - { - *from = pattern; - class_index = convert_glob_parse_class(from, pattern_end, out); - - if (class_index != 0) - { - pattern = *from; - - has_prev_c = FALSE; - prev_c = 0; - - if (!is_negative && - convert_glob_char_in_class (class_index, separator)) - separator_seen = TRUE; - continue; - } - } - else if (c == CHAR_MINUS && has_prev_c && - *pattern != CHAR_RIGHT_SQUARE_BRACKET) - { - convert_glob_write(out, CHAR_MINUS); - - char_start = pattern; - GETCHARINCTEST(c, pattern); - - if (pattern >= pattern_end) break; - - if (escape != 0 && c == escape) - { - char_start = pattern; - GETCHARINCTEST(c, pattern); - } - else if (c == CHAR_LEFT_SQUARE_BRACKET && *pattern == CHAR_COLON) - { - *from = pattern; - return PCRE2_ERROR_CONVERT_SYNTAX; - } - - if (prev_c > c) - { - *from = pattern; - return PCRE2_ERROR_CONVERT_SYNTAX; - } - - if (prev_c < separator && separator < c) separator_seen = TRUE; - - has_prev_c = FALSE; - prev_c = 0; - } - else - { - if (escape != 0 && c == escape) - { - char_start = pattern; - GETCHARINCTEST(c, pattern); - - if (pattern >= pattern_end) break; - } - - has_prev_c = TRUE; - prev_c = c; - } - - if (c == CHAR_LEFT_SQUARE_BRACKET || c == CHAR_RIGHT_SQUARE_BRACKET || - c == CHAR_BACKSLASH || c == CHAR_MINUS) - convert_glob_write(out, CHAR_BACKSLASH); - - if (c == separator) separator_seen = TRUE; - - do convert_glob_write(out, *char_start++); while (char_start < pattern); - } - -*from = pattern; -return PCRE2_ERROR_MISSING_SQUARE_BRACKET; -} - - -/* Prints a (*COMMIT) into the output. - -Arguments: - out output context -*/ - -static void -convert_glob_print_commit(pcre2_output_context *out) -{ -out->out_str[0] = CHAR_LEFT_PARENTHESIS; -out->out_str[1] = CHAR_ASTERISK; -out->out_str[2] = CHAR_C; -out->out_str[3] = CHAR_O; -out->out_str[4] = CHAR_M; -out->out_str[5] = CHAR_M; -out->out_str[6] = CHAR_I; -out->out_str[7] = CHAR_T; -convert_glob_write_str(out, 8); -convert_glob_write(out, CHAR_RIGHT_PARENTHESIS); -} - - -/* Bash glob converter. - -Arguments: - pattype the pattern type - pattern the pattern - plength length in code units - utf TRUE if UTF - use_buffer where to put the output - use_length length of use_buffer - bufflenptr where to put the used length - dummyrun TRUE if a dummy run - ccontext the convert context - -Returns: 0 => success - !0 => error code -*/ - -static int -convert_glob(uint32_t options, PCRE2_SPTR pattern, PCRE2_SIZE plength, - BOOL utf, PCRE2_UCHAR *use_buffer, PCRE2_SIZE use_length, - PCRE2_SIZE *bufflenptr, BOOL dummyrun, pcre2_convert_context *ccontext) -{ -pcre2_output_context out; -PCRE2_SPTR pattern_start = pattern; -PCRE2_SPTR pattern_end = pattern + plength; -PCRE2_UCHAR separator = ccontext->glob_separator; -PCRE2_UCHAR escape = ccontext->glob_escape; -PCRE2_UCHAR c; -BOOL no_wildsep = (options & PCRE2_CONVERT_GLOB_NO_WILD_SEPARATOR) != 0; -BOOL no_starstar = (options & PCRE2_CONVERT_GLOB_NO_STARSTAR) != 0; -BOOL in_atomic = FALSE; -BOOL after_starstar = FALSE; -BOOL no_slash_z = FALSE; -BOOL with_escape, is_start, after_separator; -int result = 0; - -(void)utf; /* Avoid compiler warning. */ - -#ifdef SUPPORT_UNICODE -if (utf && (separator >= 128 || escape >= 128)) - { - /* Currently only ASCII characters are supported. */ - *bufflenptr = 0; - return PCRE2_ERROR_CONVERT_SYNTAX; - } -#endif - -with_escape = strchr(pcre2_escaped_literals, separator) != NULL; - -/* Initialize default for error offset as end of input. */ -out.output = use_buffer; -out.output_end = use_buffer + use_length; -out.output_size = 0; - -out.out_str[0] = CHAR_LEFT_PARENTHESIS; -out.out_str[1] = CHAR_QUESTION_MARK; -out.out_str[2] = CHAR_s; -out.out_str[3] = CHAR_RIGHT_PARENTHESIS; -convert_glob_write_str(&out, 4); - -is_start = TRUE; - -if (pattern < pattern_end && pattern[0] == CHAR_ASTERISK) - { - if (no_wildsep) - is_start = FALSE; - else if (!no_starstar && pattern + 1 < pattern_end && - pattern[1] == CHAR_ASTERISK) - is_start = FALSE; - } - -if (is_start) - { - out.out_str[0] = CHAR_BACKSLASH; - out.out_str[1] = CHAR_A; - convert_glob_write_str(&out, 2); - } - -while (pattern < pattern_end) - { - c = *pattern++; - - if (c == CHAR_ASTERISK) - { - is_start = pattern == pattern_start + 1; - - if (in_atomic) - { - convert_glob_write(&out, CHAR_RIGHT_PARENTHESIS); - in_atomic = FALSE; - } - - if (!no_starstar && pattern < pattern_end && *pattern == CHAR_ASTERISK) - { - after_separator = is_start || (pattern[-2] == separator); - - do pattern++; while (pattern < pattern_end && - *pattern == CHAR_ASTERISK); - - if (pattern >= pattern_end) - { - no_slash_z = TRUE; - break; - } - - after_starstar = TRUE; - - if (after_separator && escape != 0 && *pattern == escape && - pattern + 1 < pattern_end && pattern[1] == separator) - pattern++; - - if (is_start) - { - if (*pattern != separator) continue; - - out.out_str[0] = CHAR_LEFT_PARENTHESIS; - out.out_str[1] = CHAR_QUESTION_MARK; - out.out_str[2] = CHAR_COLON; - out.out_str[3] = CHAR_BACKSLASH; - out.out_str[4] = CHAR_A; - out.out_str[5] = CHAR_VERTICAL_LINE; - convert_glob_write_str(&out, 6); - - convert_glob_print_separator(&out, separator, with_escape); - convert_glob_write(&out, CHAR_RIGHT_PARENTHESIS); - - pattern++; - continue; - } - - convert_glob_print_commit(&out); - - if (!after_separator || *pattern != separator) - { - out.out_str[0] = CHAR_DOT; - out.out_str[1] = CHAR_ASTERISK; - out.out_str[2] = CHAR_QUESTION_MARK; - convert_glob_write_str(&out, 3); - continue; - } - - out.out_str[0] = CHAR_LEFT_PARENTHESIS; - out.out_str[1] = CHAR_QUESTION_MARK; - out.out_str[2] = CHAR_COLON; - out.out_str[3] = CHAR_DOT; - out.out_str[4] = CHAR_ASTERISK; - out.out_str[5] = CHAR_QUESTION_MARK; - - convert_glob_write_str(&out, 6); - - convert_glob_print_separator(&out, separator, with_escape); - - out.out_str[0] = CHAR_RIGHT_PARENTHESIS; - out.out_str[1] = CHAR_QUESTION_MARK; - out.out_str[2] = CHAR_QUESTION_MARK; - convert_glob_write_str(&out, 3); - - pattern++; - continue; - } - - if (pattern < pattern_end && *pattern == CHAR_ASTERISK) - { - do pattern++; while (pattern < pattern_end && - *pattern == CHAR_ASTERISK); - } - - if (no_wildsep) - { - if (pattern >= pattern_end) - { - no_slash_z = TRUE; - break; - } - - /* Start check must be after the end check. */ - if (is_start) continue; - } - - if (!is_start) - { - if (after_starstar) - { - out.out_str[0] = CHAR_LEFT_PARENTHESIS; - out.out_str[1] = CHAR_QUESTION_MARK; - out.out_str[2] = CHAR_GREATER_THAN_SIGN; - convert_glob_write_str(&out, 3); - in_atomic = TRUE; - } - else - convert_glob_print_commit(&out); - } - - if (no_wildsep) - convert_glob_write(&out, CHAR_DOT); - else - convert_glob_print_wildcard(&out, separator, with_escape); - - out.out_str[0] = CHAR_ASTERISK; - out.out_str[1] = CHAR_QUESTION_MARK; - if (pattern >= pattern_end) - out.out_str[1] = CHAR_PLUS; - convert_glob_write_str(&out, 2); - continue; - } - - if (c == CHAR_QUESTION_MARK) - { - if (no_wildsep) - convert_glob_write(&out, CHAR_DOT); - else - convert_glob_print_wildcard(&out, separator, with_escape); - continue; - } - - if (c == CHAR_LEFT_SQUARE_BRACKET) - { - result = convert_glob_parse_range(&pattern, pattern_end, - &out, utf, separator, with_escape, escape, no_wildsep); - if (result != 0) break; - continue; - } - - if (escape != 0 && c == escape) - { - if (pattern >= pattern_end) - { - result = PCRE2_ERROR_CONVERT_SYNTAX; - break; - } - c = *pattern++; - } - - if (c < 128 && strchr(pcre2_escaped_literals, c) != NULL) - convert_glob_write(&out, CHAR_BACKSLASH); - - convert_glob_write(&out, c); - } - -if (result == 0) - { - if (!no_slash_z) - { - out.out_str[0] = CHAR_BACKSLASH; - out.out_str[1] = CHAR_z; - convert_glob_write_str(&out, 2); - } - - if (in_atomic) - convert_glob_write(&out, CHAR_RIGHT_PARENTHESIS); - - convert_glob_write(&out, CHAR_NUL); - - if (!dummyrun && out.output_size != (PCRE2_SIZE) (out.output - use_buffer)) - result = PCRE2_ERROR_NOMEMORY; - } - -if (result != 0) - { - *bufflenptr = pattern - pattern_start; - return result; - } - -*bufflenptr = out.output_size - 1; -return 0; -} - - -/************************************************* -* Convert pattern * -*************************************************/ - -/* This is the external-facing function for converting other forms of pattern -into PCRE2 regular expression patterns. On error, the bufflenptr argument is -used to return an offset in the original pattern. - -Arguments: - pattern the input pattern - plength length of input, or PCRE2_ZERO_TERMINATED - options options bits - buffptr pointer to pointer to output buffer - bufflenptr pointer to length of output buffer - ccontext convert context or NULL - -Returns: 0 for success, else an error code (+ve or -ve) -*/ - -PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION -pcre2_pattern_convert(PCRE2_SPTR pattern, PCRE2_SIZE plength, uint32_t options, - PCRE2_UCHAR **buffptr, PCRE2_SIZE *bufflenptr, - pcre2_convert_context *ccontext) -{ -int i, rc; -PCRE2_UCHAR dummy_buffer[DUMMY_BUFFER_SIZE]; -PCRE2_UCHAR *use_buffer = dummy_buffer; -PCRE2_SIZE use_length = DUMMY_BUFFER_SIZE; -BOOL utf = (options & PCRE2_CONVERT_UTF) != 0; -uint32_t pattype = options & TYPE_OPTIONS; - -if (pattern == NULL || bufflenptr == NULL) return PCRE2_ERROR_NULL; - -if ((options & ~ALL_OPTIONS) != 0 || /* Undefined bit set */ - (pattype & (~pattype+1)) != pattype || /* More than one type set */ - pattype == 0) /* No type set */ - { - *bufflenptr = 0; /* Error offset */ - return PCRE2_ERROR_BADOPTION; - } - -if (plength == PCRE2_ZERO_TERMINATED) plength = PRIV(strlen)(pattern); -if (ccontext == NULL) ccontext = - (pcre2_convert_context *)(&PRIV(default_convert_context)); - -/* Check UTF if required. */ - -#ifndef SUPPORT_UNICODE -if (utf) - { - *bufflenptr = 0; /* Error offset */ - return PCRE2_ERROR_UNICODE_NOT_SUPPORTED; - } -#else -if (utf && (options & PCRE2_CONVERT_NO_UTF_CHECK) == 0) - { - PCRE2_SIZE erroroffset; - rc = PRIV(valid_utf)(pattern, plength, &erroroffset); - if (rc != 0) - { - *bufflenptr = erroroffset; - return rc; - } - } -#endif - -/* If buffptr is not NULL, and what it points to is not NULL, we are being -provided with a buffer and a length, so set them as the buffer to use. */ - -if (buffptr != NULL && *buffptr != NULL) - { - use_buffer = *buffptr; - use_length = *bufflenptr; - } - -/* Call an individual converter, either just once (if a buffer was provided or -just the length is needed), or twice (if a memory allocation is required). */ - -for (i = 0; i < 2; i++) - { - PCRE2_UCHAR *allocated; - BOOL dummyrun = buffptr == NULL || *buffptr == NULL; - - switch(pattype) - { - case PCRE2_CONVERT_GLOB: - rc = convert_glob(options & ~PCRE2_CONVERT_GLOB, pattern, plength, utf, - use_buffer, use_length, bufflenptr, dummyrun, ccontext); - break; - - case PCRE2_CONVERT_POSIX_BASIC: - case PCRE2_CONVERT_POSIX_EXTENDED: - rc = convert_posix(pattype, pattern, plength, utf, use_buffer, use_length, - bufflenptr, dummyrun, ccontext); - break; - - default: - *bufflenptr = 0; /* Error offset */ - return PCRE2_ERROR_INTERNAL; - } - - if (rc != 0 || /* Error */ - buffptr == NULL || /* Just the length is required */ - *buffptr != NULL) /* Buffer was provided or allocated */ - return rc; - - /* Allocate memory for the buffer, with hidden space for an allocator at - the start. The next time round the loop runs the conversion for real. */ - - allocated = PRIV(memctl_malloc)(sizeof(pcre2_memctl) + - (*bufflenptr + 1)*PCRE2_CODE_UNIT_WIDTH, (pcre2_memctl *)ccontext); - if (allocated == NULL) return PCRE2_ERROR_NOMEMORY; - *buffptr = (PCRE2_UCHAR *)(((char *)allocated) + sizeof(pcre2_memctl)); - - use_buffer = *buffptr; - use_length = *bufflenptr + 1; - } - -/* Control should never get here. */ - -return PCRE2_ERROR_INTERNAL; -} - - -/************************************************* -* Free converted pattern * -*************************************************/ - -/* This frees a converted pattern that was put in newly-allocated memory. - -Argument: the converted pattern -Returns: nothing -*/ - -PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION -pcre2_converted_pattern_free(PCRE2_UCHAR *converted) -{ -if (converted != NULL) - { - pcre2_memctl *memctl = - (pcre2_memctl *)((char *)converted - sizeof(pcre2_memctl)); - memctl->free(memctl, memctl->memory_data); - } -} - -/* End of pcre2_convert.c */ diff --git a/modules/regex/pcre2/src/pcre2_dfa_match.c b/modules/regex/pcre2/src/pcre2_dfa_match.c deleted file mode 100644 index b16e594..0000000 --- a/modules/regex/pcre2/src/pcre2_dfa_match.c +++ /dev/null @@ -1,4066 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -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-2022 University of Cambridge - ------------------------------------------------------------------------------ -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 OWNER 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. ------------------------------------------------------------------------------ -*/ - - -/* This module contains the external function pcre2_dfa_match(), which is an -alternative matching function that uses a sort of DFA algorithm (not a true -FSM). This is NOT Perl-compatible, but it has advantages in certain -applications. */ - - -/* NOTE ABOUT PERFORMANCE: A user of this function sent some code that improved -the performance of his patterns greatly. I could not use it as it stood, as it -was not thread safe, and made assumptions about pattern sizes. Also, it caused -test 7 to loop, and test 9 to crash with a segfault. - -The issue is the check for duplicate states, which is done by a simple linear -search up the state list. (Grep for "duplicate" below to find the code.) For -many patterns, there will never be many states active at one time, so a simple -linear search is fine. In patterns that have many active states, it might be a -bottleneck. The suggested code used an indexing scheme to remember which states -had previously been used for each character, and avoided the linear search when -it knew there was no chance of a duplicate. This was implemented when adding -states to the state lists. - -I wrote some thread-safe, not-limited code to try something similar at the time -of checking for duplicates (instead of when adding states), using index vectors -on the stack. It did give a 13% improvement with one specially constructed -pattern for certain subject strings, but on other strings and on many of the -simpler patterns in the test suite it did worse. The major problem, I think, -was the extra time to initialize the index. This had to be done for each call -of internal_dfa_match(). (The supplied patch used a static vector, initialized -only once - I suspect this was the cause of the problems with the tests.) - -Overall, I concluded that the gains in some cases did not outweigh the losses -in others, so I abandoned this code. */ - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#define NLBLOCK mb /* Block containing newline information */ -#define PSSTART start_subject /* Field containing processed string start */ -#define PSEND end_subject /* Field containing processed string end */ - -#include "pcre2_internal.h" - -#define PUBLIC_DFA_MATCH_OPTIONS \ - (PCRE2_ANCHORED|PCRE2_ENDANCHORED|PCRE2_NOTBOL|PCRE2_NOTEOL|PCRE2_NOTEMPTY| \ - PCRE2_NOTEMPTY_ATSTART|PCRE2_NO_UTF_CHECK|PCRE2_PARTIAL_HARD| \ - PCRE2_PARTIAL_SOFT|PCRE2_DFA_SHORTEST|PCRE2_DFA_RESTART| \ - PCRE2_COPY_MATCHED_SUBJECT) - - -/************************************************* -* Code parameters and static tables * -*************************************************/ - -/* These are offsets that are used to turn the OP_TYPESTAR and friends opcodes -into others, under special conditions. A gap of 20 between the blocks should be -enough. The resulting opcodes don't have to be less than 256 because they are -never stored, so we push them well clear of the normal opcodes. */ - -#define OP_PROP_EXTRA 300 -#define OP_EXTUNI_EXTRA 320 -#define OP_ANYNL_EXTRA 340 -#define OP_HSPACE_EXTRA 360 -#define OP_VSPACE_EXTRA 380 - - -/* This table identifies those opcodes that are followed immediately by a -character that is to be tested in some way. This makes it possible to -centralize the loading of these characters. In the case of Type * etc, the -"character" is the opcode for \D, \d, \S, \s, \W, or \w, which will always be a -small value. Non-zero values in the table are the offsets from the opcode where -the character is to be found. ***NOTE*** If the start of this table is -modified, the three tables that follow must also be modified. */ - -static const uint8_t coptable[] = { - 0, /* End */ - 0, 0, 0, 0, 0, /* \A, \G, \K, \B, \b */ - 0, 0, 0, 0, 0, 0, /* \D, \d, \S, \s, \W, \w */ - 0, 0, 0, /* Any, AllAny, Anybyte */ - 0, 0, /* \P, \p */ - 0, 0, 0, 0, 0, /* \R, \H, \h, \V, \v */ - 0, /* \X */ - 0, 0, 0, 0, 0, 0, /* \Z, \z, $, $M, ^, ^M */ - 1, /* Char */ - 1, /* Chari */ - 1, /* not */ - 1, /* noti */ - /* Positive single-char repeats */ - 1, 1, 1, 1, 1, 1, /* *, *?, +, +?, ?, ?? */ - 1+IMM2_SIZE, 1+IMM2_SIZE, /* upto, minupto */ - 1+IMM2_SIZE, /* exact */ - 1, 1, 1, 1+IMM2_SIZE, /* *+, ++, ?+, upto+ */ - 1, 1, 1, 1, 1, 1, /* *I, *?I, +I, +?I, ?I, ??I */ - 1+IMM2_SIZE, 1+IMM2_SIZE, /* upto I, minupto I */ - 1+IMM2_SIZE, /* exact I */ - 1, 1, 1, 1+IMM2_SIZE, /* *+I, ++I, ?+I, upto+I */ - /* Negative single-char repeats - only for chars < 256 */ - 1, 1, 1, 1, 1, 1, /* NOT *, *?, +, +?, ?, ?? */ - 1+IMM2_SIZE, 1+IMM2_SIZE, /* NOT upto, minupto */ - 1+IMM2_SIZE, /* NOT exact */ - 1, 1, 1, 1+IMM2_SIZE, /* NOT *+, ++, ?+, upto+ */ - 1, 1, 1, 1, 1, 1, /* NOT *I, *?I, +I, +?I, ?I, ??I */ - 1+IMM2_SIZE, 1+IMM2_SIZE, /* NOT upto I, minupto I */ - 1+IMM2_SIZE, /* NOT exact I */ - 1, 1, 1, 1+IMM2_SIZE, /* NOT *+I, ++I, ?+I, upto+I */ - /* Positive type repeats */ - 1, 1, 1, 1, 1, 1, /* Type *, *?, +, +?, ?, ?? */ - 1+IMM2_SIZE, 1+IMM2_SIZE, /* Type upto, minupto */ - 1+IMM2_SIZE, /* Type exact */ - 1, 1, 1, 1+IMM2_SIZE, /* Type *+, ++, ?+, upto+ */ - /* Character class & ref repeats */ - 0, 0, 0, 0, 0, 0, /* *, *?, +, +?, ?, ?? */ - 0, 0, /* CRRANGE, CRMINRANGE */ - 0, 0, 0, 0, /* Possessive *+, ++, ?+, CRPOSRANGE */ - 0, /* CLASS */ - 0, /* NCLASS */ - 0, /* XCLASS - variable length */ - 0, /* REF */ - 0, /* REFI */ - 0, /* DNREF */ - 0, /* DNREFI */ - 0, /* RECURSE */ - 0, /* CALLOUT */ - 0, /* CALLOUT_STR */ - 0, /* Alt */ - 0, /* Ket */ - 0, /* KetRmax */ - 0, /* KetRmin */ - 0, /* KetRpos */ - 0, /* Reverse */ - 0, /* Assert */ - 0, /* Assert not */ - 0, /* Assert behind */ - 0, /* Assert behind not */ - 0, /* NA assert */ - 0, /* NA assert behind */ - 0, /* ONCE */ - 0, /* SCRIPT_RUN */ - 0, 0, 0, 0, 0, /* BRA, BRAPOS, CBRA, CBRAPOS, COND */ - 0, 0, 0, 0, 0, /* SBRA, SBRAPOS, SCBRA, SCBRAPOS, SCOND */ - 0, 0, /* CREF, DNCREF */ - 0, 0, /* RREF, DNRREF */ - 0, 0, /* FALSE, TRUE */ - 0, 0, 0, /* BRAZERO, BRAMINZERO, BRAPOSZERO */ - 0, 0, 0, /* MARK, PRUNE, PRUNE_ARG */ - 0, 0, 0, 0, /* SKIP, SKIP_ARG, THEN, THEN_ARG */ - 0, 0, /* COMMIT, COMMIT_ARG */ - 0, 0, 0, /* FAIL, ACCEPT, ASSERT_ACCEPT */ - 0, 0, 0 /* CLOSE, SKIPZERO, DEFINE */ -}; - -/* This table identifies those opcodes that inspect a character. It is used to -remember the fact that a character could have been inspected when the end of -the subject is reached. ***NOTE*** If the start of this table is modified, the -two tables that follow must also be modified. */ - -static const uint8_t poptable[] = { - 0, /* End */ - 0, 0, 0, 1, 1, /* \A, \G, \K, \B, \b */ - 1, 1, 1, 1, 1, 1, /* \D, \d, \S, \s, \W, \w */ - 1, 1, 1, /* Any, AllAny, Anybyte */ - 1, 1, /* \P, \p */ - 1, 1, 1, 1, 1, /* \R, \H, \h, \V, \v */ - 1, /* \X */ - 0, 0, 0, 0, 0, 0, /* \Z, \z, $, $M, ^, ^M */ - 1, /* Char */ - 1, /* Chari */ - 1, /* not */ - 1, /* noti */ - /* Positive single-char repeats */ - 1, 1, 1, 1, 1, 1, /* *, *?, +, +?, ?, ?? */ - 1, 1, 1, /* upto, minupto, exact */ - 1, 1, 1, 1, /* *+, ++, ?+, upto+ */ - 1, 1, 1, 1, 1, 1, /* *I, *?I, +I, +?I, ?I, ??I */ - 1, 1, 1, /* upto I, minupto I, exact I */ - 1, 1, 1, 1, /* *+I, ++I, ?+I, upto+I */ - /* Negative single-char repeats - only for chars < 256 */ - 1, 1, 1, 1, 1, 1, /* NOT *, *?, +, +?, ?, ?? */ - 1, 1, 1, /* NOT upto, minupto, exact */ - 1, 1, 1, 1, /* NOT *+, ++, ?+, upto+ */ - 1, 1, 1, 1, 1, 1, /* NOT *I, *?I, +I, +?I, ?I, ??I */ - 1, 1, 1, /* NOT upto I, minupto I, exact I */ - 1, 1, 1, 1, /* NOT *+I, ++I, ?+I, upto+I */ - /* Positive type repeats */ - 1, 1, 1, 1, 1, 1, /* Type *, *?, +, +?, ?, ?? */ - 1, 1, 1, /* Type upto, minupto, exact */ - 1, 1, 1, 1, /* Type *+, ++, ?+, upto+ */ - /* Character class & ref repeats */ - 1, 1, 1, 1, 1, 1, /* *, *?, +, +?, ?, ?? */ - 1, 1, /* CRRANGE, CRMINRANGE */ - 1, 1, 1, 1, /* Possessive *+, ++, ?+, CRPOSRANGE */ - 1, /* CLASS */ - 1, /* NCLASS */ - 1, /* XCLASS - variable length */ - 0, /* REF */ - 0, /* REFI */ - 0, /* DNREF */ - 0, /* DNREFI */ - 0, /* RECURSE */ - 0, /* CALLOUT */ - 0, /* CALLOUT_STR */ - 0, /* Alt */ - 0, /* Ket */ - 0, /* KetRmax */ - 0, /* KetRmin */ - 0, /* KetRpos */ - 0, /* Reverse */ - 0, /* Assert */ - 0, /* Assert not */ - 0, /* Assert behind */ - 0, /* Assert behind not */ - 0, /* NA assert */ - 0, /* NA assert behind */ - 0, /* ONCE */ - 0, /* SCRIPT_RUN */ - 0, 0, 0, 0, 0, /* BRA, BRAPOS, CBRA, CBRAPOS, COND */ - 0, 0, 0, 0, 0, /* SBRA, SBRAPOS, SCBRA, SCBRAPOS, SCOND */ - 0, 0, /* CREF, DNCREF */ - 0, 0, /* RREF, DNRREF */ - 0, 0, /* FALSE, TRUE */ - 0, 0, 0, /* BRAZERO, BRAMINZERO, BRAPOSZERO */ - 0, 0, 0, /* MARK, PRUNE, PRUNE_ARG */ - 0, 0, 0, 0, /* SKIP, SKIP_ARG, THEN, THEN_ARG */ - 0, 0, /* COMMIT, COMMIT_ARG */ - 0, 0, 0, /* FAIL, ACCEPT, ASSERT_ACCEPT */ - 0, 0, 0 /* CLOSE, SKIPZERO, DEFINE */ -}; - -/* These 2 tables allow for compact code for testing for \D, \d, \S, \s, \W, -and \w */ - -static const uint8_t toptable1[] = { - 0, 0, 0, 0, 0, 0, - ctype_digit, ctype_digit, - ctype_space, ctype_space, - ctype_word, ctype_word, - 0, 0 /* OP_ANY, OP_ALLANY */ -}; - -static const uint8_t toptable2[] = { - 0, 0, 0, 0, 0, 0, - ctype_digit, 0, - ctype_space, 0, - ctype_word, 0, - 1, 1 /* OP_ANY, OP_ALLANY */ -}; - - -/* Structure for holding data about a particular state, which is in effect the -current data for an active path through the match tree. It must consist -entirely of ints because the working vector we are passed, and which we put -these structures in, is a vector of ints. */ - -typedef struct stateblock { - int offset; /* Offset to opcode (-ve has meaning) */ - int count; /* Count for repeats */ - int data; /* Some use extra data */ -} stateblock; - -#define INTS_PER_STATEBLOCK (int)(sizeof(stateblock)/sizeof(int)) - - -/* Before version 10.32 the recursive calls of internal_dfa_match() were passed -local working space and output vectors that were created on the stack. This has -caused issues for some patterns, especially in small-stack environments such as -Windows. A new scheme is now in use which sets up a vector on the stack, but if -this is too small, heap memory is used, up to the heap_limit. The main -parameters are all numbers of ints because the workspace is a vector of ints. - -The size of the starting stack vector, DFA_START_RWS_SIZE, is in bytes, and is -defined in pcre2_internal.h so as to be available to pcre2test when it is -finding the minimum heap requirement for a match. */ - -#define OVEC_UNIT (sizeof(PCRE2_SIZE)/sizeof(int)) - -#define RWS_BASE_SIZE (DFA_START_RWS_SIZE/sizeof(int)) /* Stack vector */ -#define RWS_RSIZE 1000 /* Work size for recursion */ -#define RWS_OVEC_RSIZE (1000*OVEC_UNIT) /* Ovector for recursion */ -#define RWS_OVEC_OSIZE (2*OVEC_UNIT) /* Ovector in other cases */ - -/* This structure is at the start of each workspace block. */ - -typedef struct RWS_anchor { - struct RWS_anchor *next; - uint32_t size; /* Number of ints */ - uint32_t free; /* Number of ints */ -} RWS_anchor; - -#define RWS_ANCHOR_SIZE (sizeof(RWS_anchor)/sizeof(int)) - - - -/************************************************* -* Process a callout * -*************************************************/ - -/* This function is called to perform a callout. - -Arguments: - code current code pointer - offsets points to current capture offsets - current_subject start of current subject match - ptr current position in subject - mb the match block - extracode extra code offset when called from condition - lengthptr where to return the callout length - -Returns: the return from the callout -*/ - -static int -do_callout_dfa(PCRE2_SPTR code, PCRE2_SIZE *offsets, PCRE2_SPTR current_subject, - PCRE2_SPTR ptr, dfa_match_block *mb, PCRE2_SIZE extracode, - PCRE2_SIZE *lengthptr) -{ -pcre2_callout_block *cb = mb->cb; - -*lengthptr = (code[extracode] == OP_CALLOUT)? - (PCRE2_SIZE)PRIV(OP_lengths)[OP_CALLOUT] : - (PCRE2_SIZE)GET(code, 1 + 2*LINK_SIZE + extracode); - -if (mb->callout == NULL) return 0; /* No callout provided */ - -/* Fixed fields in the callout block are set once and for all at the start of -matching. */ - -cb->offset_vector = offsets; -cb->start_match = (PCRE2_SIZE)(current_subject - mb->start_subject); -cb->current_position = (PCRE2_SIZE)(ptr - mb->start_subject); -cb->pattern_position = GET(code, 1 + extracode); -cb->next_item_length = GET(code, 1 + LINK_SIZE + extracode); - -if (code[extracode] == OP_CALLOUT) - { - cb->callout_number = code[1 + 2*LINK_SIZE + extracode]; - cb->callout_string_offset = 0; - cb->callout_string = NULL; - cb->callout_string_length = 0; - } -else - { - cb->callout_number = 0; - cb->callout_string_offset = GET(code, 1 + 3*LINK_SIZE + extracode); - cb->callout_string = code + (1 + 4*LINK_SIZE + extracode) + 1; - cb->callout_string_length = *lengthptr - (1 + 4*LINK_SIZE) - 2; - } - -return (mb->callout)(cb, mb->callout_data); -} - - - -/************************************************* -* Expand local workspace memory * -*************************************************/ - -/* This function is called when internal_dfa_match() is about to be called -recursively and there is insufficient working space left in the current -workspace block. If there's an existing next block, use it; otherwise get a new -block unless the heap limit is reached. - -Arguments: - rwsptr pointer to block pointer (updated) - ovecsize space needed for an ovector - mb the match block - -Returns: 0 rwsptr has been updated - !0 an error code -*/ - -static int -more_workspace(RWS_anchor **rwsptr, unsigned int ovecsize, dfa_match_block *mb) -{ -RWS_anchor *rws = *rwsptr; -RWS_anchor *new; - -if (rws->next != NULL) - { - new = rws->next; - } - -/* Sizes in the RWS_anchor blocks are in units of sizeof(int), but -mb->heap_limit and mb->heap_used are in kibibytes. Play carefully, to avoid -overflow. */ - -else - { - uint32_t newsize = (rws->size >= UINT32_MAX/2)? UINT32_MAX/2 : rws->size * 2; - uint32_t newsizeK = newsize/(1024/sizeof(int)); - - if (newsizeK + mb->heap_used > mb->heap_limit) - newsizeK = (uint32_t)(mb->heap_limit - mb->heap_used); - newsize = newsizeK*(1024/sizeof(int)); - - if (newsize < RWS_RSIZE + ovecsize + RWS_ANCHOR_SIZE) - return PCRE2_ERROR_HEAPLIMIT; - new = mb->memctl.malloc(newsize*sizeof(int), mb->memctl.memory_data); - if (new == NULL) return PCRE2_ERROR_NOMEMORY; - mb->heap_used += newsizeK; - new->next = NULL; - new->size = newsize; - rws->next = new; - } - -new->free = new->size - RWS_ANCHOR_SIZE; -*rwsptr = new; -return 0; -} - - - -/************************************************* -* Match a Regular Expression - DFA engine * -*************************************************/ - -/* This internal function applies a compiled pattern to a subject string, -starting at a given point, using a DFA engine. This function is called from the -external one, possibly multiple times if the pattern is not anchored. The -function calls itself recursively for some kinds of subpattern. - -Arguments: - mb the match_data block with fixed information - this_start_code the opening bracket of this subexpression's code - current_subject where we currently are in the subject string - start_offset start offset in the subject string - offsets vector to contain the matching string offsets - offsetcount size of same - workspace vector of workspace - wscount size of same - rlevel function call recursion level - -Returns: > 0 => number of match offset pairs placed in offsets - = 0 => offsets overflowed; longest matches are present - -1 => failed to match - < -1 => some kind of unexpected problem - -The following macros are used for adding states to the two state vectors (one -for the current character, one for the following character). */ - -#define ADD_ACTIVE(x,y) \ - if (active_count++ < wscount) \ - { \ - next_active_state->offset = (x); \ - next_active_state->count = (y); \ - next_active_state++; \ - } \ - else return PCRE2_ERROR_DFA_WSSIZE - -#define ADD_ACTIVE_DATA(x,y,z) \ - if (active_count++ < wscount) \ - { \ - next_active_state->offset = (x); \ - next_active_state->count = (y); \ - next_active_state->data = (z); \ - next_active_state++; \ - } \ - else return PCRE2_ERROR_DFA_WSSIZE - -#define ADD_NEW(x,y) \ - if (new_count++ < wscount) \ - { \ - next_new_state->offset = (x); \ - next_new_state->count = (y); \ - next_new_state++; \ - } \ - else return PCRE2_ERROR_DFA_WSSIZE - -#define ADD_NEW_DATA(x,y,z) \ - if (new_count++ < wscount) \ - { \ - next_new_state->offset = (x); \ - next_new_state->count = (y); \ - next_new_state->data = (z); \ - next_new_state++; \ - } \ - else return PCRE2_ERROR_DFA_WSSIZE - -/* And now, here is the code */ - -static int -internal_dfa_match( - dfa_match_block *mb, - PCRE2_SPTR this_start_code, - PCRE2_SPTR current_subject, - PCRE2_SIZE start_offset, - PCRE2_SIZE *offsets, - uint32_t offsetcount, - int *workspace, - int wscount, - uint32_t rlevel, - int *RWS) -{ -stateblock *active_states, *new_states, *temp_states; -stateblock *next_active_state, *next_new_state; -const uint8_t *ctypes, *lcc, *fcc; -PCRE2_SPTR ptr; -PCRE2_SPTR end_code; -dfa_recursion_info new_recursive; -int active_count, new_count, match_count; - -/* Some fields in the mb block are frequently referenced, so we load them into -independent variables in the hope that this will perform better. */ - -PCRE2_SPTR start_subject = mb->start_subject; -PCRE2_SPTR end_subject = mb->end_subject; -PCRE2_SPTR start_code = mb->start_code; - -#ifdef SUPPORT_UNICODE -BOOL utf = (mb->poptions & PCRE2_UTF) != 0; -BOOL utf_or_ucp = utf || (mb->poptions & PCRE2_UCP) != 0; -#else -BOOL utf = FALSE; -#endif - -BOOL reset_could_continue = FALSE; - -if (mb->match_call_count++ >= mb->match_limit) return PCRE2_ERROR_MATCHLIMIT; -if (rlevel++ > mb->match_limit_depth) return PCRE2_ERROR_DEPTHLIMIT; -offsetcount &= (uint32_t)(-2); /* Round down */ - -wscount -= 2; -wscount = (wscount - (wscount % (INTS_PER_STATEBLOCK * 2))) / - (2 * INTS_PER_STATEBLOCK); - -ctypes = mb->tables + ctypes_offset; -lcc = mb->tables + lcc_offset; -fcc = mb->tables + fcc_offset; - -match_count = PCRE2_ERROR_NOMATCH; /* A negative number */ - -active_states = (stateblock *)(workspace + 2); -next_new_state = new_states = active_states + wscount; -new_count = 0; - -/* The first thing in any (sub) pattern is a bracket of some sort. Push all -the alternative states onto the list, and find out where the end is. This -makes is possible to use this function recursively, when we want to stop at a -matching internal ket rather than at the end. - -If we are dealing with a backward assertion we have to find out the maximum -amount to move back, and set up each alternative appropriately. */ - -if (*this_start_code == OP_ASSERTBACK || *this_start_code == OP_ASSERTBACK_NOT) - { - size_t max_back = 0; - size_t gone_back; - - end_code = this_start_code; - do - { - size_t back = (size_t)GET(end_code, 2+LINK_SIZE); - if (back > max_back) max_back = back; - end_code += GET(end_code, 1); - } - while (*end_code == OP_ALT); - - /* If we can't go back the amount required for the longest lookbehind - pattern, go back as far as we can; some alternatives may still be viable. */ - -#ifdef SUPPORT_UNICODE - /* In character mode we have to step back character by character */ - - if (utf) - { - for (gone_back = 0; gone_back < max_back; gone_back++) - { - if (current_subject <= start_subject) break; - current_subject--; - ACROSSCHAR(current_subject > start_subject, current_subject, - current_subject--); - } - } - else -#endif - - /* In byte-mode we can do this quickly. */ - - { - size_t current_offset = (size_t)(current_subject - start_subject); - gone_back = (current_offset < max_back)? current_offset : max_back; - current_subject -= gone_back; - } - - /* Save the earliest consulted character */ - - if (current_subject < mb->start_used_ptr) - mb->start_used_ptr = current_subject; - - /* Now we can process the individual branches. There will be an OP_REVERSE at - the start of each branch, except when the length of the branch is zero. */ - - end_code = this_start_code; - do - { - uint32_t revlen = (end_code[1+LINK_SIZE] == OP_REVERSE)? 1 + LINK_SIZE : 0; - size_t back = (revlen == 0)? 0 : (size_t)GET(end_code, 2+LINK_SIZE); - if (back <= gone_back) - { - int bstate = (int)(end_code - start_code + 1 + LINK_SIZE + revlen); - ADD_NEW_DATA(-bstate, 0, (int)(gone_back - back)); - } - end_code += GET(end_code, 1); - } - while (*end_code == OP_ALT); - } - -/* This is the code for a "normal" subpattern (not a backward assertion). The -start of a whole pattern is always one of these. If we are at the top level, -we may be asked to restart matching from the same point that we reached for a -previous partial match. We still have to scan through the top-level branches to -find the end state. */ - -else - { - end_code = this_start_code; - - /* Restarting */ - - if (rlevel == 1 && (mb->moptions & PCRE2_DFA_RESTART) != 0) - { - do { end_code += GET(end_code, 1); } while (*end_code == OP_ALT); - new_count = workspace[1]; - if (!workspace[0]) - memcpy(new_states, active_states, (size_t)new_count * sizeof(stateblock)); - } - - /* Not restarting */ - - else - { - int length = 1 + LINK_SIZE + - ((*this_start_code == OP_CBRA || *this_start_code == OP_SCBRA || - *this_start_code == OP_CBRAPOS || *this_start_code == OP_SCBRAPOS) - ? IMM2_SIZE:0); - do - { - ADD_NEW((int)(end_code - start_code + length), 0); - end_code += GET(end_code, 1); - length = 1 + LINK_SIZE; - } - while (*end_code == OP_ALT); - } - } - -workspace[0] = 0; /* Bit indicating which vector is current */ - -/* Loop for scanning the subject */ - -ptr = current_subject; -for (;;) - { - int i, j; - int clen, dlen; - uint32_t c, d; - int forced_fail = 0; - BOOL partial_newline = FALSE; - BOOL could_continue = reset_could_continue; - reset_could_continue = FALSE; - - if (ptr > mb->last_used_ptr) mb->last_used_ptr = ptr; - - /* Make the new state list into the active state list and empty the - new state list. */ - - temp_states = active_states; - active_states = new_states; - new_states = temp_states; - active_count = new_count; - new_count = 0; - - workspace[0] ^= 1; /* Remember for the restarting feature */ - workspace[1] = active_count; - - /* Set the pointers for adding new states */ - - next_active_state = active_states + active_count; - next_new_state = new_states; - - /* Load the current character from the subject outside the loop, as many - different states may want to look at it, and we assume that at least one - will. */ - - if (ptr < end_subject) - { - clen = 1; /* Number of data items in the character */ -#ifdef SUPPORT_UNICODE - GETCHARLENTEST(c, ptr, clen); -#else - c = *ptr; -#endif /* SUPPORT_UNICODE */ - } - else - { - clen = 0; /* This indicates the end of the subject */ - c = NOTACHAR; /* This value should never actually be used */ - } - - /* Scan up the active states and act on each one. The result of an action - may be to add more states to the currently active list (e.g. on hitting a - parenthesis) or it may be to put states on the new list, for considering - when we move the character pointer on. */ - - for (i = 0; i < active_count; i++) - { - stateblock *current_state = active_states + i; - BOOL caseless = FALSE; - PCRE2_SPTR code; - uint32_t codevalue; - int state_offset = current_state->offset; - int rrc; - int count; - - /* A negative offset is a special case meaning "hold off going to this - (negated) state until the number of characters in the data field have - been skipped". If the could_continue flag was passed over from a previous - state, arrange for it to passed on. */ - - if (state_offset < 0) - { - if (current_state->data > 0) - { - ADD_NEW_DATA(state_offset, current_state->count, - current_state->data - 1); - if (could_continue) reset_could_continue = TRUE; - continue; - } - else - { - current_state->offset = state_offset = -state_offset; - } - } - - /* Check for a duplicate state with the same count, and skip if found. - See the note at the head of this module about the possibility of improving - performance here. */ - - for (j = 0; j < i; j++) - { - if (active_states[j].offset == state_offset && - active_states[j].count == current_state->count) - goto NEXT_ACTIVE_STATE; - } - - /* The state offset is the offset to the opcode */ - - code = start_code + state_offset; - codevalue = *code; - - /* If this opcode inspects a character, but we are at the end of the - subject, remember the fact for use when testing for a partial match. */ - - if (clen == 0 && poptable[codevalue] != 0) - could_continue = TRUE; - - /* If this opcode is followed by an inline character, load it. It is - tempting to test for the presence of a subject character here, but that - is wrong, because sometimes zero repetitions of the subject are - permitted. - - We also use this mechanism for opcodes such as OP_TYPEPLUS that take an - argument that is not a data character - but is always one byte long because - the values are small. We have to take special action to deal with \P, \p, - \H, \h, \V, \v and \X in this case. To keep the other cases fast, convert - these ones to new opcodes. */ - - if (coptable[codevalue] > 0) - { - dlen = 1; -#ifdef SUPPORT_UNICODE - if (utf) { GETCHARLEN(d, (code + coptable[codevalue]), dlen); } else -#endif /* SUPPORT_UNICODE */ - d = code[coptable[codevalue]]; - if (codevalue >= OP_TYPESTAR) - { - switch(d) - { - case OP_ANYBYTE: return PCRE2_ERROR_DFA_UITEM; - case OP_NOTPROP: - case OP_PROP: codevalue += OP_PROP_EXTRA; break; - case OP_ANYNL: codevalue += OP_ANYNL_EXTRA; break; - case OP_EXTUNI: codevalue += OP_EXTUNI_EXTRA; break; - case OP_NOT_HSPACE: - case OP_HSPACE: codevalue += OP_HSPACE_EXTRA; break; - case OP_NOT_VSPACE: - case OP_VSPACE: codevalue += OP_VSPACE_EXTRA; break; - default: break; - } - } - } - else - { - dlen = 0; /* Not strictly necessary, but compilers moan */ - d = NOTACHAR; /* if these variables are not set. */ - } - - - /* Now process the individual opcodes */ - - switch (codevalue) - { -/* ========================================================================== */ - /* These cases are never obeyed. This is a fudge that causes a compile- - time error if the vectors coptable or poptable, which are indexed by - opcode, are not the correct length. It seems to be the only way to do - such a check at compile time, as the sizeof() operator does not work - in the C preprocessor. */ - - case OP_TABLE_LENGTH: - case OP_TABLE_LENGTH + - ((sizeof(coptable) == OP_TABLE_LENGTH) && - (sizeof(poptable) == OP_TABLE_LENGTH)): - return 0; - -/* ========================================================================== */ - /* Reached a closing bracket. If not at the end of the pattern, carry - on with the next opcode. For repeating opcodes, also add the repeat - state. Note that KETRPOS will always be encountered at the end of the - subpattern, because the possessive subpattern repeats are always handled - using recursive calls. Thus, it never adds any new states. - - At the end of the (sub)pattern, unless we have an empty string and - PCRE2_NOTEMPTY is set, or PCRE2_NOTEMPTY_ATSTART is set and we are at the - start of the subject, save the match data, shifting up all previous - matches so we always have the longest first. */ - - case OP_KET: - case OP_KETRMIN: - case OP_KETRMAX: - case OP_KETRPOS: - if (code != end_code) - { - ADD_ACTIVE(state_offset + 1 + LINK_SIZE, 0); - if (codevalue != OP_KET) - { - ADD_ACTIVE(state_offset - (int)GET(code, 1), 0); - } - } - else - { - if (ptr > current_subject || - ((mb->moptions & PCRE2_NOTEMPTY) == 0 && - ((mb->moptions & PCRE2_NOTEMPTY_ATSTART) == 0 || - current_subject > start_subject + mb->start_offset))) - { - if (match_count < 0) match_count = (offsetcount >= 2)? 1 : 0; - else if (match_count > 0 && ++match_count * 2 > (int)offsetcount) - match_count = 0; - count = ((match_count == 0)? (int)offsetcount : match_count * 2) - 2; - if (count > 0) (void)memmove(offsets + 2, offsets, - (size_t)count * sizeof(PCRE2_SIZE)); - if (offsetcount >= 2) - { - offsets[0] = (PCRE2_SIZE)(current_subject - start_subject); - offsets[1] = (PCRE2_SIZE)(ptr - start_subject); - } - if ((mb->moptions & PCRE2_DFA_SHORTEST) != 0) return match_count; - } - } - break; - -/* ========================================================================== */ - /* These opcodes add to the current list of states without looking - at the current character. */ - - /*-----------------------------------------------------------------*/ - case OP_ALT: - do { code += GET(code, 1); } while (*code == OP_ALT); - ADD_ACTIVE((int)(code - start_code), 0); - break; - - /*-----------------------------------------------------------------*/ - case OP_BRA: - case OP_SBRA: - do - { - ADD_ACTIVE((int)(code - start_code + 1 + LINK_SIZE), 0); - code += GET(code, 1); - } - while (*code == OP_ALT); - break; - - /*-----------------------------------------------------------------*/ - case OP_CBRA: - case OP_SCBRA: - ADD_ACTIVE((int)(code - start_code + 1 + LINK_SIZE + IMM2_SIZE), 0); - code += GET(code, 1); - while (*code == OP_ALT) - { - ADD_ACTIVE((int)(code - start_code + 1 + LINK_SIZE), 0); - code += GET(code, 1); - } - break; - - /*-----------------------------------------------------------------*/ - case OP_BRAZERO: - case OP_BRAMINZERO: - ADD_ACTIVE(state_offset + 1, 0); - code += 1 + GET(code, 2); - while (*code == OP_ALT) code += GET(code, 1); - ADD_ACTIVE((int)(code - start_code + 1 + LINK_SIZE), 0); - break; - - /*-----------------------------------------------------------------*/ - case OP_SKIPZERO: - code += 1 + GET(code, 2); - while (*code == OP_ALT) code += GET(code, 1); - ADD_ACTIVE((int)(code - start_code + 1 + LINK_SIZE), 0); - break; - - /*-----------------------------------------------------------------*/ - case OP_CIRC: - if (ptr == start_subject && (mb->moptions & PCRE2_NOTBOL) == 0) - { ADD_ACTIVE(state_offset + 1, 0); } - break; - - /*-----------------------------------------------------------------*/ - case OP_CIRCM: - if ((ptr == start_subject && (mb->moptions & PCRE2_NOTBOL) == 0) || - ((ptr != end_subject || (mb->poptions & PCRE2_ALT_CIRCUMFLEX) != 0 ) - && WAS_NEWLINE(ptr))) - { ADD_ACTIVE(state_offset + 1, 0); } - break; - - /*-----------------------------------------------------------------*/ - case OP_EOD: - if (ptr >= end_subject) - { - if ((mb->moptions & PCRE2_PARTIAL_HARD) != 0) - return PCRE2_ERROR_PARTIAL; - else { ADD_ACTIVE(state_offset + 1, 0); } - } - break; - - /*-----------------------------------------------------------------*/ - case OP_SOD: - if (ptr == start_subject) { ADD_ACTIVE(state_offset + 1, 0); } - break; - - /*-----------------------------------------------------------------*/ - case OP_SOM: - if (ptr == start_subject + start_offset) { ADD_ACTIVE(state_offset + 1, 0); } - break; - - -/* ========================================================================== */ - /* These opcodes inspect the next subject character, and sometimes - the previous one as well, but do not have an argument. The variable - clen contains the length of the current character and is zero if we are - at the end of the subject. */ - - /*-----------------------------------------------------------------*/ - case OP_ANY: - if (clen > 0 && !IS_NEWLINE(ptr)) - { - if (ptr + 1 >= mb->end_subject && - (mb->moptions & (PCRE2_PARTIAL_HARD)) != 0 && - NLBLOCK->nltype == NLTYPE_FIXED && - NLBLOCK->nllen == 2 && - c == NLBLOCK->nl[0]) - { - could_continue = partial_newline = TRUE; - } - else - { - ADD_NEW(state_offset + 1, 0); - } - } - break; - - /*-----------------------------------------------------------------*/ - case OP_ALLANY: - if (clen > 0) - { ADD_NEW(state_offset + 1, 0); } - break; - - /*-----------------------------------------------------------------*/ - case OP_EODN: - if (clen == 0 || (IS_NEWLINE(ptr) && ptr == end_subject - mb->nllen)) - { - if ((mb->moptions & PCRE2_PARTIAL_HARD) != 0) - return PCRE2_ERROR_PARTIAL; - ADD_ACTIVE(state_offset + 1, 0); - } - break; - - /*-----------------------------------------------------------------*/ - case OP_DOLL: - if ((mb->moptions & PCRE2_NOTEOL) == 0) - { - if (clen == 0 && (mb->moptions & PCRE2_PARTIAL_HARD) != 0) - could_continue = TRUE; - else if (clen == 0 || - ((mb->poptions & PCRE2_DOLLAR_ENDONLY) == 0 && IS_NEWLINE(ptr) && - (ptr == end_subject - mb->nllen) - )) - { ADD_ACTIVE(state_offset + 1, 0); } - else if (ptr + 1 >= mb->end_subject && - (mb->moptions & (PCRE2_PARTIAL_HARD|PCRE2_PARTIAL_SOFT)) != 0 && - NLBLOCK->nltype == NLTYPE_FIXED && - NLBLOCK->nllen == 2 && - c == NLBLOCK->nl[0]) - { - if ((mb->moptions & PCRE2_PARTIAL_HARD) != 0) - { - reset_could_continue = TRUE; - ADD_NEW_DATA(-(state_offset + 1), 0, 1); - } - else could_continue = partial_newline = TRUE; - } - } - break; - - /*-----------------------------------------------------------------*/ - case OP_DOLLM: - if ((mb->moptions & PCRE2_NOTEOL) == 0) - { - if (clen == 0 && (mb->moptions & PCRE2_PARTIAL_HARD) != 0) - could_continue = TRUE; - else if (clen == 0 || - ((mb->poptions & PCRE2_DOLLAR_ENDONLY) == 0 && IS_NEWLINE(ptr))) - { ADD_ACTIVE(state_offset + 1, 0); } - else if (ptr + 1 >= mb->end_subject && - (mb->moptions & (PCRE2_PARTIAL_HARD|PCRE2_PARTIAL_SOFT)) != 0 && - NLBLOCK->nltype == NLTYPE_FIXED && - NLBLOCK->nllen == 2 && - c == NLBLOCK->nl[0]) - { - if ((mb->moptions & PCRE2_PARTIAL_HARD) != 0) - { - reset_could_continue = TRUE; - ADD_NEW_DATA(-(state_offset + 1), 0, 1); - } - else could_continue = partial_newline = TRUE; - } - } - else if (IS_NEWLINE(ptr)) - { ADD_ACTIVE(state_offset + 1, 0); } - break; - - /*-----------------------------------------------------------------*/ - - case OP_DIGIT: - case OP_WHITESPACE: - case OP_WORDCHAR: - if (clen > 0 && c < 256 && - ((ctypes[c] & toptable1[codevalue]) ^ toptable2[codevalue]) != 0) - { ADD_NEW(state_offset + 1, 0); } - break; - - /*-----------------------------------------------------------------*/ - case OP_NOT_DIGIT: - case OP_NOT_WHITESPACE: - case OP_NOT_WORDCHAR: - if (clen > 0 && (c >= 256 || - ((ctypes[c] & toptable1[codevalue]) ^ toptable2[codevalue]) != 0)) - { ADD_NEW(state_offset + 1, 0); } - break; - - /*-----------------------------------------------------------------*/ - case OP_WORD_BOUNDARY: - case OP_NOT_WORD_BOUNDARY: - { - int left_word, right_word; - - if (ptr > start_subject) - { - PCRE2_SPTR temp = ptr - 1; - if (temp < mb->start_used_ptr) mb->start_used_ptr = temp; -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 - if (utf) { BACKCHAR(temp); } -#endif - GETCHARTEST(d, temp); -#ifdef SUPPORT_UNICODE - if ((mb->poptions & PCRE2_UCP) != 0) - { - if (d == '_') left_word = TRUE; else - { - uint32_t cat = UCD_CATEGORY(d); - left_word = (cat == ucp_L || cat == ucp_N); - } - } - else -#endif - left_word = d < 256 && (ctypes[d] & ctype_word) != 0; - } - else left_word = FALSE; - - if (clen > 0) - { - if (ptr >= mb->last_used_ptr) - { - PCRE2_SPTR temp = ptr + 1; -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 - if (utf) { FORWARDCHARTEST(temp, mb->end_subject); } -#endif - mb->last_used_ptr = temp; - } -#ifdef SUPPORT_UNICODE - if ((mb->poptions & PCRE2_UCP) != 0) - { - if (c == '_') right_word = TRUE; else - { - uint32_t cat = UCD_CATEGORY(c); - right_word = (cat == ucp_L || cat == ucp_N); - } - } - else -#endif - right_word = c < 256 && (ctypes[c] & ctype_word) != 0; - } - else right_word = FALSE; - - if ((left_word == right_word) == (codevalue == OP_NOT_WORD_BOUNDARY)) - { ADD_ACTIVE(state_offset + 1, 0); } - } - break; - - - /*-----------------------------------------------------------------*/ - /* Check the next character by Unicode property. We will get here only - if the support is in the binary; otherwise a compile-time error occurs. - */ - -#ifdef SUPPORT_UNICODE - case OP_PROP: - case OP_NOTPROP: - if (clen > 0) - { - BOOL OK; - const uint32_t *cp; - const ucd_record * prop = GET_UCD(c); - switch(code[1]) - { - case PT_ANY: - OK = TRUE; - break; - - case PT_LAMP: - OK = prop->chartype == ucp_Lu || prop->chartype == ucp_Ll || - prop->chartype == ucp_Lt; - break; - - case PT_GC: - OK = PRIV(ucp_gentype)[prop->chartype] == code[2]; - break; - - case PT_PC: - OK = prop->chartype == code[2]; - break; - - case PT_SC: - OK = prop->script == code[2]; - break; - - case PT_SCX: - OK = (prop->script == code[2] || - MAPBIT(PRIV(ucd_script_sets) + UCD_SCRIPTX_PROP(prop), code[2]) != 0); - break; - - /* These are specials for combination cases. */ - - case PT_ALNUM: - OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L || - PRIV(ucp_gentype)[prop->chartype] == ucp_N; - break; - - /* Perl space used to exclude VT, but from Perl 5.18 it is included, - which means that Perl space and POSIX space are now identical. PCRE - was changed at release 8.34. */ - - case PT_SPACE: /* Perl space */ - case PT_PXSPACE: /* POSIX space */ - switch(c) - { - HSPACE_CASES: - VSPACE_CASES: - OK = TRUE; - break; - - default: - OK = PRIV(ucp_gentype)[prop->chartype] == ucp_Z; - break; - } - break; - - case PT_WORD: - OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L || - PRIV(ucp_gentype)[prop->chartype] == ucp_N || - c == CHAR_UNDERSCORE; - break; - - case PT_CLIST: - cp = PRIV(ucd_caseless_sets) + code[2]; - for (;;) - { - if (c < *cp) { OK = FALSE; break; } - if (c == *cp++) { OK = TRUE; break; } - } - break; - - case PT_UCNC: - OK = c == CHAR_DOLLAR_SIGN || c == CHAR_COMMERCIAL_AT || - c == CHAR_GRAVE_ACCENT || (c >= 0xa0 && c <= 0xd7ff) || - c >= 0xe000; - break; - - case PT_BIDICL: - OK = UCD_BIDICLASS(c) == code[2]; - break; - - case PT_BOOL: - OK = MAPBIT(PRIV(ucd_boolprop_sets) + - UCD_BPROPS_PROP(prop), code[2]) != 0; - break; - - /* Should never occur, but keep compilers from grumbling. */ - - default: - OK = codevalue != OP_PROP; - break; - } - - if (OK == (codevalue == OP_PROP)) { ADD_NEW(state_offset + 3, 0); } - } - break; -#endif - - - -/* ========================================================================== */ - /* These opcodes likewise inspect the subject character, but have an - argument that is not a data character. It is one of these opcodes: - OP_ANY, OP_ALLANY, OP_DIGIT, OP_NOT_DIGIT, OP_WHITESPACE, OP_NOT_SPACE, - OP_WORDCHAR, OP_NOT_WORDCHAR. The value is loaded into d. */ - - case OP_TYPEPLUS: - case OP_TYPEMINPLUS: - case OP_TYPEPOSPLUS: - count = current_state->count; /* Already matched */ - if (count > 0) { ADD_ACTIVE(state_offset + 2, 0); } - if (clen > 0) - { - if (d == OP_ANY && ptr + 1 >= mb->end_subject && - (mb->moptions & (PCRE2_PARTIAL_HARD)) != 0 && - NLBLOCK->nltype == NLTYPE_FIXED && - NLBLOCK->nllen == 2 && - c == NLBLOCK->nl[0]) - { - could_continue = partial_newline = TRUE; - } - else if ((c >= 256 && d != OP_DIGIT && d != OP_WHITESPACE && d != OP_WORDCHAR) || - (c < 256 && - (d != OP_ANY || !IS_NEWLINE(ptr)) && - ((ctypes[c] & toptable1[d]) ^ toptable2[d]) != 0)) - { - if (count > 0 && codevalue == OP_TYPEPOSPLUS) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - count++; - ADD_NEW(state_offset, count); - } - } - break; - - /*-----------------------------------------------------------------*/ - case OP_TYPEQUERY: - case OP_TYPEMINQUERY: - case OP_TYPEPOSQUERY: - ADD_ACTIVE(state_offset + 2, 0); - if (clen > 0) - { - if (d == OP_ANY && ptr + 1 >= mb->end_subject && - (mb->moptions & (PCRE2_PARTIAL_HARD)) != 0 && - NLBLOCK->nltype == NLTYPE_FIXED && - NLBLOCK->nllen == 2 && - c == NLBLOCK->nl[0]) - { - could_continue = partial_newline = TRUE; - } - else if ((c >= 256 && d != OP_DIGIT && d != OP_WHITESPACE && d != OP_WORDCHAR) || - (c < 256 && - (d != OP_ANY || !IS_NEWLINE(ptr)) && - ((ctypes[c] & toptable1[d]) ^ toptable2[d]) != 0)) - { - if (codevalue == OP_TYPEPOSQUERY) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - ADD_NEW(state_offset + 2, 0); - } - } - break; - - /*-----------------------------------------------------------------*/ - case OP_TYPESTAR: - case OP_TYPEMINSTAR: - case OP_TYPEPOSSTAR: - ADD_ACTIVE(state_offset + 2, 0); - if (clen > 0) - { - if (d == OP_ANY && ptr + 1 >= mb->end_subject && - (mb->moptions & (PCRE2_PARTIAL_HARD)) != 0 && - NLBLOCK->nltype == NLTYPE_FIXED && - NLBLOCK->nllen == 2 && - c == NLBLOCK->nl[0]) - { - could_continue = partial_newline = TRUE; - } - else if ((c >= 256 && d != OP_DIGIT && d != OP_WHITESPACE && d != OP_WORDCHAR) || - (c < 256 && - (d != OP_ANY || !IS_NEWLINE(ptr)) && - ((ctypes[c] & toptable1[d]) ^ toptable2[d]) != 0)) - { - if (codevalue == OP_TYPEPOSSTAR) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - ADD_NEW(state_offset, 0); - } - } - break; - - /*-----------------------------------------------------------------*/ - case OP_TYPEEXACT: - count = current_state->count; /* Number already matched */ - if (clen > 0) - { - if (d == OP_ANY && ptr + 1 >= mb->end_subject && - (mb->moptions & (PCRE2_PARTIAL_HARD)) != 0 && - NLBLOCK->nltype == NLTYPE_FIXED && - NLBLOCK->nllen == 2 && - c == NLBLOCK->nl[0]) - { - could_continue = partial_newline = TRUE; - } - else if ((c >= 256 && d != OP_DIGIT && d != OP_WHITESPACE && d != OP_WORDCHAR) || - (c < 256 && - (d != OP_ANY || !IS_NEWLINE(ptr)) && - ((ctypes[c] & toptable1[d]) ^ toptable2[d]) != 0)) - { - if (++count >= (int)GET2(code, 1)) - { ADD_NEW(state_offset + 1 + IMM2_SIZE + 1, 0); } - else - { ADD_NEW(state_offset, count); } - } - } - break; - - /*-----------------------------------------------------------------*/ - case OP_TYPEUPTO: - case OP_TYPEMINUPTO: - case OP_TYPEPOSUPTO: - ADD_ACTIVE(state_offset + 2 + IMM2_SIZE, 0); - count = current_state->count; /* Number already matched */ - if (clen > 0) - { - if (d == OP_ANY && ptr + 1 >= mb->end_subject && - (mb->moptions & (PCRE2_PARTIAL_HARD)) != 0 && - NLBLOCK->nltype == NLTYPE_FIXED && - NLBLOCK->nllen == 2 && - c == NLBLOCK->nl[0]) - { - could_continue = partial_newline = TRUE; - } - else if ((c >= 256 && d != OP_DIGIT && d != OP_WHITESPACE && d != OP_WORDCHAR) || - (c < 256 && - (d != OP_ANY || !IS_NEWLINE(ptr)) && - ((ctypes[c] & toptable1[d]) ^ toptable2[d]) != 0)) - { - if (codevalue == OP_TYPEPOSUPTO) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - if (++count >= (int)GET2(code, 1)) - { ADD_NEW(state_offset + 2 + IMM2_SIZE, 0); } - else - { ADD_NEW(state_offset, count); } - } - } - break; - -/* ========================================================================== */ - /* These are virtual opcodes that are used when something like - OP_TYPEPLUS has OP_PROP, OP_NOTPROP, OP_ANYNL, or OP_EXTUNI as its - argument. It keeps the code above fast for the other cases. The argument - is in the d variable. */ - -#ifdef SUPPORT_UNICODE - case OP_PROP_EXTRA + OP_TYPEPLUS: - case OP_PROP_EXTRA + OP_TYPEMINPLUS: - case OP_PROP_EXTRA + OP_TYPEPOSPLUS: - count = current_state->count; /* Already matched */ - if (count > 0) { ADD_ACTIVE(state_offset + 4, 0); } - if (clen > 0) - { - BOOL OK; - const uint32_t *cp; - const ucd_record * prop = GET_UCD(c); - switch(code[2]) - { - case PT_ANY: - OK = TRUE; - break; - - case PT_LAMP: - OK = prop->chartype == ucp_Lu || prop->chartype == ucp_Ll || - prop->chartype == ucp_Lt; - break; - - case PT_GC: - OK = PRIV(ucp_gentype)[prop->chartype] == code[3]; - break; - - case PT_PC: - OK = prop->chartype == code[3]; - break; - - case PT_SC: - OK = prop->script == code[3]; - break; - - case PT_SCX: - OK = (prop->script == code[3] || - MAPBIT(PRIV(ucd_script_sets) + UCD_SCRIPTX_PROP(prop), code[3]) != 0); - break; - - /* These are specials for combination cases. */ - - case PT_ALNUM: - OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L || - PRIV(ucp_gentype)[prop->chartype] == ucp_N; - break; - - /* Perl space used to exclude VT, but from Perl 5.18 it is included, - which means that Perl space and POSIX space are now identical. PCRE - was changed at release 8.34. */ - - case PT_SPACE: /* Perl space */ - case PT_PXSPACE: /* POSIX space */ - switch(c) - { - HSPACE_CASES: - VSPACE_CASES: - OK = TRUE; - break; - - default: - OK = PRIV(ucp_gentype)[prop->chartype] == ucp_Z; - break; - } - break; - - case PT_WORD: - OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L || - PRIV(ucp_gentype)[prop->chartype] == ucp_N || - c == CHAR_UNDERSCORE; - break; - - case PT_CLIST: - cp = PRIV(ucd_caseless_sets) + code[3]; - for (;;) - { - if (c < *cp) { OK = FALSE; break; } - if (c == *cp++) { OK = TRUE; break; } - } - break; - - case PT_UCNC: - OK = c == CHAR_DOLLAR_SIGN || c == CHAR_COMMERCIAL_AT || - c == CHAR_GRAVE_ACCENT || (c >= 0xa0 && c <= 0xd7ff) || - c >= 0xe000; - break; - - case PT_BIDICL: - OK = UCD_BIDICLASS(c) == code[3]; - break; - - case PT_BOOL: - OK = MAPBIT(PRIV(ucd_boolprop_sets) + - UCD_BPROPS_PROP(prop), code[3]) != 0; - break; - - /* Should never occur, but keep compilers from grumbling. */ - - default: - OK = codevalue != OP_PROP; - break; - } - - if (OK == (d == OP_PROP)) - { - if (count > 0 && codevalue == OP_PROP_EXTRA + OP_TYPEPOSPLUS) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - count++; - ADD_NEW(state_offset, count); - } - } - break; - - /*-----------------------------------------------------------------*/ - case OP_EXTUNI_EXTRA + OP_TYPEPLUS: - case OP_EXTUNI_EXTRA + OP_TYPEMINPLUS: - case OP_EXTUNI_EXTRA + OP_TYPEPOSPLUS: - count = current_state->count; /* Already matched */ - if (count > 0) { ADD_ACTIVE(state_offset + 2, 0); } - if (clen > 0) - { - int ncount = 0; - if (count > 0 && codevalue == OP_EXTUNI_EXTRA + OP_TYPEPOSPLUS) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - (void)PRIV(extuni)(c, ptr + clen, mb->start_subject, end_subject, utf, - &ncount); - count++; - ADD_NEW_DATA(-state_offset, count, ncount); - } - break; -#endif - - /*-----------------------------------------------------------------*/ - case OP_ANYNL_EXTRA + OP_TYPEPLUS: - case OP_ANYNL_EXTRA + OP_TYPEMINPLUS: - case OP_ANYNL_EXTRA + OP_TYPEPOSPLUS: - count = current_state->count; /* Already matched */ - if (count > 0) { ADD_ACTIVE(state_offset + 2, 0); } - if (clen > 0) - { - int ncount = 0; - switch (c) - { - case CHAR_VT: - case CHAR_FF: - case CHAR_NEL: -#ifndef EBCDIC - case 0x2028: - case 0x2029: -#endif /* Not EBCDIC */ - if (mb->bsr_convention == PCRE2_BSR_ANYCRLF) break; - goto ANYNL01; - - case CHAR_CR: - if (ptr + 1 < end_subject && UCHAR21TEST(ptr + 1) == CHAR_LF) ncount = 1; - /* Fall through */ - - ANYNL01: - case CHAR_LF: - if (count > 0 && codevalue == OP_ANYNL_EXTRA + OP_TYPEPOSPLUS) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - count++; - ADD_NEW_DATA(-state_offset, count, ncount); - break; - - default: - break; - } - } - break; - - /*-----------------------------------------------------------------*/ - case OP_VSPACE_EXTRA + OP_TYPEPLUS: - case OP_VSPACE_EXTRA + OP_TYPEMINPLUS: - case OP_VSPACE_EXTRA + OP_TYPEPOSPLUS: - count = current_state->count; /* Already matched */ - if (count > 0) { ADD_ACTIVE(state_offset + 2, 0); } - if (clen > 0) - { - BOOL OK; - switch (c) - { - VSPACE_CASES: - OK = TRUE; - break; - - default: - OK = FALSE; - break; - } - - if (OK == (d == OP_VSPACE)) - { - if (count > 0 && codevalue == OP_VSPACE_EXTRA + OP_TYPEPOSPLUS) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - count++; - ADD_NEW_DATA(-state_offset, count, 0); - } - } - break; - - /*-----------------------------------------------------------------*/ - case OP_HSPACE_EXTRA + OP_TYPEPLUS: - case OP_HSPACE_EXTRA + OP_TYPEMINPLUS: - case OP_HSPACE_EXTRA + OP_TYPEPOSPLUS: - count = current_state->count; /* Already matched */ - if (count > 0) { ADD_ACTIVE(state_offset + 2, 0); } - if (clen > 0) - { - BOOL OK; - switch (c) - { - HSPACE_CASES: - OK = TRUE; - break; - - default: - OK = FALSE; - break; - } - - if (OK == (d == OP_HSPACE)) - { - if (count > 0 && codevalue == OP_HSPACE_EXTRA + OP_TYPEPOSPLUS) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - count++; - ADD_NEW_DATA(-state_offset, count, 0); - } - } - break; - - /*-----------------------------------------------------------------*/ -#ifdef SUPPORT_UNICODE - case OP_PROP_EXTRA + OP_TYPEQUERY: - case OP_PROP_EXTRA + OP_TYPEMINQUERY: - case OP_PROP_EXTRA + OP_TYPEPOSQUERY: - count = 4; - goto QS1; - - case OP_PROP_EXTRA + OP_TYPESTAR: - case OP_PROP_EXTRA + OP_TYPEMINSTAR: - case OP_PROP_EXTRA + OP_TYPEPOSSTAR: - count = 0; - - QS1: - - ADD_ACTIVE(state_offset + 4, 0); - if (clen > 0) - { - BOOL OK; - const uint32_t *cp; - const ucd_record * prop = GET_UCD(c); - switch(code[2]) - { - case PT_ANY: - OK = TRUE; - break; - - case PT_LAMP: - OK = prop->chartype == ucp_Lu || prop->chartype == ucp_Ll || - prop->chartype == ucp_Lt; - break; - - case PT_GC: - OK = PRIV(ucp_gentype)[prop->chartype] == code[3]; - break; - - case PT_PC: - OK = prop->chartype == code[3]; - break; - - case PT_SC: - OK = prop->script == code[3]; - break; - - case PT_SCX: - OK = (prop->script == code[3] || - MAPBIT(PRIV(ucd_script_sets) + UCD_SCRIPTX_PROP(prop), code[3]) != 0); - break; - - /* These are specials for combination cases. */ - - case PT_ALNUM: - OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L || - PRIV(ucp_gentype)[prop->chartype] == ucp_N; - break; - - /* Perl space used to exclude VT, but from Perl 5.18 it is included, - which means that Perl space and POSIX space are now identical. PCRE - was changed at release 8.34. */ - - case PT_SPACE: /* Perl space */ - case PT_PXSPACE: /* POSIX space */ - switch(c) - { - HSPACE_CASES: - VSPACE_CASES: - OK = TRUE; - break; - - default: - OK = PRIV(ucp_gentype)[prop->chartype] == ucp_Z; - break; - } - break; - - case PT_WORD: - OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L || - PRIV(ucp_gentype)[prop->chartype] == ucp_N || - c == CHAR_UNDERSCORE; - break; - - case PT_CLIST: - cp = PRIV(ucd_caseless_sets) + code[3]; - for (;;) - { - if (c < *cp) { OK = FALSE; break; } - if (c == *cp++) { OK = TRUE; break; } - } - break; - - case PT_UCNC: - OK = c == CHAR_DOLLAR_SIGN || c == CHAR_COMMERCIAL_AT || - c == CHAR_GRAVE_ACCENT || (c >= 0xa0 && c <= 0xd7ff) || - c >= 0xe000; - break; - - case PT_BIDICL: - OK = UCD_BIDICLASS(c) == code[3]; - break; - - case PT_BOOL: - OK = MAPBIT(PRIV(ucd_boolprop_sets) + - UCD_BPROPS_PROP(prop), code[3]) != 0; - break; - - /* Should never occur, but keep compilers from grumbling. */ - - default: - OK = codevalue != OP_PROP; - break; - } - - if (OK == (d == OP_PROP)) - { - if (codevalue == OP_PROP_EXTRA + OP_TYPEPOSSTAR || - codevalue == OP_PROP_EXTRA + OP_TYPEPOSQUERY) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - ADD_NEW(state_offset + count, 0); - } - } - break; - - /*-----------------------------------------------------------------*/ - case OP_EXTUNI_EXTRA + OP_TYPEQUERY: - case OP_EXTUNI_EXTRA + OP_TYPEMINQUERY: - case OP_EXTUNI_EXTRA + OP_TYPEPOSQUERY: - count = 2; - goto QS2; - - case OP_EXTUNI_EXTRA + OP_TYPESTAR: - case OP_EXTUNI_EXTRA + OP_TYPEMINSTAR: - case OP_EXTUNI_EXTRA + OP_TYPEPOSSTAR: - count = 0; - - QS2: - - ADD_ACTIVE(state_offset + 2, 0); - if (clen > 0) - { - int ncount = 0; - if (codevalue == OP_EXTUNI_EXTRA + OP_TYPEPOSSTAR || - codevalue == OP_EXTUNI_EXTRA + OP_TYPEPOSQUERY) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - (void)PRIV(extuni)(c, ptr + clen, mb->start_subject, end_subject, utf, - &ncount); - ADD_NEW_DATA(-(state_offset + count), 0, ncount); - } - break; -#endif - - /*-----------------------------------------------------------------*/ - case OP_ANYNL_EXTRA + OP_TYPEQUERY: - case OP_ANYNL_EXTRA + OP_TYPEMINQUERY: - case OP_ANYNL_EXTRA + OP_TYPEPOSQUERY: - count = 2; - goto QS3; - - case OP_ANYNL_EXTRA + OP_TYPESTAR: - case OP_ANYNL_EXTRA + OP_TYPEMINSTAR: - case OP_ANYNL_EXTRA + OP_TYPEPOSSTAR: - count = 0; - - QS3: - ADD_ACTIVE(state_offset + 2, 0); - if (clen > 0) - { - int ncount = 0; - switch (c) - { - case CHAR_VT: - case CHAR_FF: - case CHAR_NEL: -#ifndef EBCDIC - case 0x2028: - case 0x2029: -#endif /* Not EBCDIC */ - if (mb->bsr_convention == PCRE2_BSR_ANYCRLF) break; - goto ANYNL02; - - case CHAR_CR: - if (ptr + 1 < end_subject && UCHAR21TEST(ptr + 1) == CHAR_LF) ncount = 1; - /* Fall through */ - - ANYNL02: - case CHAR_LF: - if (codevalue == OP_ANYNL_EXTRA + OP_TYPEPOSSTAR || - codevalue == OP_ANYNL_EXTRA + OP_TYPEPOSQUERY) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - ADD_NEW_DATA(-(state_offset + (int)count), 0, ncount); - break; - - default: - break; - } - } - break; - - /*-----------------------------------------------------------------*/ - case OP_VSPACE_EXTRA + OP_TYPEQUERY: - case OP_VSPACE_EXTRA + OP_TYPEMINQUERY: - case OP_VSPACE_EXTRA + OP_TYPEPOSQUERY: - count = 2; - goto QS4; - - case OP_VSPACE_EXTRA + OP_TYPESTAR: - case OP_VSPACE_EXTRA + OP_TYPEMINSTAR: - case OP_VSPACE_EXTRA + OP_TYPEPOSSTAR: - count = 0; - - QS4: - ADD_ACTIVE(state_offset + 2, 0); - if (clen > 0) - { - BOOL OK; - switch (c) - { - VSPACE_CASES: - OK = TRUE; - break; - - default: - OK = FALSE; - break; - } - if (OK == (d == OP_VSPACE)) - { - if (codevalue == OP_VSPACE_EXTRA + OP_TYPEPOSSTAR || - codevalue == OP_VSPACE_EXTRA + OP_TYPEPOSQUERY) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - ADD_NEW_DATA(-(state_offset + (int)count), 0, 0); - } - } - break; - - /*-----------------------------------------------------------------*/ - case OP_HSPACE_EXTRA + OP_TYPEQUERY: - case OP_HSPACE_EXTRA + OP_TYPEMINQUERY: - case OP_HSPACE_EXTRA + OP_TYPEPOSQUERY: - count = 2; - goto QS5; - - case OP_HSPACE_EXTRA + OP_TYPESTAR: - case OP_HSPACE_EXTRA + OP_TYPEMINSTAR: - case OP_HSPACE_EXTRA + OP_TYPEPOSSTAR: - count = 0; - - QS5: - ADD_ACTIVE(state_offset + 2, 0); - if (clen > 0) - { - BOOL OK; - switch (c) - { - HSPACE_CASES: - OK = TRUE; - break; - - default: - OK = FALSE; - break; - } - - if (OK == (d == OP_HSPACE)) - { - if (codevalue == OP_HSPACE_EXTRA + OP_TYPEPOSSTAR || - codevalue == OP_HSPACE_EXTRA + OP_TYPEPOSQUERY) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - ADD_NEW_DATA(-(state_offset + (int)count), 0, 0); - } - } - break; - - /*-----------------------------------------------------------------*/ -#ifdef SUPPORT_UNICODE - case OP_PROP_EXTRA + OP_TYPEEXACT: - case OP_PROP_EXTRA + OP_TYPEUPTO: - case OP_PROP_EXTRA + OP_TYPEMINUPTO: - case OP_PROP_EXTRA + OP_TYPEPOSUPTO: - if (codevalue != OP_PROP_EXTRA + OP_TYPEEXACT) - { ADD_ACTIVE(state_offset + 1 + IMM2_SIZE + 3, 0); } - count = current_state->count; /* Number already matched */ - if (clen > 0) - { - BOOL OK; - const uint32_t *cp; - const ucd_record * prop = GET_UCD(c); - switch(code[1 + IMM2_SIZE + 1]) - { - case PT_ANY: - OK = TRUE; - break; - - case PT_LAMP: - OK = prop->chartype == ucp_Lu || prop->chartype == ucp_Ll || - prop->chartype == ucp_Lt; - break; - - case PT_GC: - OK = PRIV(ucp_gentype)[prop->chartype] == code[1 + IMM2_SIZE + 2]; - break; - - case PT_PC: - OK = prop->chartype == code[1 + IMM2_SIZE + 2]; - break; - - case PT_SC: - OK = prop->script == code[1 + IMM2_SIZE + 2]; - break; - - case PT_SCX: - OK = (prop->script == code[1 + IMM2_SIZE + 2] || - MAPBIT(PRIV(ucd_script_sets) + UCD_SCRIPTX_PROP(prop), - code[1 + IMM2_SIZE + 2]) != 0); - break; - - /* These are specials for combination cases. */ - - case PT_ALNUM: - OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L || - PRIV(ucp_gentype)[prop->chartype] == ucp_N; - break; - - /* Perl space used to exclude VT, but from Perl 5.18 it is included, - which means that Perl space and POSIX space are now identical. PCRE - was changed at release 8.34. */ - - case PT_SPACE: /* Perl space */ - case PT_PXSPACE: /* POSIX space */ - switch(c) - { - HSPACE_CASES: - VSPACE_CASES: - OK = TRUE; - break; - - default: - OK = PRIV(ucp_gentype)[prop->chartype] == ucp_Z; - break; - } - break; - - case PT_WORD: - OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L || - PRIV(ucp_gentype)[prop->chartype] == ucp_N || - c == CHAR_UNDERSCORE; - break; - - case PT_CLIST: - cp = PRIV(ucd_caseless_sets) + code[1 + IMM2_SIZE + 2]; - for (;;) - { - if (c < *cp) { OK = FALSE; break; } - if (c == *cp++) { OK = TRUE; break; } - } - break; - - case PT_UCNC: - OK = c == CHAR_DOLLAR_SIGN || c == CHAR_COMMERCIAL_AT || - c == CHAR_GRAVE_ACCENT || (c >= 0xa0 && c <= 0xd7ff) || - c >= 0xe000; - break; - - case PT_BIDICL: - OK = UCD_BIDICLASS(c) == code[1 + IMM2_SIZE + 2]; - break; - - case PT_BOOL: - OK = MAPBIT(PRIV(ucd_boolprop_sets) + - UCD_BPROPS_PROP(prop), code[1 + IMM2_SIZE + 2]) != 0; - break; - - /* Should never occur, but keep compilers from grumbling. */ - - default: - OK = codevalue != OP_PROP; - break; - } - - if (OK == (d == OP_PROP)) - { - if (codevalue == OP_PROP_EXTRA + OP_TYPEPOSUPTO) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - if (++count >= (int)GET2(code, 1)) - { ADD_NEW(state_offset + 1 + IMM2_SIZE + 3, 0); } - else - { ADD_NEW(state_offset, count); } - } - } - break; - - /*-----------------------------------------------------------------*/ - case OP_EXTUNI_EXTRA + OP_TYPEEXACT: - case OP_EXTUNI_EXTRA + OP_TYPEUPTO: - case OP_EXTUNI_EXTRA + OP_TYPEMINUPTO: - case OP_EXTUNI_EXTRA + OP_TYPEPOSUPTO: - if (codevalue != OP_EXTUNI_EXTRA + OP_TYPEEXACT) - { ADD_ACTIVE(state_offset + 2 + IMM2_SIZE, 0); } - count = current_state->count; /* Number already matched */ - if (clen > 0) - { - PCRE2_SPTR nptr; - int ncount = 0; - if (codevalue == OP_EXTUNI_EXTRA + OP_TYPEPOSUPTO) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - nptr = PRIV(extuni)(c, ptr + clen, mb->start_subject, end_subject, utf, - &ncount); - if (nptr >= end_subject && (mb->moptions & PCRE2_PARTIAL_HARD) != 0) - reset_could_continue = TRUE; - if (++count >= (int)GET2(code, 1)) - { ADD_NEW_DATA(-(state_offset + 2 + IMM2_SIZE), 0, ncount); } - else - { ADD_NEW_DATA(-state_offset, count, ncount); } - } - break; -#endif - - /*-----------------------------------------------------------------*/ - case OP_ANYNL_EXTRA + OP_TYPEEXACT: - case OP_ANYNL_EXTRA + OP_TYPEUPTO: - case OP_ANYNL_EXTRA + OP_TYPEMINUPTO: - case OP_ANYNL_EXTRA + OP_TYPEPOSUPTO: - if (codevalue != OP_ANYNL_EXTRA + OP_TYPEEXACT) - { ADD_ACTIVE(state_offset + 2 + IMM2_SIZE, 0); } - count = current_state->count; /* Number already matched */ - if (clen > 0) - { - int ncount = 0; - switch (c) - { - case CHAR_VT: - case CHAR_FF: - case CHAR_NEL: -#ifndef EBCDIC - case 0x2028: - case 0x2029: -#endif /* Not EBCDIC */ - if (mb->bsr_convention == PCRE2_BSR_ANYCRLF) break; - goto ANYNL03; - - case CHAR_CR: - if (ptr + 1 < end_subject && UCHAR21TEST(ptr + 1) == CHAR_LF) ncount = 1; - /* Fall through */ - - ANYNL03: - case CHAR_LF: - if (codevalue == OP_ANYNL_EXTRA + OP_TYPEPOSUPTO) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - if (++count >= (int)GET2(code, 1)) - { ADD_NEW_DATA(-(state_offset + 2 + IMM2_SIZE), 0, ncount); } - else - { ADD_NEW_DATA(-state_offset, count, ncount); } - break; - - default: - break; - } - } - break; - - /*-----------------------------------------------------------------*/ - case OP_VSPACE_EXTRA + OP_TYPEEXACT: - case OP_VSPACE_EXTRA + OP_TYPEUPTO: - case OP_VSPACE_EXTRA + OP_TYPEMINUPTO: - case OP_VSPACE_EXTRA + OP_TYPEPOSUPTO: - if (codevalue != OP_VSPACE_EXTRA + OP_TYPEEXACT) - { ADD_ACTIVE(state_offset + 2 + IMM2_SIZE, 0); } - count = current_state->count; /* Number already matched */ - if (clen > 0) - { - BOOL OK; - switch (c) - { - VSPACE_CASES: - OK = TRUE; - break; - - default: - OK = FALSE; - } - - if (OK == (d == OP_VSPACE)) - { - if (codevalue == OP_VSPACE_EXTRA + OP_TYPEPOSUPTO) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - if (++count >= (int)GET2(code, 1)) - { ADD_NEW_DATA(-(state_offset + 2 + IMM2_SIZE), 0, 0); } - else - { ADD_NEW_DATA(-state_offset, count, 0); } - } - } - break; - - /*-----------------------------------------------------------------*/ - case OP_HSPACE_EXTRA + OP_TYPEEXACT: - case OP_HSPACE_EXTRA + OP_TYPEUPTO: - case OP_HSPACE_EXTRA + OP_TYPEMINUPTO: - case OP_HSPACE_EXTRA + OP_TYPEPOSUPTO: - if (codevalue != OP_HSPACE_EXTRA + OP_TYPEEXACT) - { ADD_ACTIVE(state_offset + 2 + IMM2_SIZE, 0); } - count = current_state->count; /* Number already matched */ - if (clen > 0) - { - BOOL OK; - switch (c) - { - HSPACE_CASES: - OK = TRUE; - break; - - default: - OK = FALSE; - break; - } - - if (OK == (d == OP_HSPACE)) - { - if (codevalue == OP_HSPACE_EXTRA + OP_TYPEPOSUPTO) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - if (++count >= (int)GET2(code, 1)) - { ADD_NEW_DATA(-(state_offset + 2 + IMM2_SIZE), 0, 0); } - else - { ADD_NEW_DATA(-state_offset, count, 0); } - } - } - break; - -/* ========================================================================== */ - /* These opcodes are followed by a character that is usually compared - to the current subject character; it is loaded into d. We still get - here even if there is no subject character, because in some cases zero - repetitions are permitted. */ - - /*-----------------------------------------------------------------*/ - case OP_CHAR: - if (clen > 0 && c == d) { ADD_NEW(state_offset + dlen + 1, 0); } - break; - - /*-----------------------------------------------------------------*/ - case OP_CHARI: - if (clen == 0) break; - -#ifdef SUPPORT_UNICODE - if (utf_or_ucp) - { - if (c == d) { ADD_NEW(state_offset + dlen + 1, 0); } else - { - unsigned int othercase; - if (c < 128) - othercase = fcc[c]; - else - othercase = UCD_OTHERCASE(c); - if (d == othercase) { ADD_NEW(state_offset + dlen + 1, 0); } - } - } - else -#endif /* SUPPORT_UNICODE */ - /* Not UTF or UCP mode */ - { - if (TABLE_GET(c, lcc, c) == TABLE_GET(d, lcc, d)) - { ADD_NEW(state_offset + 2, 0); } - } - break; - - -#ifdef SUPPORT_UNICODE - /*-----------------------------------------------------------------*/ - /* This is a tricky one because it can match more than one character. - Find out how many characters to skip, and then set up a negative state - to wait for them to pass before continuing. */ - - case OP_EXTUNI: - if (clen > 0) - { - int ncount = 0; - PCRE2_SPTR nptr = PRIV(extuni)(c, ptr + clen, mb->start_subject, - end_subject, utf, &ncount); - if (nptr >= end_subject && (mb->moptions & PCRE2_PARTIAL_HARD) != 0) - reset_could_continue = TRUE; - ADD_NEW_DATA(-(state_offset + 1), 0, ncount); - } - break; -#endif - - /*-----------------------------------------------------------------*/ - /* This is a tricky like EXTUNI because it too can match more than one - character (when CR is followed by LF). In this case, set up a negative - state to wait for one character to pass before continuing. */ - - case OP_ANYNL: - if (clen > 0) switch(c) - { - case CHAR_VT: - case CHAR_FF: - case CHAR_NEL: -#ifndef EBCDIC - case 0x2028: - case 0x2029: -#endif /* Not EBCDIC */ - if (mb->bsr_convention == PCRE2_BSR_ANYCRLF) break; - /* Fall through */ - - case CHAR_LF: - ADD_NEW(state_offset + 1, 0); - break; - - case CHAR_CR: - if (ptr + 1 >= end_subject) - { - ADD_NEW(state_offset + 1, 0); - if ((mb->moptions & PCRE2_PARTIAL_HARD) != 0) - reset_could_continue = TRUE; - } - else if (UCHAR21TEST(ptr + 1) == CHAR_LF) - { - ADD_NEW_DATA(-(state_offset + 1), 0, 1); - } - else - { - ADD_NEW(state_offset + 1, 0); - } - break; - } - break; - - /*-----------------------------------------------------------------*/ - case OP_NOT_VSPACE: - if (clen > 0) switch(c) - { - VSPACE_CASES: - break; - - default: - ADD_NEW(state_offset + 1, 0); - break; - } - break; - - /*-----------------------------------------------------------------*/ - case OP_VSPACE: - if (clen > 0) switch(c) - { - VSPACE_CASES: - ADD_NEW(state_offset + 1, 0); - break; - - default: - break; - } - break; - - /*-----------------------------------------------------------------*/ - case OP_NOT_HSPACE: - if (clen > 0) switch(c) - { - HSPACE_CASES: - break; - - default: - ADD_NEW(state_offset + 1, 0); - break; - } - break; - - /*-----------------------------------------------------------------*/ - case OP_HSPACE: - if (clen > 0) switch(c) - { - HSPACE_CASES: - ADD_NEW(state_offset + 1, 0); - break; - - default: - break; - } - break; - - /*-----------------------------------------------------------------*/ - /* Match a negated single character casefully. */ - - case OP_NOT: - if (clen > 0 && c != d) { ADD_NEW(state_offset + dlen + 1, 0); } - break; - - /*-----------------------------------------------------------------*/ - /* Match a negated single character caselessly. */ - - case OP_NOTI: - if (clen > 0) - { - uint32_t otherd; -#ifdef SUPPORT_UNICODE - if (utf_or_ucp && d >= 128) - otherd = UCD_OTHERCASE(d); - else -#endif /* SUPPORT_UNICODE */ - otherd = TABLE_GET(d, fcc, d); - if (c != d && c != otherd) - { ADD_NEW(state_offset + dlen + 1, 0); } - } - break; - - /*-----------------------------------------------------------------*/ - case OP_PLUSI: - case OP_MINPLUSI: - case OP_POSPLUSI: - case OP_NOTPLUSI: - case OP_NOTMINPLUSI: - case OP_NOTPOSPLUSI: - caseless = TRUE; - codevalue -= OP_STARI - OP_STAR; - - /* Fall through */ - case OP_PLUS: - case OP_MINPLUS: - case OP_POSPLUS: - case OP_NOTPLUS: - case OP_NOTMINPLUS: - case OP_NOTPOSPLUS: - count = current_state->count; /* Already matched */ - if (count > 0) { ADD_ACTIVE(state_offset + dlen + 1, 0); } - if (clen > 0) - { - uint32_t otherd = NOTACHAR; - if (caseless) - { -#ifdef SUPPORT_UNICODE - if (utf_or_ucp && d >= 128) - otherd = UCD_OTHERCASE(d); - else -#endif /* SUPPORT_UNICODE */ - otherd = TABLE_GET(d, fcc, d); - } - if ((c == d || c == otherd) == (codevalue < OP_NOTSTAR)) - { - if (count > 0 && - (codevalue == OP_POSPLUS || codevalue == OP_NOTPOSPLUS)) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - count++; - ADD_NEW(state_offset, count); - } - } - break; - - /*-----------------------------------------------------------------*/ - case OP_QUERYI: - case OP_MINQUERYI: - case OP_POSQUERYI: - case OP_NOTQUERYI: - case OP_NOTMINQUERYI: - case OP_NOTPOSQUERYI: - caseless = TRUE; - codevalue -= OP_STARI - OP_STAR; - /* Fall through */ - case OP_QUERY: - case OP_MINQUERY: - case OP_POSQUERY: - case OP_NOTQUERY: - case OP_NOTMINQUERY: - case OP_NOTPOSQUERY: - ADD_ACTIVE(state_offset + dlen + 1, 0); - if (clen > 0) - { - uint32_t otherd = NOTACHAR; - if (caseless) - { -#ifdef SUPPORT_UNICODE - if (utf_or_ucp && d >= 128) - otherd = UCD_OTHERCASE(d); - else -#endif /* SUPPORT_UNICODE */ - otherd = TABLE_GET(d, fcc, d); - } - if ((c == d || c == otherd) == (codevalue < OP_NOTSTAR)) - { - if (codevalue == OP_POSQUERY || codevalue == OP_NOTPOSQUERY) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - ADD_NEW(state_offset + dlen + 1, 0); - } - } - break; - - /*-----------------------------------------------------------------*/ - case OP_STARI: - case OP_MINSTARI: - case OP_POSSTARI: - case OP_NOTSTARI: - case OP_NOTMINSTARI: - case OP_NOTPOSSTARI: - caseless = TRUE; - codevalue -= OP_STARI - OP_STAR; - /* Fall through */ - case OP_STAR: - case OP_MINSTAR: - case OP_POSSTAR: - case OP_NOTSTAR: - case OP_NOTMINSTAR: - case OP_NOTPOSSTAR: - ADD_ACTIVE(state_offset + dlen + 1, 0); - if (clen > 0) - { - uint32_t otherd = NOTACHAR; - if (caseless) - { -#ifdef SUPPORT_UNICODE - if (utf_or_ucp && d >= 128) - otherd = UCD_OTHERCASE(d); - else -#endif /* SUPPORT_UNICODE */ - otherd = TABLE_GET(d, fcc, d); - } - if ((c == d || c == otherd) == (codevalue < OP_NOTSTAR)) - { - if (codevalue == OP_POSSTAR || codevalue == OP_NOTPOSSTAR) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - ADD_NEW(state_offset, 0); - } - } - break; - - /*-----------------------------------------------------------------*/ - case OP_EXACTI: - case OP_NOTEXACTI: - caseless = TRUE; - codevalue -= OP_STARI - OP_STAR; - /* Fall through */ - case OP_EXACT: - case OP_NOTEXACT: - count = current_state->count; /* Number already matched */ - if (clen > 0) - { - uint32_t otherd = NOTACHAR; - if (caseless) - { -#ifdef SUPPORT_UNICODE - if (utf_or_ucp && d >= 128) - otherd = UCD_OTHERCASE(d); - else -#endif /* SUPPORT_UNICODE */ - otherd = TABLE_GET(d, fcc, d); - } - if ((c == d || c == otherd) == (codevalue < OP_NOTSTAR)) - { - if (++count >= (int)GET2(code, 1)) - { ADD_NEW(state_offset + dlen + 1 + IMM2_SIZE, 0); } - else - { ADD_NEW(state_offset, count); } - } - } - break; - - /*-----------------------------------------------------------------*/ - case OP_UPTOI: - case OP_MINUPTOI: - case OP_POSUPTOI: - case OP_NOTUPTOI: - case OP_NOTMINUPTOI: - case OP_NOTPOSUPTOI: - caseless = TRUE; - codevalue -= OP_STARI - OP_STAR; - /* Fall through */ - case OP_UPTO: - case OP_MINUPTO: - case OP_POSUPTO: - case OP_NOTUPTO: - case OP_NOTMINUPTO: - case OP_NOTPOSUPTO: - ADD_ACTIVE(state_offset + dlen + 1 + IMM2_SIZE, 0); - count = current_state->count; /* Number already matched */ - if (clen > 0) - { - uint32_t otherd = NOTACHAR; - if (caseless) - { -#ifdef SUPPORT_UNICODE - if (utf_or_ucp && d >= 128) - otherd = UCD_OTHERCASE(d); - else -#endif /* SUPPORT_UNICODE */ - otherd = TABLE_GET(d, fcc, d); - } - if ((c == d || c == otherd) == (codevalue < OP_NOTSTAR)) - { - if (codevalue == OP_POSUPTO || codevalue == OP_NOTPOSUPTO) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - if (++count >= (int)GET2(code, 1)) - { ADD_NEW(state_offset + dlen + 1 + IMM2_SIZE, 0); } - else - { ADD_NEW(state_offset, count); } - } - } - break; - - -/* ========================================================================== */ - /* These are the class-handling opcodes */ - - case OP_CLASS: - case OP_NCLASS: - case OP_XCLASS: - { - BOOL isinclass = FALSE; - int next_state_offset; - PCRE2_SPTR ecode; - - /* For a simple class, there is always just a 32-byte table, and we - can set isinclass from it. */ - - if (codevalue != OP_XCLASS) - { - ecode = code + 1 + (32 / sizeof(PCRE2_UCHAR)); - if (clen > 0) - { - isinclass = (c > 255)? (codevalue == OP_NCLASS) : - ((((uint8_t *)(code + 1))[c/8] & (1u << (c&7))) != 0); - } - } - - /* An extended class may have a table or a list of single characters, - ranges, or both, and it may be positive or negative. There's a - function that sorts all this out. */ - - else - { - ecode = code + GET(code, 1); - if (clen > 0) isinclass = PRIV(xclass)(c, code + 1 + LINK_SIZE, utf); - } - - /* At this point, isinclass is set for all kinds of class, and ecode - points to the byte after the end of the class. If there is a - quantifier, this is where it will be. */ - - next_state_offset = (int)(ecode - start_code); - - switch (*ecode) - { - case OP_CRSTAR: - case OP_CRMINSTAR: - case OP_CRPOSSTAR: - ADD_ACTIVE(next_state_offset + 1, 0); - if (isinclass) - { - if (*ecode == OP_CRPOSSTAR) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - ADD_NEW(state_offset, 0); - } - break; - - case OP_CRPLUS: - case OP_CRMINPLUS: - case OP_CRPOSPLUS: - count = current_state->count; /* Already matched */ - if (count > 0) { ADD_ACTIVE(next_state_offset + 1, 0); } - if (isinclass) - { - if (count > 0 && *ecode == OP_CRPOSPLUS) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - count++; - ADD_NEW(state_offset, count); - } - break; - - case OP_CRQUERY: - case OP_CRMINQUERY: - case OP_CRPOSQUERY: - ADD_ACTIVE(next_state_offset + 1, 0); - if (isinclass) - { - if (*ecode == OP_CRPOSQUERY) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - ADD_NEW(next_state_offset + 1, 0); - } - break; - - case OP_CRRANGE: - case OP_CRMINRANGE: - case OP_CRPOSRANGE: - count = current_state->count; /* Already matched */ - if (count >= (int)GET2(ecode, 1)) - { ADD_ACTIVE(next_state_offset + 1 + 2 * IMM2_SIZE, 0); } - if (isinclass) - { - int max = (int)GET2(ecode, 1 + IMM2_SIZE); - - if (*ecode == OP_CRPOSRANGE && count >= (int)GET2(ecode, 1)) - { - active_count--; /* Remove non-match possibility */ - next_active_state--; - } - - if (++count >= max && max != 0) /* Max 0 => no limit */ - { ADD_NEW(next_state_offset + 1 + 2 * IMM2_SIZE, 0); } - else - { ADD_NEW(state_offset, count); } - } - break; - - default: - if (isinclass) { ADD_NEW(next_state_offset, 0); } - break; - } - } - break; - -/* ========================================================================== */ - /* These are the opcodes for fancy brackets of various kinds. We have - to use recursion in order to handle them. The "always failing" assertion - (?!) is optimised to OP_FAIL when compiling, so we have to support that, - though the other "backtracking verbs" are not supported. */ - - case OP_FAIL: - forced_fail++; /* Count FAILs for multiple states */ - break; - - case OP_ASSERT: - case OP_ASSERT_NOT: - case OP_ASSERTBACK: - case OP_ASSERTBACK_NOT: - { - int rc; - int *local_workspace; - PCRE2_SIZE *local_offsets; - PCRE2_SPTR endasscode = code + GET(code, 1); - RWS_anchor *rws = (RWS_anchor *)RWS; - - if (rws->free < RWS_RSIZE + RWS_OVEC_OSIZE) - { - rc = more_workspace(&rws, RWS_OVEC_OSIZE, mb); - if (rc != 0) return rc; - RWS = (int *)rws; - } - - local_offsets = (PCRE2_SIZE *)(RWS + rws->size - rws->free); - local_workspace = ((int *)local_offsets) + RWS_OVEC_OSIZE; - rws->free -= RWS_RSIZE + RWS_OVEC_OSIZE; - - while (*endasscode == OP_ALT) endasscode += GET(endasscode, 1); - - rc = internal_dfa_match( - mb, /* static match data */ - code, /* this subexpression's code */ - ptr, /* where we currently are */ - (PCRE2_SIZE)(ptr - start_subject), /* start offset */ - local_offsets, /* offset vector */ - RWS_OVEC_OSIZE/OVEC_UNIT, /* size of same */ - local_workspace, /* workspace vector */ - RWS_RSIZE, /* size of same */ - rlevel, /* function recursion level */ - RWS); /* recursion workspace */ - - rws->free += RWS_RSIZE + RWS_OVEC_OSIZE; - - if (rc < 0 && rc != PCRE2_ERROR_NOMATCH) return rc; - if ((rc >= 0) == (codevalue == OP_ASSERT || codevalue == OP_ASSERTBACK)) - { ADD_ACTIVE((int)(endasscode + LINK_SIZE + 1 - start_code), 0); } - } - break; - - /*-----------------------------------------------------------------*/ - case OP_COND: - case OP_SCOND: - { - int codelink = (int)GET(code, 1); - PCRE2_UCHAR condcode; - - /* Because of the way auto-callout works during compile, a callout item - is inserted between OP_COND and an assertion condition. This does not - happen for the other conditions. */ - - if (code[LINK_SIZE + 1] == OP_CALLOUT - || code[LINK_SIZE + 1] == OP_CALLOUT_STR) - { - PCRE2_SIZE callout_length; - rrc = do_callout_dfa(code, offsets, current_subject, ptr, mb, - 1 + LINK_SIZE, &callout_length); - if (rrc < 0) return rrc; /* Abandon */ - if (rrc > 0) break; /* Fail this thread */ - code += callout_length; /* Skip callout data */ - } - - condcode = code[LINK_SIZE+1]; - - /* Back reference conditions and duplicate named recursion conditions - are not supported */ - - if (condcode == OP_CREF || condcode == OP_DNCREF || - condcode == OP_DNRREF) - return PCRE2_ERROR_DFA_UCOND; - - /* The DEFINE condition is always false, and the assertion (?!) is - converted to OP_FAIL. */ - - if (condcode == OP_FALSE || condcode == OP_FAIL) - { ADD_ACTIVE(state_offset + codelink + LINK_SIZE + 1, 0); } - - /* There is also an always-true condition */ - - else if (condcode == OP_TRUE) - { ADD_ACTIVE(state_offset + LINK_SIZE + 2, 0); } - - /* The only supported version of OP_RREF is for the value RREF_ANY, - which means "test if in any recursion". We can't test for specifically - recursed groups. */ - - else if (condcode == OP_RREF) - { - unsigned int value = GET2(code, LINK_SIZE + 2); - if (value != RREF_ANY) return PCRE2_ERROR_DFA_UCOND; - if (mb->recursive != NULL) - { ADD_ACTIVE(state_offset + LINK_SIZE + 2 + IMM2_SIZE, 0); } - else { ADD_ACTIVE(state_offset + codelink + LINK_SIZE + 1, 0); } - } - - /* Otherwise, the condition is an assertion */ - - else - { - int rc; - int *local_workspace; - PCRE2_SIZE *local_offsets; - PCRE2_SPTR asscode = code + LINK_SIZE + 1; - PCRE2_SPTR endasscode = asscode + GET(asscode, 1); - RWS_anchor *rws = (RWS_anchor *)RWS; - - if (rws->free < RWS_RSIZE + RWS_OVEC_OSIZE) - { - rc = more_workspace(&rws, RWS_OVEC_OSIZE, mb); - if (rc != 0) return rc; - RWS = (int *)rws; - } - - local_offsets = (PCRE2_SIZE *)(RWS + rws->size - rws->free); - local_workspace = ((int *)local_offsets) + RWS_OVEC_OSIZE; - rws->free -= RWS_RSIZE + RWS_OVEC_OSIZE; - - while (*endasscode == OP_ALT) endasscode += GET(endasscode, 1); - - rc = internal_dfa_match( - mb, /* fixed match data */ - asscode, /* this subexpression's code */ - ptr, /* where we currently are */ - (PCRE2_SIZE)(ptr - start_subject), /* start offset */ - local_offsets, /* offset vector */ - RWS_OVEC_OSIZE/OVEC_UNIT, /* size of same */ - local_workspace, /* workspace vector */ - RWS_RSIZE, /* size of same */ - rlevel, /* function recursion level */ - RWS); /* recursion workspace */ - - rws->free += RWS_RSIZE + RWS_OVEC_OSIZE; - - if (rc < 0 && rc != PCRE2_ERROR_NOMATCH) return rc; - if ((rc >= 0) == - (condcode == OP_ASSERT || condcode == OP_ASSERTBACK)) - { ADD_ACTIVE((int)(endasscode + LINK_SIZE + 1 - start_code), 0); } - else - { ADD_ACTIVE(state_offset + codelink + LINK_SIZE + 1, 0); } - } - } - break; - - /*-----------------------------------------------------------------*/ - case OP_RECURSE: - { - int rc; - int *local_workspace; - PCRE2_SIZE *local_offsets; - RWS_anchor *rws = (RWS_anchor *)RWS; - dfa_recursion_info *ri; - PCRE2_SPTR callpat = start_code + GET(code, 1); - uint32_t recno = (callpat == mb->start_code)? 0 : - GET2(callpat, 1 + LINK_SIZE); - - if (rws->free < RWS_RSIZE + RWS_OVEC_RSIZE) - { - rc = more_workspace(&rws, RWS_OVEC_RSIZE, mb); - if (rc != 0) return rc; - RWS = (int *)rws; - } - - local_offsets = (PCRE2_SIZE *)(RWS + rws->size - rws->free); - local_workspace = ((int *)local_offsets) + RWS_OVEC_RSIZE; - rws->free -= RWS_RSIZE + RWS_OVEC_RSIZE; - - /* Check for repeating a recursion without advancing the subject - pointer. This should catch convoluted mutual recursions. (Some simple - cases are caught at compile time.) */ - - for (ri = mb->recursive; ri != NULL; ri = ri->prevrec) - if (recno == ri->group_num && ptr == ri->subject_position) - return PCRE2_ERROR_RECURSELOOP; - - /* Remember this recursion and where we started it so as to - catch infinite loops. */ - - new_recursive.group_num = recno; - new_recursive.subject_position = ptr; - new_recursive.prevrec = mb->recursive; - mb->recursive = &new_recursive; - - rc = internal_dfa_match( - mb, /* fixed match data */ - callpat, /* this subexpression's code */ - ptr, /* where we currently are */ - (PCRE2_SIZE)(ptr - start_subject), /* start offset */ - local_offsets, /* offset vector */ - RWS_OVEC_RSIZE/OVEC_UNIT, /* size of same */ - local_workspace, /* workspace vector */ - RWS_RSIZE, /* size of same */ - rlevel, /* function recursion level */ - RWS); /* recursion workspace */ - - rws->free += RWS_RSIZE + RWS_OVEC_RSIZE; - mb->recursive = new_recursive.prevrec; /* Done this recursion */ - - /* Ran out of internal offsets */ - - if (rc == 0) return PCRE2_ERROR_DFA_RECURSE; - - /* For each successful matched substring, set up the next state with a - count of characters to skip before trying it. Note that the count is in - characters, not bytes. */ - - if (rc > 0) - { - for (rc = rc*2 - 2; rc >= 0; rc -= 2) - { - PCRE2_SIZE charcount = local_offsets[rc+1] - local_offsets[rc]; -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 - if (utf) - { - PCRE2_SPTR p = start_subject + local_offsets[rc]; - PCRE2_SPTR pp = start_subject + local_offsets[rc+1]; - while (p < pp) if (NOT_FIRSTCU(*p++)) charcount--; - } -#endif - if (charcount > 0) - { - ADD_NEW_DATA(-(state_offset + LINK_SIZE + 1), 0, - (int)(charcount - 1)); - } - else - { - ADD_ACTIVE(state_offset + LINK_SIZE + 1, 0); - } - } - } - else if (rc != PCRE2_ERROR_NOMATCH) return rc; - } - break; - - /*-----------------------------------------------------------------*/ - case OP_BRAPOS: - case OP_SBRAPOS: - case OP_CBRAPOS: - case OP_SCBRAPOS: - case OP_BRAPOSZERO: - { - int rc; - int *local_workspace; - PCRE2_SIZE *local_offsets; - PCRE2_SIZE charcount, matched_count; - PCRE2_SPTR local_ptr = ptr; - RWS_anchor *rws = (RWS_anchor *)RWS; - BOOL allow_zero; - - if (rws->free < RWS_RSIZE + RWS_OVEC_OSIZE) - { - rc = more_workspace(&rws, RWS_OVEC_OSIZE, mb); - if (rc != 0) return rc; - RWS = (int *)rws; - } - - local_offsets = (PCRE2_SIZE *)(RWS + rws->size - rws->free); - local_workspace = ((int *)local_offsets) + RWS_OVEC_OSIZE; - rws->free -= RWS_RSIZE + RWS_OVEC_OSIZE; - - if (codevalue == OP_BRAPOSZERO) - { - allow_zero = TRUE; - codevalue = *(++code); /* Codevalue will be one of above BRAs */ - } - else allow_zero = FALSE; - - /* Loop to match the subpattern as many times as possible as if it were - a complete pattern. */ - - for (matched_count = 0;; matched_count++) - { - rc = internal_dfa_match( - mb, /* fixed match data */ - code, /* this subexpression's code */ - local_ptr, /* where we currently are */ - (PCRE2_SIZE)(ptr - start_subject), /* start offset */ - local_offsets, /* offset vector */ - RWS_OVEC_OSIZE/OVEC_UNIT, /* size of same */ - local_workspace, /* workspace vector */ - RWS_RSIZE, /* size of same */ - rlevel, /* function recursion level */ - RWS); /* recursion workspace */ - - /* Failed to match */ - - if (rc < 0) - { - if (rc != PCRE2_ERROR_NOMATCH) return rc; - break; - } - - /* Matched: break the loop if zero characters matched. */ - - charcount = local_offsets[1] - local_offsets[0]; - if (charcount == 0) break; - local_ptr += charcount; /* Advance temporary position ptr */ - } - - rws->free += RWS_RSIZE + RWS_OVEC_OSIZE; - - /* At this point we have matched the subpattern matched_count - times, and local_ptr is pointing to the character after the end of the - last match. */ - - if (matched_count > 0 || allow_zero) - { - PCRE2_SPTR end_subpattern = code; - int next_state_offset; - - do { end_subpattern += GET(end_subpattern, 1); } - while (*end_subpattern == OP_ALT); - next_state_offset = - (int)(end_subpattern - start_code + LINK_SIZE + 1); - - /* Optimization: if there are no more active states, and there - are no new states yet set up, then skip over the subject string - right here, to save looping. Otherwise, set up the new state to swing - into action when the end of the matched substring is reached. */ - - if (i + 1 >= active_count && new_count == 0) - { - ptr = local_ptr; - clen = 0; - ADD_NEW(next_state_offset, 0); - } - else - { - PCRE2_SPTR p = ptr; - PCRE2_SPTR pp = local_ptr; - charcount = (PCRE2_SIZE)(pp - p); -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 - if (utf) while (p < pp) if (NOT_FIRSTCU(*p++)) charcount--; -#endif - ADD_NEW_DATA(-next_state_offset, 0, (int)(charcount - 1)); - } - } - } - break; - - /*-----------------------------------------------------------------*/ - case OP_ONCE: - { - int rc; - int *local_workspace; - PCRE2_SIZE *local_offsets; - RWS_anchor *rws = (RWS_anchor *)RWS; - - if (rws->free < RWS_RSIZE + RWS_OVEC_OSIZE) - { - rc = more_workspace(&rws, RWS_OVEC_OSIZE, mb); - if (rc != 0) return rc; - RWS = (int *)rws; - } - - local_offsets = (PCRE2_SIZE *)(RWS + rws->size - rws->free); - local_workspace = ((int *)local_offsets) + RWS_OVEC_OSIZE; - rws->free -= RWS_RSIZE + RWS_OVEC_OSIZE; - - rc = internal_dfa_match( - mb, /* fixed match data */ - code, /* this subexpression's code */ - ptr, /* where we currently are */ - (PCRE2_SIZE)(ptr - start_subject), /* start offset */ - local_offsets, /* offset vector */ - RWS_OVEC_OSIZE/OVEC_UNIT, /* size of same */ - local_workspace, /* workspace vector */ - RWS_RSIZE, /* size of same */ - rlevel, /* function recursion level */ - RWS); /* recursion workspace */ - - rws->free += RWS_RSIZE + RWS_OVEC_OSIZE; - - if (rc >= 0) - { - PCRE2_SPTR end_subpattern = code; - PCRE2_SIZE charcount = local_offsets[1] - local_offsets[0]; - int next_state_offset, repeat_state_offset; - - do { end_subpattern += GET(end_subpattern, 1); } - while (*end_subpattern == OP_ALT); - next_state_offset = - (int)(end_subpattern - start_code + LINK_SIZE + 1); - - /* If the end of this subpattern is KETRMAX or KETRMIN, we must - arrange for the repeat state also to be added to the relevant list. - Calculate the offset, or set -1 for no repeat. */ - - repeat_state_offset = (*end_subpattern == OP_KETRMAX || - *end_subpattern == OP_KETRMIN)? - (int)(end_subpattern - start_code - GET(end_subpattern, 1)) : -1; - - /* If we have matched an empty string, add the next state at the - current character pointer. This is important so that the duplicate - checking kicks in, which is what breaks infinite loops that match an - empty string. */ - - if (charcount == 0) - { - ADD_ACTIVE(next_state_offset, 0); - } - - /* Optimization: if there are no more active states, and there - are no new states yet set up, then skip over the subject string - right here, to save looping. Otherwise, set up the new state to swing - into action when the end of the matched substring is reached. */ - - else if (i + 1 >= active_count && new_count == 0) - { - ptr += charcount; - clen = 0; - ADD_NEW(next_state_offset, 0); - - /* If we are adding a repeat state at the new character position, - we must fudge things so that it is the only current state. - Otherwise, it might be a duplicate of one we processed before, and - that would cause it to be skipped. */ - - if (repeat_state_offset >= 0) - { - next_active_state = active_states; - active_count = 0; - i = -1; - ADD_ACTIVE(repeat_state_offset, 0); - } - } - else - { -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 - if (utf) - { - PCRE2_SPTR p = start_subject + local_offsets[0]; - PCRE2_SPTR pp = start_subject + local_offsets[1]; - while (p < pp) if (NOT_FIRSTCU(*p++)) charcount--; - } -#endif - ADD_NEW_DATA(-next_state_offset, 0, (int)(charcount - 1)); - if (repeat_state_offset >= 0) - { ADD_NEW_DATA(-repeat_state_offset, 0, (int)(charcount - 1)); } - } - } - else if (rc != PCRE2_ERROR_NOMATCH) return rc; - } - break; - - -/* ========================================================================== */ - /* Handle callouts */ - - case OP_CALLOUT: - case OP_CALLOUT_STR: - { - PCRE2_SIZE callout_length; - rrc = do_callout_dfa(code, offsets, current_subject, ptr, mb, 0, - &callout_length); - if (rrc < 0) return rrc; /* Abandon */ - if (rrc == 0) - { ADD_ACTIVE(state_offset + (int)callout_length, 0); } - } - break; - - -/* ========================================================================== */ - default: /* Unsupported opcode */ - return PCRE2_ERROR_DFA_UITEM; - } - - NEXT_ACTIVE_STATE: continue; - - } /* End of loop scanning active states */ - - /* We have finished the processing at the current subject character. If no - new states have been set for the next character, we have found all the - matches that we are going to find. If partial matching has been requested, - check for appropriate conditions. - - The "forced_ fail" variable counts the number of (*F) encountered for the - character. If it is equal to the original active_count (saved in - workspace[1]) it means that (*F) was found on every active state. In this - case we don't want to give a partial match. - - The "could_continue" variable is true if a state could have continued but - for the fact that the end of the subject was reached. */ - - if (new_count <= 0) - { - if (could_continue && /* Some could go on, and */ - forced_fail != workspace[1] && /* Not all forced fail & */ - ( /* either... */ - (mb->moptions & PCRE2_PARTIAL_HARD) != 0 /* Hard partial */ - || /* or... */ - ((mb->moptions & PCRE2_PARTIAL_SOFT) != 0 && /* Soft partial and */ - match_count < 0) /* no matches */ - ) && /* And... */ - ( - partial_newline || /* Either partial NL */ - ( /* or ... */ - ptr >= end_subject && /* End of subject and */ - ( /* either */ - ptr > mb->start_used_ptr || /* Inspected non-empty string */ - mb->allowemptypartial /* or pattern has lookbehind */ - ) /* or could match empty */ - ) - )) - match_count = PCRE2_ERROR_PARTIAL; - break; /* Exit from loop along the subject string */ - } - - /* One or more states are active for the next character. */ - - ptr += clen; /* Advance to next subject character */ - } /* Loop to move along the subject string */ - -/* Control gets here from "break" a few lines above. If we have a match and -PCRE2_ENDANCHORED is set, the match fails. */ - -if (match_count >= 0 && - ((mb->moptions | mb->poptions) & PCRE2_ENDANCHORED) != 0 && - ptr < end_subject) - match_count = PCRE2_ERROR_NOMATCH; - -return match_count; -} - - - -/************************************************* -* Match a pattern using the DFA algorithm * -*************************************************/ - -/* This function matches a compiled pattern to a subject string, using the -alternate matching algorithm that finds all matches at once. - -Arguments: - code points to the compiled pattern - subject subject string - length length of subject string - startoffset where to start matching in the subject - options option bits - match_data points to a match data structure - gcontext points to a match context - workspace pointer to workspace - wscount size of workspace - -Returns: > 0 => number of match offset pairs placed in offsets - = 0 => offsets overflowed; longest matches are present - -1 => failed to match - < -1 => some kind of unexpected problem -*/ - -PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION -pcre2_dfa_match(const pcre2_code *code, PCRE2_SPTR subject, PCRE2_SIZE length, - PCRE2_SIZE start_offset, uint32_t options, pcre2_match_data *match_data, - pcre2_match_context *mcontext, int *workspace, PCRE2_SIZE wscount) -{ -int rc; -int was_zero_terminated = 0; - -const pcre2_real_code *re = (const pcre2_real_code *)code; - -PCRE2_SPTR start_match; -PCRE2_SPTR end_subject; -PCRE2_SPTR bumpalong_limit; -PCRE2_SPTR req_cu_ptr; - -BOOL utf, anchored, startline, firstline; -BOOL has_first_cu = FALSE; -BOOL has_req_cu = FALSE; - -#if PCRE2_CODE_UNIT_WIDTH == 8 -PCRE2_SPTR memchr_found_first_cu = NULL; -PCRE2_SPTR memchr_found_first_cu2 = NULL; -#endif - -PCRE2_UCHAR first_cu = 0; -PCRE2_UCHAR first_cu2 = 0; -PCRE2_UCHAR req_cu = 0; -PCRE2_UCHAR req_cu2 = 0; - -const uint8_t *start_bits = NULL; - -/* We need to have mb pointing to a match block, because the IS_NEWLINE macro -is used below, and it expects NLBLOCK to be defined as a pointer. */ - -pcre2_callout_block cb; -dfa_match_block actual_match_block; -dfa_match_block *mb = &actual_match_block; - -/* Set up a starting block of memory for use during recursive calls to -internal_dfa_match(). By putting this on the stack, it minimizes resource use -in the case when it is not needed. If this is too small, more memory is -obtained from the heap. At the start of each block is an anchor structure.*/ - -int base_recursion_workspace[RWS_BASE_SIZE]; -RWS_anchor *rws = (RWS_anchor *)base_recursion_workspace; -rws->next = NULL; -rws->size = RWS_BASE_SIZE; -rws->free = RWS_BASE_SIZE - RWS_ANCHOR_SIZE; - -/* Recognize NULL, length 0 as an empty string. */ - -if (subject == NULL && length == 0) subject = (PCRE2_SPTR)""; - -/* Plausibility checks */ - -if ((options & ~PUBLIC_DFA_MATCH_OPTIONS) != 0) return PCRE2_ERROR_BADOPTION; -if (re == NULL || subject == NULL || workspace == NULL || match_data == NULL) - return PCRE2_ERROR_NULL; - -if (length == PCRE2_ZERO_TERMINATED) - { - length = PRIV(strlen)(subject); - was_zero_terminated = 1; - } - -if (wscount < 20) return PCRE2_ERROR_DFA_WSSIZE; -if (start_offset > length) return PCRE2_ERROR_BADOFFSET; - -/* Partial matching and PCRE2_ENDANCHORED are currently not allowed at the same -time. */ - -if ((options & (PCRE2_PARTIAL_HARD|PCRE2_PARTIAL_SOFT)) != 0 && - ((re->overall_options | options) & PCRE2_ENDANCHORED) != 0) - return PCRE2_ERROR_BADOPTION; - -/* Invalid UTF support is not available for DFA matching. */ - -if ((re->overall_options & PCRE2_MATCH_INVALID_UTF) != 0) - return PCRE2_ERROR_DFA_UINVALID_UTF; - -/* Check that the first field in the block is the magic number. If it is not, -return with PCRE2_ERROR_BADMAGIC. */ - -if (re->magic_number != MAGIC_NUMBER) return PCRE2_ERROR_BADMAGIC; - -/* Check the code unit width. */ - -if ((re->flags & PCRE2_MODE_MASK) != PCRE2_CODE_UNIT_WIDTH/8) - return PCRE2_ERROR_BADMODE; - -/* PCRE2_NOTEMPTY and PCRE2_NOTEMPTY_ATSTART are match-time flags in the -options variable for this function. Users of PCRE2 who are not calling the -function directly would like to have a way of setting these flags, in the same -way that they can set pcre2_compile() flags like PCRE2_NO_AUTOPOSSESS with -constructions like (*NO_AUTOPOSSESS). To enable this, (*NOTEMPTY) and -(*NOTEMPTY_ATSTART) set bits in the pattern's "flag" function which can now be -transferred to the options for this function. The bits are guaranteed to be -adjacent, but do not have the same values. This bit of Boolean trickery assumes -that the match-time bits are not more significant than the flag bits. If by -accident this is not the case, a compile-time division by zero error will -occur. */ - -#define FF (PCRE2_NOTEMPTY_SET|PCRE2_NE_ATST_SET) -#define OO (PCRE2_NOTEMPTY|PCRE2_NOTEMPTY_ATSTART) -options |= (re->flags & FF) / ((FF & (~FF+1)) / (OO & (~OO+1))); -#undef FF -#undef OO - -/* If restarting after a partial match, do some sanity checks on the contents -of the workspace. */ - -if ((options & PCRE2_DFA_RESTART) != 0) - { - if ((workspace[0] & (-2)) != 0 || workspace[1] < 1 || - workspace[1] > (int)((wscount - 2)/INTS_PER_STATEBLOCK)) - return PCRE2_ERROR_DFA_BADRESTART; - } - -/* Set some local values */ - -utf = (re->overall_options & PCRE2_UTF) != 0; -start_match = subject + start_offset; -end_subject = subject + length; -req_cu_ptr = start_match - 1; -anchored = (options & (PCRE2_ANCHORED|PCRE2_DFA_RESTART)) != 0 || - (re->overall_options & PCRE2_ANCHORED) != 0; - -/* The "must be at the start of a line" flags are used in a loop when finding -where to start. */ - -startline = (re->flags & PCRE2_STARTLINE) != 0; -firstline = (re->overall_options & PCRE2_FIRSTLINE) != 0; -bumpalong_limit = end_subject; - -/* Initialize and set up the fixed fields in the callout block, with a pointer -in the match block. */ - -mb->cb = &cb; -cb.version = 2; -cb.subject = subject; -cb.subject_length = (PCRE2_SIZE)(end_subject - subject); -cb.callout_flags = 0; -cb.capture_top = 1; /* No capture support */ -cb.capture_last = 0; -cb.mark = NULL; /* No (*MARK) support */ - -/* Get data from the match context, if present, and fill in the remaining -fields in the match block. It is an error to set an offset limit without -setting the flag at compile time. */ - -if (mcontext == NULL) - { - mb->callout = NULL; - mb->memctl = re->memctl; - mb->match_limit = PRIV(default_match_context).match_limit; - mb->match_limit_depth = PRIV(default_match_context).depth_limit; - mb->heap_limit = PRIV(default_match_context).heap_limit; - } -else - { - if (mcontext->offset_limit != PCRE2_UNSET) - { - if ((re->overall_options & PCRE2_USE_OFFSET_LIMIT) == 0) - return PCRE2_ERROR_BADOFFSETLIMIT; - bumpalong_limit = subject + mcontext->offset_limit; - } - mb->callout = mcontext->callout; - mb->callout_data = mcontext->callout_data; - mb->memctl = mcontext->memctl; - mb->match_limit = mcontext->match_limit; - mb->match_limit_depth = mcontext->depth_limit; - mb->heap_limit = mcontext->heap_limit; - } - -if (mb->match_limit > re->limit_match) - mb->match_limit = re->limit_match; - -if (mb->match_limit_depth > re->limit_depth) - mb->match_limit_depth = re->limit_depth; - -if (mb->heap_limit > re->limit_heap) - mb->heap_limit = re->limit_heap; - -mb->start_code = (PCRE2_UCHAR *)((uint8_t *)re + sizeof(pcre2_real_code)) + - re->name_count * re->name_entry_size; -mb->tables = re->tables; -mb->start_subject = subject; -mb->end_subject = end_subject; -mb->start_offset = start_offset; -mb->allowemptypartial = (re->max_lookbehind > 0) || - (re->flags & PCRE2_MATCH_EMPTY) != 0; -mb->moptions = options; -mb->poptions = re->overall_options; -mb->match_call_count = 0; -mb->heap_used = 0; - -/* Process the \R and newline settings. */ - -mb->bsr_convention = re->bsr_convention; -mb->nltype = NLTYPE_FIXED; -switch(re->newline_convention) - { - case PCRE2_NEWLINE_CR: - mb->nllen = 1; - mb->nl[0] = CHAR_CR; - break; - - case PCRE2_NEWLINE_LF: - mb->nllen = 1; - mb->nl[0] = CHAR_NL; - break; - - case PCRE2_NEWLINE_NUL: - mb->nllen = 1; - mb->nl[0] = CHAR_NUL; - break; - - case PCRE2_NEWLINE_CRLF: - mb->nllen = 2; - mb->nl[0] = CHAR_CR; - mb->nl[1] = CHAR_NL; - break; - - case PCRE2_NEWLINE_ANY: - mb->nltype = NLTYPE_ANY; - break; - - case PCRE2_NEWLINE_ANYCRLF: - mb->nltype = NLTYPE_ANYCRLF; - break; - - default: return PCRE2_ERROR_INTERNAL; - } - -/* Check a UTF string for validity if required. For 8-bit and 16-bit strings, -we must also check that a starting offset does not point into the middle of a -multiunit character. We check only the portion of the subject that is going to -be inspected during matching - from the offset minus the maximum back reference -to the given length. This saves time when a small part of a large subject is -being matched by the use of a starting offset. Note that the maximum lookbehind -is a number of characters, not code units. */ - -#ifdef SUPPORT_UNICODE -if (utf && (options & PCRE2_NO_UTF_CHECK) == 0) - { - PCRE2_SPTR check_subject = start_match; /* start_match includes offset */ - - if (start_offset > 0) - { -#if PCRE2_CODE_UNIT_WIDTH != 32 - unsigned int i; - if (start_match < end_subject && NOT_FIRSTCU(*start_match)) - return PCRE2_ERROR_BADUTFOFFSET; - for (i = re->max_lookbehind; i > 0 && check_subject > subject; i--) - { - check_subject--; - while (check_subject > subject && -#if PCRE2_CODE_UNIT_WIDTH == 8 - (*check_subject & 0xc0) == 0x80) -#else /* 16-bit */ - (*check_subject & 0xfc00) == 0xdc00) -#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */ - check_subject--; - } -#else /* In the 32-bit library, one code unit equals one character. */ - check_subject -= re->max_lookbehind; - if (check_subject < subject) check_subject = subject; -#endif /* PCRE2_CODE_UNIT_WIDTH != 32 */ - } - - /* Validate the relevant portion of the subject. After an error, adjust the - offset to be an absolute offset in the whole string. */ - - match_data->rc = PRIV(valid_utf)(check_subject, - length - (PCRE2_SIZE)(check_subject - subject), &(match_data->startchar)); - if (match_data->rc != 0) - { - match_data->startchar += (PCRE2_SIZE)(check_subject - subject); - return match_data->rc; - } - } -#endif /* SUPPORT_UNICODE */ - -/* Set up the first code unit to match, if available. If there's no first code -unit there may be a bitmap of possible first characters. */ - -if ((re->flags & PCRE2_FIRSTSET) != 0) - { - has_first_cu = TRUE; - first_cu = first_cu2 = (PCRE2_UCHAR)(re->first_codeunit); - if ((re->flags & PCRE2_FIRSTCASELESS) != 0) - { - first_cu2 = TABLE_GET(first_cu, mb->tables + fcc_offset, first_cu); -#ifdef SUPPORT_UNICODE -#if PCRE2_CODE_UNIT_WIDTH == 8 - if (first_cu > 127 && !utf && (re->overall_options & PCRE2_UCP) != 0) - first_cu2 = (PCRE2_UCHAR)UCD_OTHERCASE(first_cu); -#else - if (first_cu > 127 && (utf || (re->overall_options & PCRE2_UCP) != 0)) - first_cu2 = (PCRE2_UCHAR)UCD_OTHERCASE(first_cu); -#endif -#endif /* SUPPORT_UNICODE */ - } - } -else - if (!startline && (re->flags & PCRE2_FIRSTMAPSET) != 0) - start_bits = re->start_bitmap; - -/* There may be a "last known required code unit" set. */ - -if ((re->flags & PCRE2_LASTSET) != 0) - { - has_req_cu = TRUE; - req_cu = req_cu2 = (PCRE2_UCHAR)(re->last_codeunit); - if ((re->flags & PCRE2_LASTCASELESS) != 0) - { - req_cu2 = TABLE_GET(req_cu, mb->tables + fcc_offset, req_cu); -#ifdef SUPPORT_UNICODE -#if PCRE2_CODE_UNIT_WIDTH == 8 - if (req_cu > 127 && !utf && (re->overall_options & PCRE2_UCP) != 0) - req_cu2 = (PCRE2_UCHAR)UCD_OTHERCASE(req_cu); -#else - if (req_cu > 127 && (utf || (re->overall_options & PCRE2_UCP) != 0)) - req_cu2 = (PCRE2_UCHAR)UCD_OTHERCASE(req_cu); -#endif -#endif /* SUPPORT_UNICODE */ - } - } - -/* If the match data block was previously used with PCRE2_COPY_MATCHED_SUBJECT, -free the memory that was obtained. */ - -if ((match_data->flags & PCRE2_MD_COPIED_SUBJECT) != 0) - { - match_data->memctl.free((void *)match_data->subject, - match_data->memctl.memory_data); - match_data->flags &= ~PCRE2_MD_COPIED_SUBJECT; - } - -/* Fill in fields that are always returned in the match data. */ - -match_data->code = re; -match_data->subject = NULL; /* Default for no match */ -match_data->mark = NULL; -match_data->matchedby = PCRE2_MATCHEDBY_DFA_INTERPRETER; - -/* Call the main matching function, looping for a non-anchored regex after a -failed match. If not restarting, perform certain optimizations at the start of -a match. */ - -for (;;) - { - /* ----------------- Start of match optimizations ---------------- */ - - /* There are some optimizations that avoid running the match if a known - starting point is not found, or if a known later code unit is not present. - However, there is an option (settable at compile time) that disables - these, for testing and for ensuring that all callouts do actually occur. - The optimizations must also be avoided when restarting a DFA match. */ - - if ((re->overall_options & PCRE2_NO_START_OPTIMIZE) == 0 && - (options & PCRE2_DFA_RESTART) == 0) - { - /* If firstline is TRUE, the start of the match is constrained to the first - line of a multiline string. That is, the match must be before or at the - first newline following the start of matching. Temporarily adjust - end_subject so that we stop the optimization scans for a first code unit - immediately after the first character of a newline (the first code unit can - legitimately be a newline). If the match fails at the newline, later code - breaks this loop. */ - - if (firstline) - { - PCRE2_SPTR t = start_match; -#ifdef SUPPORT_UNICODE - if (utf) - { - while (t < end_subject && !IS_NEWLINE(t)) - { - t++; - ACROSSCHAR(t < end_subject, t, t++); - } - } - else -#endif - while (t < end_subject && !IS_NEWLINE(t)) t++; - end_subject = t; - } - - /* Anchored: check the first code unit if one is recorded. This may seem - pointless but it can help in detecting a no match case without scanning for - the required code unit. */ - - if (anchored) - { - if (has_first_cu || start_bits != NULL) - { - BOOL ok = start_match < end_subject; - if (ok) - { - PCRE2_UCHAR c = UCHAR21TEST(start_match); - ok = has_first_cu && (c == first_cu || c == first_cu2); - if (!ok && start_bits != NULL) - { -#if PCRE2_CODE_UNIT_WIDTH != 8 - if (c > 255) c = 255; -#endif - ok = (start_bits[c/8] & (1u << (c&7))) != 0; - } - } - if (!ok) break; - } - } - - /* Not anchored. Advance to a unique first code unit if there is one. */ - - else - { - if (has_first_cu) - { - if (first_cu != first_cu2) /* Caseless */ - { - /* In 16-bit and 32_bit modes we have to do our own search, so can - look for both cases at once. */ - -#if PCRE2_CODE_UNIT_WIDTH != 8 - PCRE2_UCHAR smc; - while (start_match < end_subject && - (smc = UCHAR21TEST(start_match)) != first_cu && - smc != first_cu2) - start_match++; -#else - /* In 8-bit mode, the use of memchr() gives a big speed up, even - though we have to call it twice in order to find the earliest - occurrence of the code unit in either of its cases. Caching is used - to remember the positions of previously found code units. This can - make a huge difference when the strings are very long and only one - case is actually present. */ - - PCRE2_SPTR pp1 = NULL; - PCRE2_SPTR pp2 = NULL; - PCRE2_SIZE searchlength = end_subject - start_match; - - /* If we haven't got a previously found position for first_cu, or if - the current starting position is later, we need to do a search. If - the code unit is not found, set it to the end. */ - - if (memchr_found_first_cu == NULL || - start_match > memchr_found_first_cu) - { - pp1 = memchr(start_match, first_cu, searchlength); - memchr_found_first_cu = (pp1 == NULL)? end_subject : pp1; - } - - /* If the start is before a previously found position, use the - previous position, or NULL if a previous search failed. */ - - else pp1 = (memchr_found_first_cu == end_subject)? NULL : - memchr_found_first_cu; - - /* Do the same thing for the other case. */ - - if (memchr_found_first_cu2 == NULL || - start_match > memchr_found_first_cu2) - { - pp2 = memchr(start_match, first_cu2, searchlength); - memchr_found_first_cu2 = (pp2 == NULL)? end_subject : pp2; - } - - else pp2 = (memchr_found_first_cu2 == end_subject)? NULL : - memchr_found_first_cu2; - - /* Set the start to the end of the subject if neither case was found. - Otherwise, use the earlier found point. */ - - if (pp1 == NULL) - start_match = (pp2 == NULL)? end_subject : pp2; - else - start_match = (pp2 == NULL || pp1 < pp2)? pp1 : pp2; - -#endif /* 8-bit handling */ - } - - /* The caseful case is much simpler. */ - - else - { -#if PCRE2_CODE_UNIT_WIDTH != 8 - while (start_match < end_subject && UCHAR21TEST(start_match) != - first_cu) - start_match++; -#else /* 8-bit code units */ - start_match = memchr(start_match, first_cu, end_subject - start_match); - if (start_match == NULL) start_match = end_subject; -#endif - } - - /* If we can't find the required code unit, having reached the true end - of the subject, break the bumpalong loop, to force a match failure, - except when doing partial matching, when we let the next cycle run at - the end of the subject. To see why, consider the pattern /(?<=abc)def/, - which partially matches "abc", even though the string does not contain - the starting character "d". If we have not reached the true end of the - subject (PCRE2_FIRSTLINE caused end_subject to be temporarily modified) - we also let the cycle run, because the matching string is legitimately - allowed to start with the first code unit of a newline. */ - - if ((mb->moptions & (PCRE2_PARTIAL_HARD|PCRE2_PARTIAL_SOFT)) == 0 && - start_match >= mb->end_subject) - break; - } - - /* If there's no first code unit, advance to just after a linebreak for a - multiline match if required. */ - - else if (startline) - { - if (start_match > mb->start_subject + start_offset) - { -#ifdef SUPPORT_UNICODE - if (utf) - { - while (start_match < end_subject && !WAS_NEWLINE(start_match)) - { - start_match++; - ACROSSCHAR(start_match < end_subject, start_match, start_match++); - } - } - else -#endif - while (start_match < end_subject && !WAS_NEWLINE(start_match)) - start_match++; - - /* If we have just passed a CR and the newline option is ANY or - ANYCRLF, and we are now at a LF, advance the match position by one - more code unit. */ - - if (start_match[-1] == CHAR_CR && - (mb->nltype == NLTYPE_ANY || mb->nltype == NLTYPE_ANYCRLF) && - start_match < end_subject && - UCHAR21TEST(start_match) == CHAR_NL) - start_match++; - } - } - - /* If there's no first code unit or a requirement for a multiline line - start, advance to a non-unique first code unit if any have been - identified. The bitmap contains only 256 bits. When code units are 16 or - 32 bits wide, all code units greater than 254 set the 255 bit. */ - - else if (start_bits != NULL) - { - while (start_match < end_subject) - { - uint32_t c = UCHAR21TEST(start_match); -#if PCRE2_CODE_UNIT_WIDTH != 8 - if (c > 255) c = 255; -#endif - if ((start_bits[c/8] & (1u << (c&7))) != 0) break; - start_match++; - } - - /* See comment above in first_cu checking about the next line. */ - - if ((mb->moptions & (PCRE2_PARTIAL_HARD|PCRE2_PARTIAL_SOFT)) == 0 && - start_match >= mb->end_subject) - break; - } - } /* End of first code unit handling */ - - /* Restore fudged end_subject */ - - end_subject = mb->end_subject; - - /* The following two optimizations are disabled for partial matching. */ - - if ((mb->moptions & (PCRE2_PARTIAL_HARD|PCRE2_PARTIAL_SOFT)) == 0) - { - PCRE2_SPTR p; - - /* The minimum matching length is a lower bound; no actual string of that - length may actually match the pattern. Although the value is, strictly, - in characters, we treat it as code units to avoid spending too much time - in this optimization. */ - - if (end_subject - start_match < re->minlength) goto NOMATCH_EXIT; - - /* If req_cu is set, we know that that code unit must appear in the - subject for the match to succeed. If the first code unit is set, req_cu - must be later in the subject; otherwise the test starts at the match - point. This optimization can save a huge amount of backtracking in - patterns with nested unlimited repeats that aren't going to match. - Writing separate code for cased/caseless versions makes it go faster, as - does using an autoincrement and backing off on a match. As in the case of - the first code unit, using memchr() in the 8-bit library gives a big - speed up. Unlike the first_cu check above, we do not need to call - memchr() twice in the caseless case because we only need to check for the - presence of the character in either case, not find the first occurrence. - - The search can be skipped if the code unit was found later than the - current starting point in a previous iteration of the bumpalong loop. - - HOWEVER: when the subject string is very, very long, searching to its end - can take a long time, and give bad performance on quite ordinary - patterns. This showed up when somebody was matching something like - /^\d+C/ on a 32-megabyte string... so we don't do this when the string is - sufficiently long, but it's worth searching a lot more for unanchored - patterns. */ - - p = start_match + (has_first_cu? 1:0); - if (has_req_cu && p > req_cu_ptr) - { - PCRE2_SIZE check_length = end_subject - start_match; - - if (check_length < REQ_CU_MAX || - (!anchored && check_length < REQ_CU_MAX * 1000)) - { - if (req_cu != req_cu2) /* Caseless */ - { -#if PCRE2_CODE_UNIT_WIDTH != 8 - while (p < end_subject) - { - uint32_t pp = UCHAR21INCTEST(p); - if (pp == req_cu || pp == req_cu2) { p--; break; } - } -#else /* 8-bit code units */ - PCRE2_SPTR pp = p; - p = memchr(pp, req_cu, end_subject - pp); - if (p == NULL) - { - p = memchr(pp, req_cu2, end_subject - pp); - if (p == NULL) p = end_subject; - } -#endif /* PCRE2_CODE_UNIT_WIDTH != 8 */ - } - - /* The caseful case */ - - else - { -#if PCRE2_CODE_UNIT_WIDTH != 8 - while (p < end_subject) - { - if (UCHAR21INCTEST(p) == req_cu) { p--; break; } - } - -#else /* 8-bit code units */ - p = memchr(p, req_cu, end_subject - p); - if (p == NULL) p = end_subject; -#endif - } - - /* If we can't find the required code unit, break the matching loop, - forcing a match failure. */ - - if (p >= end_subject) break; - - /* If we have found the required code unit, save the point where we - found it, so that we don't search again next time round the loop if - the start hasn't passed this code unit yet. */ - - req_cu_ptr = p; - } - } - } - } - - /* ------------ End of start of match optimizations ------------ */ - - /* Give no match if we have passed the bumpalong limit. */ - - if (start_match > bumpalong_limit) break; - - /* OK, now we can do the business */ - - mb->start_used_ptr = start_match; - mb->last_used_ptr = start_match; - mb->recursive = NULL; - - rc = internal_dfa_match( - mb, /* fixed match data */ - mb->start_code, /* this subexpression's code */ - start_match, /* where we currently are */ - start_offset, /* start offset in subject */ - match_data->ovector, /* offset vector */ - (uint32_t)match_data->oveccount * 2, /* actual size of same */ - workspace, /* workspace vector */ - (int)wscount, /* size of same */ - 0, /* function recurse level */ - base_recursion_workspace); /* initial workspace for recursion */ - - /* Anything other than "no match" means we are done, always; otherwise, carry - on only if not anchored. */ - - if (rc != PCRE2_ERROR_NOMATCH || anchored) - { - if (rc == PCRE2_ERROR_PARTIAL && match_data->oveccount > 0) - { - match_data->ovector[0] = (PCRE2_SIZE)(start_match - subject); - match_data->ovector[1] = (PCRE2_SIZE)(end_subject - subject); - } - match_data->leftchar = (PCRE2_SIZE)(mb->start_used_ptr - subject); - match_data->rightchar = (PCRE2_SIZE)( mb->last_used_ptr - subject); - match_data->startchar = (PCRE2_SIZE)(start_match - subject); - match_data->rc = rc; - - if (rc >= 0 &&(options & PCRE2_COPY_MATCHED_SUBJECT) != 0) - { - length = CU2BYTES(length + was_zero_terminated); - match_data->subject = match_data->memctl.malloc(length, - match_data->memctl.memory_data); - if (match_data->subject == NULL) return PCRE2_ERROR_NOMEMORY; - memcpy((void *)match_data->subject, subject, length); - match_data->flags |= PCRE2_MD_COPIED_SUBJECT; - } - else - { - if (rc >= 0 || rc == PCRE2_ERROR_PARTIAL) match_data->subject = subject; - } - goto EXIT; - } - - /* Advance to the next subject character unless we are at the end of a line - and firstline is set. */ - - if (firstline && IS_NEWLINE(start_match)) break; - start_match++; -#ifdef SUPPORT_UNICODE - if (utf) - { - ACROSSCHAR(start_match < end_subject, start_match, start_match++); - } -#endif - if (start_match > end_subject) break; - - /* If we have just passed a CR and we are now at a LF, and the pattern does - not contain any explicit matches for \r or \n, and the newline option is CRLF - or ANY or ANYCRLF, advance the match position by one more character. */ - - if (UCHAR21TEST(start_match - 1) == CHAR_CR && - start_match < end_subject && - UCHAR21TEST(start_match) == CHAR_NL && - (re->flags & PCRE2_HASCRORLF) == 0 && - (mb->nltype == NLTYPE_ANY || - mb->nltype == NLTYPE_ANYCRLF || - mb->nllen == 2)) - start_match++; - - } /* "Bumpalong" loop */ - -NOMATCH_EXIT: -rc = PCRE2_ERROR_NOMATCH; - -EXIT: -while (rws->next != NULL) - { - RWS_anchor *next = rws->next; - rws->next = next->next; - mb->memctl.free(next, mb->memctl.memory_data); - } - -return rc; -} - -/* These #undefs are here to enable unity builds with CMake. */ - -#undef NLBLOCK /* Block containing newline information */ -#undef PSSTART /* Field containing processed string start */ -#undef PSEND /* Field containing processed string end */ - -/* End of pcre2_dfa_match.c */ diff --git a/modules/regex/pcre2/src/pcre2_error.c b/modules/regex/pcre2/src/pcre2_error.c deleted file mode 100644 index 09904c0..0000000 --- a/modules/regex/pcre2/src/pcre2_error.c +++ /dev/null @@ -1,341 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -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 - ------------------------------------------------------------------------------ -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 OWNER 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. ------------------------------------------------------------------------------ -*/ - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "pcre2_internal.h" - -#define STRING(a) # a -#define XSTRING(s) STRING(s) - -/* The texts of compile-time error messages. Compile-time error numbers start -at COMPILE_ERROR_BASE (100). - -This used to be a table of strings, but in order to reduce the number of -relocations needed when a shared library is loaded dynamically, it is now one -long string. We cannot use a table of offsets, because the lengths of inserts -such as XSTRING(MAX_NAME_SIZE) are not known. Instead, -pcre2_get_error_message() counts through to the one it wants - this isn't a -performance issue because these strings are used only when there is an error. - -Each substring ends with \0 to insert a null character. This includes the final -substring, so that the whole string ends with \0\0, which can be detected when -counting through. */ - -static const unsigned char compile_error_texts[] = - "no error\0" - "\\ at end of pattern\0" - "\\c at end of pattern\0" - "unrecognized character follows \\\0" - "numbers out of order in {} quantifier\0" - /* 5 */ - "number too big in {} quantifier\0" - "missing terminating ] for character class\0" - "escape sequence is invalid in character class\0" - "range out of order in character class\0" - "quantifier does not follow a repeatable item\0" - /* 10 */ - "internal error: unexpected repeat\0" - "unrecognized character after (? or (?-\0" - "POSIX named classes are supported only within a class\0" - "POSIX collating elements are not supported\0" - "missing closing parenthesis\0" - /* 15 */ - "reference to non-existent subpattern\0" - "pattern passed as NULL\0" - "unrecognised compile-time option bit(s)\0" - "missing ) after (?# comment\0" - "parentheses are too deeply nested\0" - /* 20 */ - "regular expression is too large\0" - "failed to allocate heap memory\0" - "unmatched closing parenthesis\0" - "internal error: code overflow\0" - "missing closing parenthesis for condition\0" - /* 25 */ - "lookbehind assertion is not fixed length\0" - "a relative value of zero is not allowed\0" - "conditional subpattern contains more than two branches\0" - "assertion expected after (?( or (?(?C)\0" - "digit expected after (?+ or (?-\0" - /* 30 */ - "unknown POSIX class name\0" - "internal error in pcre2_study(): should not occur\0" - "this version of PCRE2 does not have Unicode support\0" - "parentheses are too deeply nested (stack check)\0" - "character code point value in \\x{} or \\o{} is too large\0" - /* 35 */ - "lookbehind is too complicated\0" - "\\C is not allowed in a lookbehind assertion in UTF-" XSTRING(PCRE2_CODE_UNIT_WIDTH) " mode\0" - "PCRE2 does not support \\F, \\L, \\l, \\N{name}, \\U, or \\u\0" - "number after (?C is greater than 255\0" - "closing parenthesis for (?C expected\0" - /* 40 */ - "invalid escape sequence in (*VERB) name\0" - "unrecognized character after (?P\0" - "syntax error in subpattern name (missing terminator?)\0" - "two named subpatterns have the same name (PCRE2_DUPNAMES not set)\0" - "subpattern name must start with a non-digit\0" - /* 45 */ - "this version of PCRE2 does not have support for \\P, \\p, or \\X\0" - "malformed \\P or \\p sequence\0" - "unknown property after \\P or \\p\0" - "subpattern name is too long (maximum " XSTRING(MAX_NAME_SIZE) " code units)\0" - "too many named subpatterns (maximum " XSTRING(MAX_NAME_COUNT) ")\0" - /* 50 */ - "invalid range in character class\0" - "octal value is greater than \\377 in 8-bit non-UTF-8 mode\0" - "internal error: overran compiling workspace\0" - "internal error: previously-checked referenced subpattern not found\0" - "DEFINE subpattern contains more than one branch\0" - /* 55 */ - "missing opening brace after \\o\0" - "internal error: unknown newline setting\0" - "\\g is not followed by a braced, angle-bracketed, or quoted name/number or by a plain number\0" - "(?R (recursive pattern call) must be followed by a closing parenthesis\0" - /* "an argument is not allowed for (*ACCEPT), (*FAIL), or (*COMMIT)\0" */ - "obsolete error (should not occur)\0" /* Was the above */ - /* 60 */ - "(*VERB) not recognized or malformed\0" - "subpattern number is too big\0" - "subpattern name expected\0" - "internal error: parsed pattern overflow\0" - "non-octal character in \\o{} (closing brace missing?)\0" - /* 65 */ - "different names for subpatterns of the same number are not allowed\0" - "(*MARK) must have an argument\0" - "non-hex character in \\x{} (closing brace missing?)\0" -#ifndef EBCDIC - "\\c must be followed by a printable ASCII character\0" -#else - "\\c must be followed by a letter or one of [\\]^_?\0" -#endif - "\\k is not followed by a braced, angle-bracketed, or quoted name\0" - /* 70 */ - "internal error: unknown meta code in check_lookbehinds()\0" - "\\N is not supported in a class\0" - "callout string is too long\0" - "disallowed Unicode code point (>= 0xd800 && <= 0xdfff)\0" - "using UTF is disabled by the application\0" - /* 75 */ - "using UCP is disabled by the application\0" - "name is too long in (*MARK), (*PRUNE), (*SKIP), or (*THEN)\0" - "character code point value in \\u.... sequence is too large\0" - "digits missing in \\x{} or \\o{} or \\N{U+}\0" - "syntax error or number too big in (?(VERSION condition\0" - /* 80 */ - "internal error: unknown opcode in auto_possessify()\0" - "missing terminating delimiter for callout with string argument\0" - "unrecognized string delimiter follows (?C\0" - "using \\C is disabled by the application\0" - "(?| and/or (?J: or (?x: parentheses are too deeply nested\0" - /* 85 */ - "using \\C is disabled in this PCRE2 library\0" - "regular expression is too complicated\0" - "lookbehind assertion is too long\0" - "pattern string is longer than the limit set by the application\0" - "internal error: unknown code in parsed pattern\0" - /* 90 */ - "internal error: bad code value in parsed_skip()\0" - "PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES is not allowed in UTF-16 mode\0" - "invalid option bits with PCRE2_LITERAL\0" - "\\N{U+dddd} is supported only in Unicode (UTF) mode\0" - "invalid hyphen in option setting\0" - /* 95 */ - "(*alpha_assertion) not recognized\0" - "script runs require Unicode support, which this version of PCRE2 does not have\0" - "too many capturing groups (maximum 65535)\0" - "atomic assertion expected after (?( or (?(?C)\0" - "\\K is not allowed in lookarounds (but see PCRE2_EXTRA_ALLOW_LOOKAROUND_BSK)\0" - ; - -/* Match-time and UTF error texts are in the same format. */ - -static const unsigned char match_error_texts[] = - "no error\0" - "no match\0" - "partial match\0" - "UTF-8 error: 1 byte missing at end\0" - "UTF-8 error: 2 bytes missing at end\0" - /* 5 */ - "UTF-8 error: 3 bytes missing at end\0" - "UTF-8 error: 4 bytes missing at end\0" - "UTF-8 error: 5 bytes missing at end\0" - "UTF-8 error: byte 2 top bits not 0x80\0" - "UTF-8 error: byte 3 top bits not 0x80\0" - /* 10 */ - "UTF-8 error: byte 4 top bits not 0x80\0" - "UTF-8 error: byte 5 top bits not 0x80\0" - "UTF-8 error: byte 6 top bits not 0x80\0" - "UTF-8 error: 5-byte character is not allowed (RFC 3629)\0" - "UTF-8 error: 6-byte character is not allowed (RFC 3629)\0" - /* 15 */ - "UTF-8 error: code points greater than 0x10ffff are not defined\0" - "UTF-8 error: code points 0xd800-0xdfff are not defined\0" - "UTF-8 error: overlong 2-byte sequence\0" - "UTF-8 error: overlong 3-byte sequence\0" - "UTF-8 error: overlong 4-byte sequence\0" - /* 20 */ - "UTF-8 error: overlong 5-byte sequence\0" - "UTF-8 error: overlong 6-byte sequence\0" - "UTF-8 error: isolated byte with 0x80 bit set\0" - "UTF-8 error: illegal byte (0xfe or 0xff)\0" - "UTF-16 error: missing low surrogate at end\0" - /* 25 */ - "UTF-16 error: invalid low surrogate\0" - "UTF-16 error: isolated low surrogate\0" - "UTF-32 error: code points 0xd800-0xdfff are not defined\0" - "UTF-32 error: code points greater than 0x10ffff are not defined\0" - "bad data value\0" - /* 30 */ - "patterns do not all use the same character tables\0" - "magic number missing\0" - "pattern compiled in wrong mode: 8/16/32-bit error\0" - "bad offset value\0" - "bad option value\0" - /* 35 */ - "invalid replacement string\0" - "bad offset into UTF string\0" - "callout error code\0" /* Never returned by PCRE2 itself */ - "invalid data in workspace for DFA restart\0" - "too much recursion for DFA matching\0" - /* 40 */ - "backreference condition or recursion test is not supported for DFA matching\0" - "function is not supported for DFA matching\0" - "pattern contains an item that is not supported for DFA matching\0" - "workspace size exceeded in DFA matching\0" - "internal error - pattern overwritten?\0" - /* 45 */ - "bad JIT option\0" - "JIT stack limit reached\0" - "match limit exceeded\0" - "no more memory\0" - "unknown substring\0" - /* 50 */ - "non-unique substring name\0" - "NULL argument passed with non-zero length\0" - "nested recursion at the same subject position\0" - "matching depth limit exceeded\0" - "requested value is not available\0" - /* 55 */ - "requested value is not set\0" - "offset limit set without PCRE2_USE_OFFSET_LIMIT\0" - "bad escape sequence in replacement string\0" - "expected closing curly bracket in replacement string\0" - "bad substitution in replacement string\0" - /* 60 */ - "match with end before start or start moved backwards is not supported\0" - "too many replacements (more than INT_MAX)\0" - "bad serialized data\0" - "heap limit exceeded\0" - "invalid syntax\0" - /* 65 */ - "internal error - duplicate substitution match\0" - "PCRE2_MATCH_INVALID_UTF is not supported for DFA matching\0" - ; - - -/************************************************* -* Return error message * -*************************************************/ - -/* This function copies an error message into a buffer whose units are of an -appropriate width. Error numbers are positive for compile-time errors, and -negative for match-time errors (except for UTF errors), but the numbers are all -distinct. - -Arguments: - enumber error number - buffer where to put the message (zero terminated) - size size of the buffer in code units - -Returns: length of message if all is well - negative on error -*/ - -PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION -pcre2_get_error_message(int enumber, PCRE2_UCHAR *buffer, PCRE2_SIZE size) -{ -const unsigned char *message; -PCRE2_SIZE i; -int n; - -if (size == 0) return PCRE2_ERROR_NOMEMORY; - -if (enumber >= COMPILE_ERROR_BASE) /* Compile error */ - { - message = compile_error_texts; - n = enumber - COMPILE_ERROR_BASE; - } -else if (enumber < 0) /* Match or UTF error */ - { - message = match_error_texts; - n = -enumber; - } -else /* Invalid error number */ - { - message = (unsigned char *)"\0"; /* Empty message list */ - n = 1; - } - -for (; n > 0; n--) - { - while (*message++ != CHAR_NUL) {}; - if (*message == CHAR_NUL) return PCRE2_ERROR_BADDATA; - } - -for (i = 0; *message != 0; i++) - { - if (i >= size - 1) - { - buffer[i] = 0; /* Terminate partial message */ - return PCRE2_ERROR_NOMEMORY; - } - buffer[i] = *message++; - } - -buffer[i] = 0; -return (int)i; -} - -/* End of pcre2_error.c */ diff --git a/modules/regex/pcre2/src/pcre2_extuni.c b/modules/regex/pcre2/src/pcre2_extuni.c deleted file mode 100644 index b23946b..0000000 --- a/modules/regex/pcre2/src/pcre2_extuni.c +++ /dev/null @@ -1,148 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -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 - ------------------------------------------------------------------------------ -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 OWNER 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. ------------------------------------------------------------------------------ -*/ - -/* This module contains an internal function that is used to match a Unicode -extended grapheme sequence. It is used by both pcre2_match() and -pcre2_def_match(). However, it is called only when Unicode support is being -compiled. Nevertheless, we provide a dummy function when there is no Unicode -support, because some compilers do not like functionless source files. */ - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - - -#include "pcre2_internal.h" - - -/* Dummy function */ - -#ifndef SUPPORT_UNICODE -PCRE2_SPTR -PRIV(extuni)(uint32_t c, PCRE2_SPTR eptr, PCRE2_SPTR start_subject, - PCRE2_SPTR end_subject, BOOL utf, int *xcount) -{ -(void)c; -(void)eptr; -(void)start_subject; -(void)end_subject; -(void)utf; -(void)xcount; -return NULL; -} -#else - - -/************************************************* -* Match an extended grapheme sequence * -*************************************************/ - -/* -Arguments: - c the first character - eptr pointer to next character - start_subject pointer to start of subject - end_subject pointer to end of subject - utf TRUE if in UTF mode - xcount pointer to count of additional characters, - or NULL if count not needed - -Returns: pointer after the end of the sequence -*/ - -PCRE2_SPTR -PRIV(extuni)(uint32_t c, PCRE2_SPTR eptr, PCRE2_SPTR start_subject, - PCRE2_SPTR end_subject, BOOL utf, int *xcount) -{ -int lgb = UCD_GRAPHBREAK(c); - -while (eptr < end_subject) - { - int rgb; - int len = 1; - if (!utf) c = *eptr; else { GETCHARLEN(c, eptr, len); } - rgb = UCD_GRAPHBREAK(c); - if ((PRIV(ucp_gbtable)[lgb] & (1u << rgb)) == 0) break; - - /* Not breaking between Regional Indicators is allowed only if there - are an even number of preceding RIs. */ - - if (lgb == ucp_gbRegional_Indicator && rgb == ucp_gbRegional_Indicator) - { - int ricount = 0; - PCRE2_SPTR bptr = eptr - 1; - if (utf) BACKCHAR(bptr); - - /* bptr is pointing to the left-hand character */ - - while (bptr > start_subject) - { - bptr--; - if (utf) - { - BACKCHAR(bptr); - GETCHAR(c, bptr); - } - else - c = *bptr; - if (UCD_GRAPHBREAK(c) != ucp_gbRegional_Indicator) break; - ricount++; - } - 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. */ - - if ((rgb != ucp_gbExtend && rgb != ucp_gbZWJ) || - lgb != ucp_gbExtended_Pictographic) - lgb = rgb; - - eptr += len; - if (xcount != NULL) *xcount += 1; - } - -return eptr; -} - -#endif /* SUPPORT_UNICODE */ - -/* End of pcre2_extuni.c */ diff --git a/modules/regex/pcre2/src/pcre2_find_bracket.c b/modules/regex/pcre2/src/pcre2_find_bracket.c deleted file mode 100644 index 70baa13..0000000 --- a/modules/regex/pcre2/src/pcre2_find_bracket.c +++ /dev/null @@ -1,219 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -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-2018 University of Cambridge - ------------------------------------------------------------------------------ -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 OWNER 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. ------------------------------------------------------------------------------ -*/ - - -/* This module contains a single function that scans through a compiled pattern -until it finds a capturing bracket with the given number, or, if the number is -negative, an instance of OP_REVERSE for a lookbehind. The function is called -from pcre2_compile.c and also from pcre2_study.c when finding the minimum -matching length. */ - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "pcre2_internal.h" - - -/************************************************* -* Scan compiled regex for specific bracket * -*************************************************/ - -/* -Arguments: - code points to start of expression - utf TRUE in UTF mode - number the required bracket number or negative to find a lookbehind - -Returns: pointer to the opcode for the bracket, or NULL if not found -*/ - -PCRE2_SPTR -PRIV(find_bracket)(PCRE2_SPTR code, BOOL utf, int number) -{ -for (;;) - { - PCRE2_UCHAR c = *code; - - if (c == OP_END) return NULL; - - /* XCLASS is used for classes that cannot be represented just by a bit map. - This includes negated single high-valued characters. CALLOUT_STR is used for - callouts with string arguments. In both cases the length in the table is - zero; the actual length is stored in the compiled code. */ - - if (c == OP_XCLASS) code += GET(code, 1); - else if (c == OP_CALLOUT_STR) code += GET(code, 1 + 2*LINK_SIZE); - - /* Handle lookbehind */ - - else if (c == OP_REVERSE) - { - if (number < 0) return (PCRE2_UCHAR *)code; - code += PRIV(OP_lengths)[c]; - } - - /* Handle capturing bracket */ - - else if (c == OP_CBRA || c == OP_SCBRA || - c == OP_CBRAPOS || c == OP_SCBRAPOS) - { - int n = (int)GET2(code, 1+LINK_SIZE); - if (n == number) return (PCRE2_UCHAR *)code; - code += PRIV(OP_lengths)[c]; - } - - /* Otherwise, we can get the item's length from the table, except that for - repeated character types, we have to test for \p and \P, which have an extra - two bytes of parameters, and for MARK/PRUNE/SKIP/THEN with an argument, we - must add in its length. */ - - else - { - switch(c) - { - case OP_TYPESTAR: - case OP_TYPEMINSTAR: - case OP_TYPEPLUS: - case OP_TYPEMINPLUS: - case OP_TYPEQUERY: - case OP_TYPEMINQUERY: - case OP_TYPEPOSSTAR: - case OP_TYPEPOSPLUS: - case OP_TYPEPOSQUERY: - if (code[1] == OP_PROP || code[1] == OP_NOTPROP) code += 2; - break; - - case OP_TYPEUPTO: - case OP_TYPEMINUPTO: - case OP_TYPEEXACT: - case OP_TYPEPOSUPTO: - if (code[1 + IMM2_SIZE] == OP_PROP || code[1 + IMM2_SIZE] == OP_NOTPROP) - code += 2; - break; - - case OP_MARK: - case OP_COMMIT_ARG: - case OP_PRUNE_ARG: - case OP_SKIP_ARG: - case OP_THEN_ARG: - code += code[1]; - break; - } - - /* Add in the fixed length from the table */ - - code += PRIV(OP_lengths)[c]; - - /* In UTF-8 and UTF-16 modes, opcodes that are followed by a character may be - followed by a multi-byte character. The length in the table is a minimum, so - we have to arrange to skip the extra bytes. */ - -#ifdef MAYBE_UTF_MULTI - if (utf) switch(c) - { - case OP_CHAR: - case OP_CHARI: - case OP_NOT: - case OP_NOTI: - case OP_EXACT: - case OP_EXACTI: - case OP_NOTEXACT: - case OP_NOTEXACTI: - case OP_UPTO: - case OP_UPTOI: - case OP_NOTUPTO: - case OP_NOTUPTOI: - case OP_MINUPTO: - case OP_MINUPTOI: - case OP_NOTMINUPTO: - case OP_NOTMINUPTOI: - case OP_POSUPTO: - case OP_POSUPTOI: - case OP_NOTPOSUPTO: - case OP_NOTPOSUPTOI: - case OP_STAR: - case OP_STARI: - case OP_NOTSTAR: - case OP_NOTSTARI: - case OP_MINSTAR: - case OP_MINSTARI: - case OP_NOTMINSTAR: - case OP_NOTMINSTARI: - case OP_POSSTAR: - case OP_POSSTARI: - case OP_NOTPOSSTAR: - case OP_NOTPOSSTARI: - case OP_PLUS: - case OP_PLUSI: - case OP_NOTPLUS: - case OP_NOTPLUSI: - case OP_MINPLUS: - case OP_MINPLUSI: - case OP_NOTMINPLUS: - case OP_NOTMINPLUSI: - case OP_POSPLUS: - case OP_POSPLUSI: - case OP_NOTPOSPLUS: - case OP_NOTPOSPLUSI: - case OP_QUERY: - case OP_QUERYI: - case OP_NOTQUERY: - case OP_NOTQUERYI: - case OP_MINQUERY: - case OP_MINQUERYI: - case OP_NOTMINQUERY: - case OP_NOTMINQUERYI: - case OP_POSQUERY: - case OP_POSQUERYI: - case OP_NOTPOSQUERY: - case OP_NOTPOSQUERYI: - if (HAS_EXTRALEN(code[-1])) code += GET_EXTRALEN(code[-1]); - break; - } -#else - (void)(utf); /* Keep compiler happy by referencing function argument */ -#endif /* MAYBE_UTF_MULTI */ - } - } -} - -/* End of pcre2_find_bracket.c */ diff --git a/modules/regex/pcre2/src/pcre2_internal.h b/modules/regex/pcre2/src/pcre2_internal.h deleted file mode 100644 index 92dd313..0000000 --- a/modules/regex/pcre2/src/pcre2_internal.h +++ /dev/null @@ -1,2047 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE2 is a library of functions to support regular expressions whose syntax -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-2022 University of Cambridge - ------------------------------------------------------------------------------ -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 OWNER 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. ------------------------------------------------------------------------------ -*/ - -#ifndef PCRE2_INTERNAL_H_IDEMPOTENT_GUARD -#define PCRE2_INTERNAL_H_IDEMPOTENT_GUARD - -/* We do not support both EBCDIC and Unicode at the same time. The "configure" -script prevents both being selected, but not everybody uses "configure". EBCDIC -is only supported for the 8-bit library, but the check for this has to be later -in this file, because the first part is not width-dependent, and is included by -pcre2test.c with CODE_UNIT_WIDTH == 0. */ - -#if defined EBCDIC && defined SUPPORT_UNICODE -#error The use of both EBCDIC and SUPPORT_UNICODE is not supported. -#endif - -/* Standard C headers */ - -#include -#include -#include -#include -#include -#include - -/* Macros to make boolean values more obvious. The #ifndef is to pacify -compiler warnings in environments where these macros are defined elsewhere. -Unfortunately, there is no way to do the same for the typedef. */ - -typedef int BOOL; -#ifndef FALSE -#define FALSE 0 -#define TRUE 1 -#endif - -/* Valgrind (memcheck) support */ - -#ifdef SUPPORT_VALGRIND -#include -#endif - -/* -ftrivial-auto-var-init support supports initializing all local variables -to avoid some classes of bug, but this can cause an unacceptable slowdown -for large on-stack arrays in hot functions. This macro lets us annotate -such arrays. */ - -#ifdef HAVE_ATTRIBUTE_UNINITIALIZED -#define PCRE2_KEEP_UNINITIALIZED __attribute__((uninitialized)) -#else -#define PCRE2_KEEP_UNINITIALIZED -#endif - -/* Older versions of MSVC lack snprintf(). This define allows for -warning/error-free compilation and testing with MSVC compilers back to at least -MSVC 10/2010. Except for VC6 (which is missing some fundamentals and fails). */ - -#if defined(_MSC_VER) && (_MSC_VER < 1900) -#define snprintf _snprintf -#endif - -/* When compiling a DLL for Windows, the exported symbols have to be declared -using some MS magic. I found some useful information on this web page: -http://msdn2.microsoft.com/en-us/library/y4h7bcy6(VS.80).aspx. According to the -information there, using __declspec(dllexport) without "extern" we have a -definition; with "extern" we have a declaration. The settings here override the -setting in pcre2.h (which is included below); it defines only PCRE2_EXP_DECL, -which is all that is needed for applications (they just import the symbols). We -use: - - PCRE2_EXP_DECL for declarations - PCRE2_EXP_DEFN for definitions - -The reason for wrapping this in #ifndef PCRE2_EXP_DECL is so that pcre2test, -which is an application, but needs to import this file in order to "peek" at -internals, can #include pcre2.h first to get an application's-eye view. - -In principle, people compiling for non-Windows, non-Unix-like (i.e. uncommon, -special-purpose environments) might want to stick other stuff in front of -exported symbols. That's why, in the non-Windows case, we set PCRE2_EXP_DEFN -only if it is not already set. */ - -#ifndef PCRE2_EXP_DECL -# ifdef _WIN32 -# ifndef PCRE2_STATIC -# define PCRE2_EXP_DECL extern __declspec(dllexport) -# define PCRE2_EXP_DEFN __declspec(dllexport) -# else -# define PCRE2_EXP_DECL extern -# define PCRE2_EXP_DEFN -# endif -# else -# ifdef __cplusplus -# define PCRE2_EXP_DECL extern "C" -# else -# define PCRE2_EXP_DECL extern -# endif -# ifndef PCRE2_EXP_DEFN -# define PCRE2_EXP_DEFN PCRE2_EXP_DECL -# endif -# endif -#endif - -/* Include the public PCRE2 header and the definitions of UCP character -property values. This must follow the setting of PCRE2_EXP_DECL above. */ - -#include "pcre2.h" -#include "pcre2_ucp.h" - -/* When PCRE2 is compiled as a C++ library, the subject pointer can be replaced -with a custom type. This makes it possible, for example, to allow pcre2_match() -to process subject strings that are discontinuous by using a smart pointer -class. It must always be possible to inspect all of the subject string in -pcre2_match() because of the way it backtracks. */ - -/* WARNING: This is as yet untested for PCRE2. */ - -#ifdef CUSTOM_SUBJECT_PTR -#undef PCRE2_SPTR -#define PCRE2_SPTR CUSTOM_SUBJECT_PTR -#endif - -/* When checking for integer overflow in pcre2_compile(), we need to handle -large integers. If a 64-bit integer type is available, we can use that. -Otherwise we have to cast to double, which of course requires floating point -arithmetic. Handle this by defining a macro for the appropriate type. */ - -#if defined INT64_MAX || defined int64_t -#define INT64_OR_DOUBLE int64_t -#else -#define INT64_OR_DOUBLE double -#endif - -/* External (in the C sense) functions and tables that are private to the -libraries are always referenced using the PRIV macro. This makes it possible -for pcre2test.c to include some of the source files from the libraries using a -different PRIV definition to avoid name clashes. It also makes it clear in the -code that a non-static object is being referenced. */ - -#ifndef PRIV -#define PRIV(name) _pcre2_##name -#endif - -/* When compiling for use with the Virtual Pascal compiler, these functions -need to have their names changed. PCRE2 must be compiled with the -DVPCOMPAT -option on the command line. */ - -#ifdef VPCOMPAT -#define strlen(s) _strlen(s) -#define strncmp(s1,s2,m) _strncmp(s1,s2,m) -#define memcmp(s,c,n) _memcmp(s,c,n) -#define memcpy(d,s,n) _memcpy(d,s,n) -#define memmove(d,s,n) _memmove(d,s,n) -#define memset(s,c,n) _memset(s,c,n) -#else /* VPCOMPAT */ - -/* Otherwise, to cope with SunOS4 and other systems that lack memmove(), define -a macro that calls an emulating function. */ - -#ifndef HAVE_MEMMOVE -#undef memmove /* Some systems may have a macro */ -#define memmove(a, b, c) PRIV(memmove)(a, b, c) -#endif /* not HAVE_MEMMOVE */ -#endif /* not VPCOMPAT */ - -/* This is an unsigned int value that no UTF character can ever have, as -Unicode doesn't go beyond 0x0010ffff. */ - -#define NOTACHAR 0xffffffff - -/* This is the largest valid UTF/Unicode code point. */ - -#define MAX_UTF_CODE_POINT 0x10ffff - -/* Compile-time positive error numbers (all except UTF errors, which are -negative) start at this value. It should probably never be changed, in case -some application is checking for specific numbers. There is a copy of this -#define in pcre2posix.c (which now no longer includes this file). Ideally, a -way of having a single definition should be found, but as the number is -unlikely to change, this is not a pressing issue. The original reason for -having a base other than 0 was to keep the absolute values of compile-time and -run-time error numbers numerically different, but in the event the code does -not rely on this. */ - -#define COMPILE_ERROR_BASE 100 - -/* The initial frames vector for remembering pcre2_match() backtracking points -is allocated on the heap, of this size (bytes) or ten times the frame size if -larger, unless the heap limit is smaller. Typical frame sizes are a few hundred -bytes (it depends on the number of capturing parentheses) so 20KiB handles -quite a few frames. A larger vector on the heap is obtained for matches that -need more frames, subject to the heap limit. */ - -#define START_FRAMES_SIZE 20480 - -/* For DFA matching, an initial internal workspace vector is allocated on the -stack. The heap is used only if this turns out to be too small. */ - -#define DFA_START_RWS_SIZE 30720 - -/* Define the default BSR convention. */ - -#ifdef BSR_ANYCRLF -#define BSR_DEFAULT PCRE2_BSR_ANYCRLF -#else -#define BSR_DEFAULT PCRE2_BSR_UNICODE -#endif - - -/* ---------------- Basic UTF-8 macros ---------------- */ - -/* These UTF-8 macros are always defined because they are used in pcre2test for -handling wide characters in 16-bit and 32-bit modes, even if an 8-bit library -is not supported. */ - -/* Tests whether a UTF-8 code point needs extra bytes to decode. */ - -#define HASUTF8EXTRALEN(c) ((c) >= 0xc0) - -/* The following macros were originally written in the form of loops that used -data from the tables whose names start with PRIV(utf8_table). They were -rewritten by a user so as not to use loops, because in some environments this -gives a significant performance advantage, and it seems never to do any harm. -*/ - -/* Base macro to pick up the remaining bytes of a UTF-8 character, not -advancing the pointer. */ - -#define GETUTF8(c, eptr) \ - { \ - if ((c & 0x20u) == 0) \ - c = ((c & 0x1fu) << 6) | (eptr[1] & 0x3fu); \ - else if ((c & 0x10u) == 0) \ - c = ((c & 0x0fu) << 12) | ((eptr[1] & 0x3fu) << 6) | (eptr[2] & 0x3fu); \ - else if ((c & 0x08u) == 0) \ - c = ((c & 0x07u) << 18) | ((eptr[1] & 0x3fu) << 12) | \ - ((eptr[2] & 0x3fu) << 6) | (eptr[3] & 0x3fu); \ - else if ((c & 0x04u) == 0) \ - c = ((c & 0x03u) << 24) | ((eptr[1] & 0x3fu) << 18) | \ - ((eptr[2] & 0x3fu) << 12) | ((eptr[3] & 0x3fu) << 6) | \ - (eptr[4] & 0x3fu); \ - else \ - c = ((c & 0x01u) << 30) | ((eptr[1] & 0x3fu) << 24) | \ - ((eptr[2] & 0x3fu) << 18) | ((eptr[3] & 0x3fu) << 12) | \ - ((eptr[4] & 0x3fu) << 6) | (eptr[5] & 0x3fu); \ - } - -/* Base macro to pick up the remaining bytes of a UTF-8 character, advancing -the pointer. */ - -#define GETUTF8INC(c, eptr) \ - { \ - if ((c & 0x20u) == 0) \ - c = ((c & 0x1fu) << 6) | (*eptr++ & 0x3fu); \ - else if ((c & 0x10u) == 0) \ - { \ - c = ((c & 0x0fu) << 12) | ((*eptr & 0x3fu) << 6) | (eptr[1] & 0x3fu); \ - eptr += 2; \ - } \ - else if ((c & 0x08u) == 0) \ - { \ - c = ((c & 0x07u) << 18) | ((*eptr & 0x3fu) << 12) | \ - ((eptr[1] & 0x3fu) << 6) | (eptr[2] & 0x3fu); \ - eptr += 3; \ - } \ - else if ((c & 0x04u) == 0) \ - { \ - c = ((c & 0x03u) << 24) | ((*eptr & 0x3fu) << 18) | \ - ((eptr[1] & 0x3fu) << 12) | ((eptr[2] & 0x3fu) << 6) | \ - (eptr[3] & 0x3fu); \ - eptr += 4; \ - } \ - else \ - { \ - c = ((c & 0x01u) << 30) | ((*eptr & 0x3fu) << 24) | \ - ((eptr[1] & 0x3fu) << 18) | ((eptr[2] & 0x3fu) << 12) | \ - ((eptr[3] & 0x3fu) << 6) | (eptr[4] & 0x3fu); \ - eptr += 5; \ - } \ - } - -/* Base macro to pick up the remaining bytes of a UTF-8 character, not -advancing the pointer, incrementing the length. */ - -#define GETUTF8LEN(c, eptr, len) \ - { \ - if ((c & 0x20u) == 0) \ - { \ - c = ((c & 0x1fu) << 6) | (eptr[1] & 0x3fu); \ - len++; \ - } \ - else if ((c & 0x10u) == 0) \ - { \ - c = ((c & 0x0fu) << 12) | ((eptr[1] & 0x3fu) << 6) | (eptr[2] & 0x3fu); \ - len += 2; \ - } \ - else if ((c & 0x08u) == 0) \ - {\ - c = ((c & 0x07u) << 18) | ((eptr[1] & 0x3fu) << 12) | \ - ((eptr[2] & 0x3fu) << 6) | (eptr[3] & 0x3fu); \ - len += 3; \ - } \ - else if ((c & 0x04u) == 0) \ - { \ - c = ((c & 0x03u) << 24) | ((eptr[1] & 0x3fu) << 18) | \ - ((eptr[2] & 0x3fu) << 12) | ((eptr[3] & 0x3fu) << 6) | \ - (eptr[4] & 0x3fu); \ - len += 4; \ - } \ - else \ - {\ - c = ((c & 0x01u) << 30) | ((eptr[1] & 0x3fu) << 24) | \ - ((eptr[2] & 0x3fu) << 18) | ((eptr[3] & 0x3fu) << 12) | \ - ((eptr[4] & 0x3fu) << 6) | (eptr[5] & 0x3fu); \ - len += 5; \ - } \ - } - -/* --------------- Whitespace macros ---------------- */ - -/* Tests for Unicode horizontal and vertical whitespace characters must check a -number of different values. Using a switch statement for this generates the -fastest code (no loop, no memory access), and there are several places in the -interpreter code where this happens. In order to ensure that all the case lists -remain in step, we use macros so that there is only one place where the lists -are defined. - -These values are also required as lists in pcre2_compile.c when processing \h, -\H, \v and \V in a character class. The lists are defined in pcre2_tables.c, -but macros that define the values are here so that all the definitions are -together. The lists must be in ascending character order, terminated by -NOTACHAR (which is 0xffffffff). - -Any changes should ensure that the various macros are kept in step with each -other. NOTE: The values also appear in pcre2_jit_compile.c. */ - -/* -------------- ASCII/Unicode environments -------------- */ - -#ifndef EBCDIC - -/* Character U+180E (Mongolian Vowel Separator) is not included in the list of -spaces in the Unicode file PropList.txt, and Perl does not recognize it as a -space. However, in many other sources it is listed as a space and has been in -PCRE (both APIs) for a long time. */ - -#define HSPACE_LIST \ - CHAR_HT, CHAR_SPACE, CHAR_NBSP, \ - 0x1680, 0x180e, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, \ - 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x202f, 0x205f, 0x3000, \ - NOTACHAR - -#define HSPACE_MULTIBYTE_CASES \ - case 0x1680: /* OGHAM SPACE MARK */ \ - case 0x180e: /* MONGOLIAN VOWEL SEPARATOR */ \ - case 0x2000: /* EN QUAD */ \ - case 0x2001: /* EM QUAD */ \ - case 0x2002: /* EN SPACE */ \ - case 0x2003: /* EM SPACE */ \ - case 0x2004: /* THREE-PER-EM SPACE */ \ - case 0x2005: /* FOUR-PER-EM SPACE */ \ - case 0x2006: /* SIX-PER-EM SPACE */ \ - case 0x2007: /* FIGURE SPACE */ \ - case 0x2008: /* PUNCTUATION SPACE */ \ - case 0x2009: /* THIN SPACE */ \ - case 0x200A: /* HAIR SPACE */ \ - case 0x202f: /* NARROW NO-BREAK SPACE */ \ - case 0x205f: /* MEDIUM MATHEMATICAL SPACE */ \ - case 0x3000 /* IDEOGRAPHIC SPACE */ - -#define HSPACE_BYTE_CASES \ - case CHAR_HT: \ - case CHAR_SPACE: \ - case CHAR_NBSP - -#define HSPACE_CASES \ - HSPACE_BYTE_CASES: \ - HSPACE_MULTIBYTE_CASES - -#define VSPACE_LIST \ - CHAR_LF, CHAR_VT, CHAR_FF, CHAR_CR, CHAR_NEL, 0x2028, 0x2029, NOTACHAR - -#define VSPACE_MULTIBYTE_CASES \ - case 0x2028: /* LINE SEPARATOR */ \ - case 0x2029 /* PARAGRAPH SEPARATOR */ - -#define VSPACE_BYTE_CASES \ - case CHAR_LF: \ - case CHAR_VT: \ - case CHAR_FF: \ - case CHAR_CR: \ - case CHAR_NEL - -#define VSPACE_CASES \ - VSPACE_BYTE_CASES: \ - VSPACE_MULTIBYTE_CASES - -/* -------------- EBCDIC environments -------------- */ - -#else -#define HSPACE_LIST CHAR_HT, CHAR_SPACE, CHAR_NBSP, NOTACHAR - -#define HSPACE_BYTE_CASES \ - case CHAR_HT: \ - case CHAR_SPACE: \ - case CHAR_NBSP - -#define HSPACE_CASES HSPACE_BYTE_CASES - -#ifdef EBCDIC_NL25 -#define VSPACE_LIST \ - CHAR_VT, CHAR_FF, CHAR_CR, CHAR_NEL, CHAR_LF, NOTACHAR -#else -#define VSPACE_LIST \ - CHAR_VT, CHAR_FF, CHAR_CR, CHAR_LF, CHAR_NEL, NOTACHAR -#endif - -#define VSPACE_BYTE_CASES \ - case CHAR_LF: \ - case CHAR_VT: \ - case CHAR_FF: \ - case CHAR_CR: \ - case CHAR_NEL - -#define VSPACE_CASES VSPACE_BYTE_CASES -#endif /* EBCDIC */ - -/* -------------- End of whitespace macros -------------- */ - - -/* PCRE2 is able to support several different kinds of newline (CR, LF, CRLF, -"any" and "anycrlf" at present). The following macros are used to package up -testing for newlines. NLBLOCK, PSSTART, and PSEND are defined in the various -modules to indicate in which datablock the parameters exist, and what the -start/end of string field names are. */ - -#define NLTYPE_FIXED 0 /* Newline is a fixed length string */ -#define NLTYPE_ANY 1 /* Newline is any Unicode line ending */ -#define NLTYPE_ANYCRLF 2 /* Newline is CR, LF, or CRLF */ - -/* This macro checks for a newline at the given position */ - -#define IS_NEWLINE(p) \ - ((NLBLOCK->nltype != NLTYPE_FIXED)? \ - ((p) < NLBLOCK->PSEND && \ - PRIV(is_newline)((p), NLBLOCK->nltype, NLBLOCK->PSEND, \ - &(NLBLOCK->nllen), utf)) \ - : \ - ((p) <= NLBLOCK->PSEND - NLBLOCK->nllen && \ - UCHAR21TEST(p) == NLBLOCK->nl[0] && \ - (NLBLOCK->nllen == 1 || UCHAR21TEST(p+1) == NLBLOCK->nl[1]) \ - ) \ - ) - -/* This macro checks for a newline immediately preceding the given position */ - -#define WAS_NEWLINE(p) \ - ((NLBLOCK->nltype != NLTYPE_FIXED)? \ - ((p) > NLBLOCK->PSSTART && \ - PRIV(was_newline)((p), NLBLOCK->nltype, NLBLOCK->PSSTART, \ - &(NLBLOCK->nllen), utf)) \ - : \ - ((p) >= NLBLOCK->PSSTART + NLBLOCK->nllen && \ - UCHAR21TEST(p - NLBLOCK->nllen) == NLBLOCK->nl[0] && \ - (NLBLOCK->nllen == 1 || UCHAR21TEST(p - NLBLOCK->nllen + 1) == NLBLOCK->nl[1]) \ - ) \ - ) - -/* Private flags containing information about the compiled pattern. The first -three must not be changed, because whichever is set is actually the number of -bytes in a code unit in that mode. */ - -#define PCRE2_MODE8 0x00000001 /* compiled in 8 bit mode */ -#define PCRE2_MODE16 0x00000002 /* compiled in 16 bit mode */ -#define PCRE2_MODE32 0x00000004 /* compiled in 32 bit mode */ -#define PCRE2_FIRSTSET 0x00000010 /* first_code unit is set */ -#define PCRE2_FIRSTCASELESS 0x00000020 /* caseless first code unit */ -#define PCRE2_FIRSTMAPSET 0x00000040 /* bitmap of first code units is set */ -#define PCRE2_LASTSET 0x00000080 /* last code unit is set */ -#define PCRE2_LASTCASELESS 0x00000100 /* caseless last code unit */ -#define PCRE2_STARTLINE 0x00000200 /* start after \n for multiline */ -#define PCRE2_JCHANGED 0x00000400 /* j option used in pattern */ -#define PCRE2_HASCRORLF 0x00000800 /* explicit \r or \n in pattern */ -#define PCRE2_HASTHEN 0x00001000 /* pattern contains (*THEN) */ -#define PCRE2_MATCH_EMPTY 0x00002000 /* pattern can match empty string */ -#define PCRE2_BSR_SET 0x00004000 /* BSR was set in the pattern */ -#define PCRE2_NL_SET 0x00008000 /* newline was set in the pattern */ -#define PCRE2_NOTEMPTY_SET 0x00010000 /* (*NOTEMPTY) used ) keep */ -#define PCRE2_NE_ATST_SET 0x00020000 /* (*NOTEMPTY_ATSTART) used) together */ -#define PCRE2_DEREF_TABLES 0x00040000 /* release character tables */ -#define PCRE2_NOJIT 0x00080000 /* (*NOJIT) used */ -#define PCRE2_HASBKPORX 0x00100000 /* contains \P, \p, or \X */ -#define PCRE2_DUPCAPUSED 0x00200000 /* contains (?| */ -#define PCRE2_HASBKC 0x00400000 /* contains \C */ -#define PCRE2_HASACCEPT 0x00800000 /* contains (*ACCEPT) */ - -#define PCRE2_MODE_MASK (PCRE2_MODE8 | PCRE2_MODE16 | PCRE2_MODE32) - -/* Values for the matchedby field in a match data block. */ - -enum { PCRE2_MATCHEDBY_INTERPRETER, /* pcre2_match() */ - PCRE2_MATCHEDBY_DFA_INTERPRETER, /* pcre2_dfa_match() */ - PCRE2_MATCHEDBY_JIT }; /* pcre2_jit_match() */ - -/* Values for the flags field in a match data block. */ - -#define PCRE2_MD_COPIED_SUBJECT 0x01u - -/* Magic number to provide a small check against being handed junk. */ - -#define MAGIC_NUMBER 0x50435245UL /* 'PCRE' */ - -/* The maximum remaining length of subject we are prepared to search for a -req_unit match from an anchored pattern. In 8-bit mode, memchr() is used and is -much faster than the search loop that has to be used in 16-bit and 32-bit -modes. */ - -#if PCRE2_CODE_UNIT_WIDTH == 8 -#define REQ_CU_MAX 5000 -#else -#define REQ_CU_MAX 2000 -#endif - -/* Offsets for the bitmap tables in the cbits set of tables. Each table -contains a set of bits for a class map. Some classes are built by combining -these tables. */ - -#define cbit_space 0 /* [:space:] or \s */ -#define cbit_xdigit 32 /* [:xdigit:] */ -#define cbit_digit 64 /* [:digit:] or \d */ -#define cbit_upper 96 /* [:upper:] */ -#define cbit_lower 128 /* [:lower:] */ -#define cbit_word 160 /* [:word:] or \w */ -#define cbit_graph 192 /* [:graph:] */ -#define cbit_print 224 /* [:print:] */ -#define cbit_punct 256 /* [:punct:] */ -#define cbit_cntrl 288 /* [:cntrl:] */ -#define cbit_length 320 /* Length of the cbits table */ - -/* Bit definitions for entries in the ctypes table. Do not change these values -without checking pcre2_jit_compile.c, which has an assertion to ensure that -ctype_word has the value 16. */ - -#define ctype_space 0x01 -#define ctype_letter 0x02 -#define ctype_lcletter 0x04 -#define ctype_digit 0x08 -#define ctype_word 0x10 /* alphanumeric or '_' */ - -/* Offsets of the various tables from the base tables pointer, and -total length of the tables. */ - -#define lcc_offset 0 /* Lower case */ -#define fcc_offset 256 /* Flip case */ -#define cbits_offset 512 /* Character classes */ -#define ctypes_offset (cbits_offset + cbit_length) /* Character types */ -#define TABLES_LENGTH (ctypes_offset + 256) - - -/* -------------------- Character and string names ------------------------ */ - -/* If PCRE2 is to support UTF-8 on EBCDIC platforms, we cannot use normal -character constants like '*' because the compiler would emit their EBCDIC code, -which is different from their ASCII/UTF-8 code. Instead we define macros for -the characters so that they always use the ASCII/UTF-8 code when UTF-8 support -is enabled. When UTF-8 support is not enabled, the definitions use character -literals. Both character and string versions of each character are needed, and -there are some longer strings as well. - -This means that, on EBCDIC platforms, the PCRE2 library can handle either -EBCDIC, or UTF-8, but not both. To support both in the same compiled library -would need different lookups depending on whether PCRE2_UTF was set or not. -This would make it impossible to use characters in switch/case statements, -which would reduce performance. For a theoretical use (which nobody has asked -for) in a minority area (EBCDIC platforms), this is not sensible. Any -application that did need both could compile two versions of the library, using -macros to give the functions distinct names. */ - -#ifndef SUPPORT_UNICODE - -/* UTF-8 support is not enabled; use the platform-dependent character literals -so that PCRE2 works in both ASCII and EBCDIC environments, but only in non-UTF -mode. Newline characters are problematic in EBCDIC. Though it has CR and LF -characters, a common practice has been to use its NL (0x15) character as the -line terminator in C-like processing environments. However, sometimes the LF -(0x25) character is used instead, according to this Unicode document: - -http://unicode.org/standard/reports/tr13/tr13-5.html - -PCRE2 defaults EBCDIC NL to 0x15, but has a build-time option to select 0x25 -instead. Whichever is *not* chosen is defined as NEL. - -In both ASCII and EBCDIC environments, CHAR_NL and CHAR_LF are synonyms for the -same code point. */ - -#ifdef EBCDIC - -#ifndef EBCDIC_NL25 -#define CHAR_NL '\x15' -#define CHAR_NEL '\x25' -#define STR_NL "\x15" -#define STR_NEL "\x25" -#else -#define CHAR_NL '\x25' -#define CHAR_NEL '\x15' -#define STR_NL "\x25" -#define STR_NEL "\x15" -#endif - -#define CHAR_LF CHAR_NL -#define STR_LF STR_NL - -#define CHAR_ESC '\047' -#define CHAR_DEL '\007' -#define CHAR_NBSP ((unsigned char)'\x41') -#define STR_ESC "\047" -#define STR_DEL "\007" - -#else /* Not EBCDIC */ - -/* In ASCII/Unicode, linefeed is '\n' and we equate this to NL for -compatibility. NEL is the Unicode newline character; make sure it is -a positive value. */ - -#define CHAR_LF '\n' -#define CHAR_NL CHAR_LF -#define CHAR_NEL ((unsigned char)'\x85') -#define CHAR_ESC '\033' -#define CHAR_DEL '\177' -#define CHAR_NBSP ((unsigned char)'\xa0') - -#define STR_LF "\n" -#define STR_NL STR_LF -#define STR_NEL "\x85" -#define STR_ESC "\033" -#define STR_DEL "\177" - -#endif /* EBCDIC */ - -/* The remaining definitions work in both environments. */ - -#define CHAR_NUL '\0' -#define CHAR_HT '\t' -#define CHAR_VT '\v' -#define CHAR_FF '\f' -#define CHAR_CR '\r' -#define CHAR_BS '\b' -#define CHAR_BEL '\a' - -#define CHAR_SPACE ' ' -#define CHAR_EXCLAMATION_MARK '!' -#define CHAR_QUOTATION_MARK '"' -#define CHAR_NUMBER_SIGN '#' -#define CHAR_DOLLAR_SIGN '$' -#define CHAR_PERCENT_SIGN '%' -#define CHAR_AMPERSAND '&' -#define CHAR_APOSTROPHE '\'' -#define CHAR_LEFT_PARENTHESIS '(' -#define CHAR_RIGHT_PARENTHESIS ')' -#define CHAR_ASTERISK '*' -#define CHAR_PLUS '+' -#define CHAR_COMMA ',' -#define CHAR_MINUS '-' -#define CHAR_DOT '.' -#define CHAR_SLASH '/' -#define CHAR_0 '0' -#define CHAR_1 '1' -#define CHAR_2 '2' -#define CHAR_3 '3' -#define CHAR_4 '4' -#define CHAR_5 '5' -#define CHAR_6 '6' -#define CHAR_7 '7' -#define CHAR_8 '8' -#define CHAR_9 '9' -#define CHAR_COLON ':' -#define CHAR_SEMICOLON ';' -#define CHAR_LESS_THAN_SIGN '<' -#define CHAR_EQUALS_SIGN '=' -#define CHAR_GREATER_THAN_SIGN '>' -#define CHAR_QUESTION_MARK '?' -#define CHAR_COMMERCIAL_AT '@' -#define CHAR_A 'A' -#define CHAR_B 'B' -#define CHAR_C 'C' -#define CHAR_D 'D' -#define CHAR_E 'E' -#define CHAR_F 'F' -#define CHAR_G 'G' -#define CHAR_H 'H' -#define CHAR_I 'I' -#define CHAR_J 'J' -#define CHAR_K 'K' -#define CHAR_L 'L' -#define CHAR_M 'M' -#define CHAR_N 'N' -#define CHAR_O 'O' -#define CHAR_P 'P' -#define CHAR_Q 'Q' -#define CHAR_R 'R' -#define CHAR_S 'S' -#define CHAR_T 'T' -#define CHAR_U 'U' -#define CHAR_V 'V' -#define CHAR_W 'W' -#define CHAR_X 'X' -#define CHAR_Y 'Y' -#define CHAR_Z 'Z' -#define CHAR_LEFT_SQUARE_BRACKET '[' -#define CHAR_BACKSLASH '\\' -#define CHAR_RIGHT_SQUARE_BRACKET ']' -#define CHAR_CIRCUMFLEX_ACCENT '^' -#define CHAR_UNDERSCORE '_' -#define CHAR_GRAVE_ACCENT '`' -#define CHAR_a 'a' -#define CHAR_b 'b' -#define CHAR_c 'c' -#define CHAR_d 'd' -#define CHAR_e 'e' -#define CHAR_f 'f' -#define CHAR_g 'g' -#define CHAR_h 'h' -#define CHAR_i 'i' -#define CHAR_j 'j' -#define CHAR_k 'k' -#define CHAR_l 'l' -#define CHAR_m 'm' -#define CHAR_n 'n' -#define CHAR_o 'o' -#define CHAR_p 'p' -#define CHAR_q 'q' -#define CHAR_r 'r' -#define CHAR_s 's' -#define CHAR_t 't' -#define CHAR_u 'u' -#define CHAR_v 'v' -#define CHAR_w 'w' -#define CHAR_x 'x' -#define CHAR_y 'y' -#define CHAR_z 'z' -#define CHAR_LEFT_CURLY_BRACKET '{' -#define CHAR_VERTICAL_LINE '|' -#define CHAR_RIGHT_CURLY_BRACKET '}' -#define CHAR_TILDE '~' - -#define STR_HT "\t" -#define STR_VT "\v" -#define STR_FF "\f" -#define STR_CR "\r" -#define STR_BS "\b" -#define STR_BEL "\a" - -#define STR_SPACE " " -#define STR_EXCLAMATION_MARK "!" -#define STR_QUOTATION_MARK "\"" -#define STR_NUMBER_SIGN "#" -#define STR_DOLLAR_SIGN "$" -#define STR_PERCENT_SIGN "%" -#define STR_AMPERSAND "&" -#define STR_APOSTROPHE "'" -#define STR_LEFT_PARENTHESIS "(" -#define STR_RIGHT_PARENTHESIS ")" -#define STR_ASTERISK "*" -#define STR_PLUS "+" -#define STR_COMMA "," -#define STR_MINUS "-" -#define STR_DOT "." -#define STR_SLASH "/" -#define STR_0 "0" -#define STR_1 "1" -#define STR_2 "2" -#define STR_3 "3" -#define STR_4 "4" -#define STR_5 "5" -#define STR_6 "6" -#define STR_7 "7" -#define STR_8 "8" -#define STR_9 "9" -#define STR_COLON ":" -#define STR_SEMICOLON ";" -#define STR_LESS_THAN_SIGN "<" -#define STR_EQUALS_SIGN "=" -#define STR_GREATER_THAN_SIGN ">" -#define STR_QUESTION_MARK "?" -#define STR_COMMERCIAL_AT "@" -#define STR_A "A" -#define STR_B "B" -#define STR_C "C" -#define STR_D "D" -#define STR_E "E" -#define STR_F "F" -#define STR_G "G" -#define STR_H "H" -#define STR_I "I" -#define STR_J "J" -#define STR_K "K" -#define STR_L "L" -#define STR_M "M" -#define STR_N "N" -#define STR_O "O" -#define STR_P "P" -#define STR_Q "Q" -#define STR_R "R" -#define STR_S "S" -#define STR_T "T" -#define STR_U "U" -#define STR_V "V" -#define STR_W "W" -#define STR_X "X" -#define STR_Y "Y" -#define STR_Z "Z" -#define STR_LEFT_SQUARE_BRACKET "[" -#define STR_BACKSLASH "\\" -#define STR_RIGHT_SQUARE_BRACKET "]" -#define STR_CIRCUMFLEX_ACCENT "^" -#define STR_UNDERSCORE "_" -#define STR_GRAVE_ACCENT "`" -#define STR_a "a" -#define STR_b "b" -#define STR_c "c" -#define STR_d "d" -#define STR_e "e" -#define STR_f "f" -#define STR_g "g" -#define STR_h "h" -#define STR_i "i" -#define STR_j "j" -#define STR_k "k" -#define STR_l "l" -#define STR_m "m" -#define STR_n "n" -#define STR_o "o" -#define STR_p "p" -#define STR_q "q" -#define STR_r "r" -#define STR_s "s" -#define STR_t "t" -#define STR_u "u" -#define STR_v "v" -#define STR_w "w" -#define STR_x "x" -#define STR_y "y" -#define STR_z "z" -#define STR_LEFT_CURLY_BRACKET "{" -#define STR_VERTICAL_LINE "|" -#define STR_RIGHT_CURLY_BRACKET "}" -#define STR_TILDE "~" - -#define STRING_ACCEPT0 "ACCEPT\0" -#define STRING_COMMIT0 "COMMIT\0" -#define STRING_F0 "F\0" -#define STRING_FAIL0 "FAIL\0" -#define STRING_MARK0 "MARK\0" -#define STRING_PRUNE0 "PRUNE\0" -#define STRING_SKIP0 "SKIP\0" -#define STRING_THEN "THEN" - -#define STRING_atomic0 "atomic\0" -#define STRING_pla0 "pla\0" -#define STRING_plb0 "plb\0" -#define STRING_napla0 "napla\0" -#define STRING_naplb0 "naplb\0" -#define STRING_nla0 "nla\0" -#define STRING_nlb0 "nlb\0" -#define STRING_sr0 "sr\0" -#define STRING_asr0 "asr\0" -#define STRING_positive_lookahead0 "positive_lookahead\0" -#define STRING_positive_lookbehind0 "positive_lookbehind\0" -#define STRING_non_atomic_positive_lookahead0 "non_atomic_positive_lookahead\0" -#define STRING_non_atomic_positive_lookbehind0 "non_atomic_positive_lookbehind\0" -#define STRING_negative_lookahead0 "negative_lookahead\0" -#define STRING_negative_lookbehind0 "negative_lookbehind\0" -#define STRING_script_run0 "script_run\0" -#define STRING_atomic_script_run "atomic_script_run" - -#define STRING_alpha0 "alpha\0" -#define STRING_lower0 "lower\0" -#define STRING_upper0 "upper\0" -#define STRING_alnum0 "alnum\0" -#define STRING_ascii0 "ascii\0" -#define STRING_blank0 "blank\0" -#define STRING_cntrl0 "cntrl\0" -#define STRING_digit0 "digit\0" -#define STRING_graph0 "graph\0" -#define STRING_print0 "print\0" -#define STRING_punct0 "punct\0" -#define STRING_space0 "space\0" -#define STRING_word0 "word\0" -#define STRING_xdigit "xdigit" - -#define STRING_DEFINE "DEFINE" -#define STRING_VERSION "VERSION" -#define STRING_WEIRD_STARTWORD "[:<:]]" -#define STRING_WEIRD_ENDWORD "[:>:]]" - -#define STRING_CR_RIGHTPAR "CR)" -#define STRING_LF_RIGHTPAR "LF)" -#define STRING_CRLF_RIGHTPAR "CRLF)" -#define STRING_ANY_RIGHTPAR "ANY)" -#define STRING_ANYCRLF_RIGHTPAR "ANYCRLF)" -#define STRING_NUL_RIGHTPAR "NUL)" -#define STRING_BSR_ANYCRLF_RIGHTPAR "BSR_ANYCRLF)" -#define STRING_BSR_UNICODE_RIGHTPAR "BSR_UNICODE)" -#define STRING_UTF8_RIGHTPAR "UTF8)" -#define STRING_UTF16_RIGHTPAR "UTF16)" -#define STRING_UTF32_RIGHTPAR "UTF32)" -#define STRING_UTF_RIGHTPAR "UTF)" -#define STRING_UCP_RIGHTPAR "UCP)" -#define STRING_NO_AUTO_POSSESS_RIGHTPAR "NO_AUTO_POSSESS)" -#define STRING_NO_DOTSTAR_ANCHOR_RIGHTPAR "NO_DOTSTAR_ANCHOR)" -#define STRING_NO_JIT_RIGHTPAR "NO_JIT)" -#define STRING_NO_START_OPT_RIGHTPAR "NO_START_OPT)" -#define STRING_NOTEMPTY_RIGHTPAR "NOTEMPTY)" -#define STRING_NOTEMPTY_ATSTART_RIGHTPAR "NOTEMPTY_ATSTART)" -#define STRING_LIMIT_HEAP_EQ "LIMIT_HEAP=" -#define STRING_LIMIT_MATCH_EQ "LIMIT_MATCH=" -#define STRING_LIMIT_DEPTH_EQ "LIMIT_DEPTH=" -#define STRING_LIMIT_RECURSION_EQ "LIMIT_RECURSION=" -#define STRING_MARK "MARK" - -#define STRING_bc "bc" -#define STRING_bidiclass "bidiclass" -#define STRING_sc "sc" -#define STRING_script "script" -#define STRING_scriptextensions "scriptextensions" -#define STRING_scx "scx" - -#else /* SUPPORT_UNICODE */ - -/* UTF-8 support is enabled; always use UTF-8 (=ASCII) character codes. This -works in both modes non-EBCDIC platforms, and on EBCDIC platforms in UTF-8 mode -only. */ - -#define CHAR_HT '\011' -#define CHAR_VT '\013' -#define CHAR_FF '\014' -#define CHAR_CR '\015' -#define CHAR_LF '\012' -#define CHAR_NL CHAR_LF -#define CHAR_NEL ((unsigned char)'\x85') -#define CHAR_BS '\010' -#define CHAR_BEL '\007' -#define CHAR_ESC '\033' -#define CHAR_DEL '\177' - -#define CHAR_NUL '\0' -#define CHAR_SPACE '\040' -#define CHAR_EXCLAMATION_MARK '\041' -#define CHAR_QUOTATION_MARK '\042' -#define CHAR_NUMBER_SIGN '\043' -#define CHAR_DOLLAR_SIGN '\044' -#define CHAR_PERCENT_SIGN '\045' -#define CHAR_AMPERSAND '\046' -#define CHAR_APOSTROPHE '\047' -#define CHAR_LEFT_PARENTHESIS '\050' -#define CHAR_RIGHT_PARENTHESIS '\051' -#define CHAR_ASTERISK '\052' -#define CHAR_PLUS '\053' -#define CHAR_COMMA '\054' -#define CHAR_MINUS '\055' -#define CHAR_DOT '\056' -#define CHAR_SLASH '\057' -#define CHAR_0 '\060' -#define CHAR_1 '\061' -#define CHAR_2 '\062' -#define CHAR_3 '\063' -#define CHAR_4 '\064' -#define CHAR_5 '\065' -#define CHAR_6 '\066' -#define CHAR_7 '\067' -#define CHAR_8 '\070' -#define CHAR_9 '\071' -#define CHAR_COLON '\072' -#define CHAR_SEMICOLON '\073' -#define CHAR_LESS_THAN_SIGN '\074' -#define CHAR_EQUALS_SIGN '\075' -#define CHAR_GREATER_THAN_SIGN '\076' -#define CHAR_QUESTION_MARK '\077' -#define CHAR_COMMERCIAL_AT '\100' -#define CHAR_A '\101' -#define CHAR_B '\102' -#define CHAR_C '\103' -#define CHAR_D '\104' -#define CHAR_E '\105' -#define CHAR_F '\106' -#define CHAR_G '\107' -#define CHAR_H '\110' -#define CHAR_I '\111' -#define CHAR_J '\112' -#define CHAR_K '\113' -#define CHAR_L '\114' -#define CHAR_M '\115' -#define CHAR_N '\116' -#define CHAR_O '\117' -#define CHAR_P '\120' -#define CHAR_Q '\121' -#define CHAR_R '\122' -#define CHAR_S '\123' -#define CHAR_T '\124' -#define CHAR_U '\125' -#define CHAR_V '\126' -#define CHAR_W '\127' -#define CHAR_X '\130' -#define CHAR_Y '\131' -#define CHAR_Z '\132' -#define CHAR_LEFT_SQUARE_BRACKET '\133' -#define CHAR_BACKSLASH '\134' -#define CHAR_RIGHT_SQUARE_BRACKET '\135' -#define CHAR_CIRCUMFLEX_ACCENT '\136' -#define CHAR_UNDERSCORE '\137' -#define CHAR_GRAVE_ACCENT '\140' -#define CHAR_a '\141' -#define CHAR_b '\142' -#define CHAR_c '\143' -#define CHAR_d '\144' -#define CHAR_e '\145' -#define CHAR_f '\146' -#define CHAR_g '\147' -#define CHAR_h '\150' -#define CHAR_i '\151' -#define CHAR_j '\152' -#define CHAR_k '\153' -#define CHAR_l '\154' -#define CHAR_m '\155' -#define CHAR_n '\156' -#define CHAR_o '\157' -#define CHAR_p '\160' -#define CHAR_q '\161' -#define CHAR_r '\162' -#define CHAR_s '\163' -#define CHAR_t '\164' -#define CHAR_u '\165' -#define CHAR_v '\166' -#define CHAR_w '\167' -#define CHAR_x '\170' -#define CHAR_y '\171' -#define CHAR_z '\172' -#define CHAR_LEFT_CURLY_BRACKET '\173' -#define CHAR_VERTICAL_LINE '\174' -#define CHAR_RIGHT_CURLY_BRACKET '\175' -#define CHAR_TILDE '\176' -#define CHAR_NBSP ((unsigned char)'\xa0') - -#define STR_HT "\011" -#define STR_VT "\013" -#define STR_FF "\014" -#define STR_CR "\015" -#define STR_NL "\012" -#define STR_BS "\010" -#define STR_BEL "\007" -#define STR_ESC "\033" -#define STR_DEL "\177" - -#define STR_SPACE "\040" -#define STR_EXCLAMATION_MARK "\041" -#define STR_QUOTATION_MARK "\042" -#define STR_NUMBER_SIGN "\043" -#define STR_DOLLAR_SIGN "\044" -#define STR_PERCENT_SIGN "\045" -#define STR_AMPERSAND "\046" -#define STR_APOSTROPHE "\047" -#define STR_LEFT_PARENTHESIS "\050" -#define STR_RIGHT_PARENTHESIS "\051" -#define STR_ASTERISK "\052" -#define STR_PLUS "\053" -#define STR_COMMA "\054" -#define STR_MINUS "\055" -#define STR_DOT "\056" -#define STR_SLASH "\057" -#define STR_0 "\060" -#define STR_1 "\061" -#define STR_2 "\062" -#define STR_3 "\063" -#define STR_4 "\064" -#define STR_5 "\065" -#define STR_6 "\066" -#define STR_7 "\067" -#define STR_8 "\070" -#define STR_9 "\071" -#define STR_COLON "\072" -#define STR_SEMICOLON "\073" -#define STR_LESS_THAN_SIGN "\074" -#define STR_EQUALS_SIGN "\075" -#define STR_GREATER_THAN_SIGN "\076" -#define STR_QUESTION_MARK "\077" -#define STR_COMMERCIAL_AT "\100" -#define STR_A "\101" -#define STR_B "\102" -#define STR_C "\103" -#define STR_D "\104" -#define STR_E "\105" -#define STR_F "\106" -#define STR_G "\107" -#define STR_H "\110" -#define STR_I "\111" -#define STR_J "\112" -#define STR_K "\113" -#define STR_L "\114" -#define STR_M "\115" -#define STR_N "\116" -#define STR_O "\117" -#define STR_P "\120" -#define STR_Q "\121" -#define STR_R "\122" -#define STR_S "\123" -#define STR_T "\124" -#define STR_U "\125" -#define STR_V "\126" -#define STR_W "\127" -#define STR_X "\130" -#define STR_Y "\131" -#define STR_Z "\132" -#define STR_LEFT_SQUARE_BRACKET "\133" -#define STR_BACKSLASH "\134" -#define STR_RIGHT_SQUARE_BRACKET "\135" -#define STR_CIRCUMFLEX_ACCENT "\136" -#define STR_UNDERSCORE "\137" -#define STR_GRAVE_ACCENT "\140" -#define STR_a "\141" -#define STR_b "\142" -#define STR_c "\143" -#define STR_d "\144" -#define STR_e "\145" -#define STR_f "\146" -#define STR_g "\147" -#define STR_h "\150" -#define STR_i "\151" -#define STR_j "\152" -#define STR_k "\153" -#define STR_l "\154" -#define STR_m "\155" -#define STR_n "\156" -#define STR_o "\157" -#define STR_p "\160" -#define STR_q "\161" -#define STR_r "\162" -#define STR_s "\163" -#define STR_t "\164" -#define STR_u "\165" -#define STR_v "\166" -#define STR_w "\167" -#define STR_x "\170" -#define STR_y "\171" -#define STR_z "\172" -#define STR_LEFT_CURLY_BRACKET "\173" -#define STR_VERTICAL_LINE "\174" -#define STR_RIGHT_CURLY_BRACKET "\175" -#define STR_TILDE "\176" - -#define STRING_ACCEPT0 STR_A STR_C STR_C STR_E STR_P STR_T "\0" -#define STRING_COMMIT0 STR_C STR_O STR_M STR_M STR_I STR_T "\0" -#define STRING_F0 STR_F "\0" -#define STRING_FAIL0 STR_F STR_A STR_I STR_L "\0" -#define STRING_MARK0 STR_M STR_A STR_R STR_K "\0" -#define STRING_PRUNE0 STR_P STR_R STR_U STR_N STR_E "\0" -#define STRING_SKIP0 STR_S STR_K STR_I STR_P "\0" -#define STRING_THEN STR_T STR_H STR_E STR_N - -#define STRING_atomic0 STR_a STR_t STR_o STR_m STR_i STR_c "\0" -#define STRING_pla0 STR_p STR_l STR_a "\0" -#define STRING_plb0 STR_p STR_l STR_b "\0" -#define STRING_napla0 STR_n STR_a STR_p STR_l STR_a "\0" -#define STRING_naplb0 STR_n STR_a STR_p STR_l STR_b "\0" -#define STRING_nla0 STR_n STR_l STR_a "\0" -#define STRING_nlb0 STR_n STR_l STR_b "\0" -#define STRING_sr0 STR_s STR_r "\0" -#define STRING_asr0 STR_a STR_s STR_r "\0" -#define STRING_positive_lookahead0 STR_p STR_o STR_s STR_i STR_t STR_i STR_v STR_e STR_UNDERSCORE STR_l STR_o STR_o STR_k STR_a STR_h STR_e STR_a STR_d "\0" -#define STRING_positive_lookbehind0 STR_p STR_o STR_s STR_i STR_t STR_i STR_v STR_e STR_UNDERSCORE STR_l STR_o STR_o STR_k STR_b STR_e STR_h STR_i STR_n STR_d "\0" -#define STRING_non_atomic_positive_lookahead0 STR_n STR_o STR_n STR_UNDERSCORE STR_a STR_t STR_o STR_m STR_i STR_c STR_UNDERSCORE STR_p STR_o STR_s STR_i STR_t STR_i STR_v STR_e STR_UNDERSCORE STR_l STR_o STR_o STR_k STR_a STR_h STR_e STR_a STR_d "\0" -#define STRING_non_atomic_positive_lookbehind0 STR_n STR_o STR_n STR_UNDERSCORE STR_a STR_t STR_o STR_m STR_i STR_c STR_UNDERSCORE STR_p STR_o STR_s STR_i STR_t STR_i STR_v STR_e STR_UNDERSCORE STR_l STR_o STR_o STR_k STR_b STR_e STR_h STR_i STR_n STR_d "\0" -#define STRING_negative_lookahead0 STR_n STR_e STR_g STR_a STR_t STR_i STR_v STR_e STR_UNDERSCORE STR_l STR_o STR_o STR_k STR_a STR_h STR_e STR_a STR_d "\0" -#define STRING_negative_lookbehind0 STR_n STR_e STR_g STR_a STR_t STR_i STR_v STR_e STR_UNDERSCORE STR_l STR_o STR_o STR_k STR_b STR_e STR_h STR_i STR_n STR_d "\0" -#define STRING_script_run0 STR_s STR_c STR_r STR_i STR_p STR_t STR_UNDERSCORE STR_r STR_u STR_n "\0" -#define STRING_atomic_script_run STR_a STR_t STR_o STR_m STR_i STR_c STR_UNDERSCORE STR_s STR_c STR_r STR_i STR_p STR_t STR_UNDERSCORE STR_r STR_u STR_n - -#define STRING_alpha0 STR_a STR_l STR_p STR_h STR_a "\0" -#define STRING_lower0 STR_l STR_o STR_w STR_e STR_r "\0" -#define STRING_upper0 STR_u STR_p STR_p STR_e STR_r "\0" -#define STRING_alnum0 STR_a STR_l STR_n STR_u STR_m "\0" -#define STRING_ascii0 STR_a STR_s STR_c STR_i STR_i "\0" -#define STRING_blank0 STR_b STR_l STR_a STR_n STR_k "\0" -#define STRING_cntrl0 STR_c STR_n STR_t STR_r STR_l "\0" -#define STRING_digit0 STR_d STR_i STR_g STR_i STR_t "\0" -#define STRING_graph0 STR_g STR_r STR_a STR_p STR_h "\0" -#define STRING_print0 STR_p STR_r STR_i STR_n STR_t "\0" -#define STRING_punct0 STR_p STR_u STR_n STR_c STR_t "\0" -#define STRING_space0 STR_s STR_p STR_a STR_c STR_e "\0" -#define STRING_word0 STR_w STR_o STR_r STR_d "\0" -#define STRING_xdigit STR_x STR_d STR_i STR_g STR_i STR_t - -#define STRING_DEFINE STR_D STR_E STR_F STR_I STR_N STR_E -#define STRING_VERSION STR_V STR_E STR_R STR_S STR_I STR_O STR_N -#define STRING_WEIRD_STARTWORD STR_LEFT_SQUARE_BRACKET STR_COLON STR_LESS_THAN_SIGN STR_COLON STR_RIGHT_SQUARE_BRACKET STR_RIGHT_SQUARE_BRACKET -#define STRING_WEIRD_ENDWORD STR_LEFT_SQUARE_BRACKET STR_COLON STR_GREATER_THAN_SIGN STR_COLON STR_RIGHT_SQUARE_BRACKET STR_RIGHT_SQUARE_BRACKET - -#define STRING_CR_RIGHTPAR STR_C STR_R STR_RIGHT_PARENTHESIS -#define STRING_LF_RIGHTPAR STR_L STR_F STR_RIGHT_PARENTHESIS -#define STRING_CRLF_RIGHTPAR STR_C STR_R STR_L STR_F STR_RIGHT_PARENTHESIS -#define STRING_ANY_RIGHTPAR STR_A STR_N STR_Y STR_RIGHT_PARENTHESIS -#define STRING_ANYCRLF_RIGHTPAR STR_A STR_N STR_Y STR_C STR_R STR_L STR_F STR_RIGHT_PARENTHESIS -#define STRING_NUL_RIGHTPAR STR_N STR_U STR_L STR_RIGHT_PARENTHESIS -#define STRING_BSR_ANYCRLF_RIGHTPAR STR_B STR_S STR_R STR_UNDERSCORE STR_A STR_N STR_Y STR_C STR_R STR_L STR_F STR_RIGHT_PARENTHESIS -#define STRING_BSR_UNICODE_RIGHTPAR STR_B STR_S STR_R STR_UNDERSCORE STR_U STR_N STR_I STR_C STR_O STR_D STR_E STR_RIGHT_PARENTHESIS -#define STRING_UTF8_RIGHTPAR STR_U STR_T STR_F STR_8 STR_RIGHT_PARENTHESIS -#define STRING_UTF16_RIGHTPAR STR_U STR_T STR_F STR_1 STR_6 STR_RIGHT_PARENTHESIS -#define STRING_UTF32_RIGHTPAR STR_U STR_T STR_F STR_3 STR_2 STR_RIGHT_PARENTHESIS -#define STRING_UTF_RIGHTPAR STR_U STR_T STR_F STR_RIGHT_PARENTHESIS -#define STRING_UCP_RIGHTPAR STR_U STR_C STR_P STR_RIGHT_PARENTHESIS -#define STRING_NO_AUTO_POSSESS_RIGHTPAR STR_N STR_O STR_UNDERSCORE STR_A STR_U STR_T STR_O STR_UNDERSCORE STR_P STR_O STR_S STR_S STR_E STR_S STR_S STR_RIGHT_PARENTHESIS -#define STRING_NO_DOTSTAR_ANCHOR_RIGHTPAR STR_N STR_O STR_UNDERSCORE STR_D STR_O STR_T STR_S STR_T STR_A STR_R STR_UNDERSCORE STR_A STR_N STR_C STR_H STR_O STR_R STR_RIGHT_PARENTHESIS -#define STRING_NO_JIT_RIGHTPAR STR_N STR_O STR_UNDERSCORE STR_J STR_I STR_T STR_RIGHT_PARENTHESIS -#define STRING_NO_START_OPT_RIGHTPAR STR_N STR_O STR_UNDERSCORE STR_S STR_T STR_A STR_R STR_T STR_UNDERSCORE STR_O STR_P STR_T STR_RIGHT_PARENTHESIS -#define STRING_NOTEMPTY_RIGHTPAR STR_N STR_O STR_T STR_E STR_M STR_P STR_T STR_Y STR_RIGHT_PARENTHESIS -#define STRING_NOTEMPTY_ATSTART_RIGHTPAR STR_N STR_O STR_T STR_E STR_M STR_P STR_T STR_Y STR_UNDERSCORE STR_A STR_T STR_S STR_T STR_A STR_R STR_T STR_RIGHT_PARENTHESIS -#define STRING_LIMIT_HEAP_EQ STR_L STR_I STR_M STR_I STR_T STR_UNDERSCORE STR_H STR_E STR_A STR_P STR_EQUALS_SIGN -#define STRING_LIMIT_MATCH_EQ STR_L STR_I STR_M STR_I STR_T STR_UNDERSCORE STR_M STR_A STR_T STR_C STR_H STR_EQUALS_SIGN -#define STRING_LIMIT_DEPTH_EQ STR_L STR_I STR_M STR_I STR_T STR_UNDERSCORE STR_D STR_E STR_P STR_T STR_H STR_EQUALS_SIGN -#define STRING_LIMIT_RECURSION_EQ STR_L STR_I STR_M STR_I STR_T STR_UNDERSCORE STR_R STR_E STR_C STR_U STR_R STR_S STR_I STR_O STR_N STR_EQUALS_SIGN -#define STRING_MARK STR_M STR_A STR_R STR_K - -#define STRING_bc STR_b STR_c -#define STRING_bidiclass STR_b STR_i STR_d STR_i STR_c STR_l STR_a STR_s STR_s -#define STRING_sc STR_s STR_c -#define STRING_script STR_s STR_c STR_r STR_i STR_p STR_t -#define STRING_scriptextensions STR_s STR_c STR_r STR_i STR_p STR_t STR_e STR_x STR_t STR_e STR_n STR_s STR_i STR_o STR_n STR_s -#define STRING_scx STR_s STR_c STR_x - - -#endif /* SUPPORT_UNICODE */ - -/* -------------------- End of character and string names -------------------*/ - -/* -------------------- Definitions for compiled patterns -------------------*/ - -/* Codes for different types of Unicode property. If these definitions are -changed, the autopossessifying table in pcre2_auto_possess.c must be updated to -match. */ - -#define PT_ANY 0 /* Any property - matches all chars */ -#define PT_LAMP 1 /* L& - the union of Lu, Ll, Lt */ -#define PT_GC 2 /* Specified general characteristic (e.g. L) */ -#define PT_PC 3 /* Specified particular characteristic (e.g. Lu) */ -#define PT_SC 4 /* Script only (e.g. Han) */ -#define PT_SCX 5 /* Script extensions (includes SC) */ -#define PT_ALNUM 6 /* Alphanumeric - the union of L and N */ -#define PT_SPACE 7 /* Perl space - general category Z plus 9,10,12,13 */ -#define PT_PXSPACE 8 /* POSIX space - Z plus 9,10,11,12,13 */ -#define PT_WORD 9 /* Word - L plus N plus underscore */ -#define PT_CLIST 10 /* Pseudo-property: match character list */ -#define PT_UCNC 11 /* Universal Character nameable character */ -#define PT_BIDICL 12 /* Specified bidi class */ -#define PT_BOOL 13 /* Boolean property */ -#define PT_TABSIZE 14 /* Size of square table for autopossessify tests */ - -/* The following special properties are used only in XCLASS items, when POSIX -classes are specified and PCRE2_UCP is set - in other words, for Unicode -handling of these classes. They are not available via the \p or \P escapes like -those in the above list, and so they do not take part in the autopossessifying -table. */ - -#define PT_PXGRAPH 14 /* [:graph:] - characters that mark the paper */ -#define PT_PXPRINT 15 /* [:print:] - [:graph:] plus non-control spaces */ -#define PT_PXPUNCT 16 /* [:punct:] - punctuation characters */ - -/* This value is used when parsing \p and \P escapes to indicate that neither -\p{script:...} nor \p{scx:...} has been encountered. */ - -#define PT_NOTSCRIPT 255 - -/* Flag bits and data types for the extended class (OP_XCLASS) for classes that -contain characters with values greater than 255. */ - -#define XCL_NOT 0x01 /* Flag: this is a negative class */ -#define XCL_MAP 0x02 /* Flag: a 32-byte map is present */ -#define XCL_HASPROP 0x04 /* Flag: property checks are present. */ - -#define XCL_END 0 /* Marks end of individual items */ -#define XCL_SINGLE 1 /* Single item (one multibyte char) follows */ -#define XCL_RANGE 2 /* A range (two multibyte chars) follows */ -#define XCL_PROP 3 /* Unicode property (2-byte property code follows) */ -#define XCL_NOTPROP 4 /* Unicode inverted property (ditto) */ - -/* These are escaped items that aren't just an encoding of a particular data -value such as \n. They must have non-zero values, as check_escape() returns 0 -for a data character. In the escapes[] table in pcre2_compile.c their values -are negated in order to distinguish them from data values. - -They must appear here in the same order as in the opcode definitions below, up -to ESC_z. There's a dummy for OP_ALLANY because it corresponds to "." in DOTALL -mode rather than an escape sequence. It is also used for [^] in JavaScript -compatibility mode, and for \C in non-utf mode. In non-DOTALL mode, "." behaves -like \N. - -Negative numbers are used to encode a backreference (\1, \2, \3, etc.) in -check_escape(). There are tests in the code for an escape greater than ESC_b -and less than ESC_Z to detect the types that may be repeated. These are the -types that consume characters. If any new escapes are put in between that don't -consume a character, that code will have to change. */ - -enum { ESC_A = 1, ESC_G, ESC_K, ESC_B, ESC_b, ESC_D, ESC_d, ESC_S, ESC_s, - ESC_W, ESC_w, ESC_N, ESC_dum, ESC_C, ESC_P, ESC_p, ESC_R, ESC_H, - ESC_h, ESC_V, ESC_v, ESC_X, ESC_Z, ESC_z, - ESC_E, ESC_Q, ESC_g, ESC_k }; - - -/********************** Opcode definitions ******************/ - -/****** NOTE NOTE NOTE ****** - -Starting from 1 (i.e. after OP_END), the values up to OP_EOD must correspond in -order to the list of escapes immediately above. Furthermore, values up to -OP_DOLLM must not be changed without adjusting the table called autoposstab in -pcre2_auto_possess.c. - -Whenever this list is updated, the two macro definitions that follow must be -updated to match. The possessification table called "opcode_possessify" in -pcre2_compile.c must also be updated, and also the tables called "coptable" -and "poptable" in pcre2_dfa_match.c. - -****** NOTE NOTE NOTE ******/ - - -/* The values between FIRST_AUTOTAB_OP and LAST_AUTOTAB_RIGHT_OP, inclusive, -are used in a table for deciding whether a repeated character type can be -auto-possessified. */ - -#define FIRST_AUTOTAB_OP OP_NOT_DIGIT -#define LAST_AUTOTAB_LEFT_OP OP_EXTUNI -#define LAST_AUTOTAB_RIGHT_OP OP_DOLLM - -enum { - OP_END, /* 0 End of pattern */ - - /* Values corresponding to backslashed metacharacters */ - - OP_SOD, /* 1 Start of data: \A */ - OP_SOM, /* 2 Start of match (subject + offset): \G */ - OP_SET_SOM, /* 3 Set start of match (\K) */ - OP_NOT_WORD_BOUNDARY, /* 4 \B */ - OP_WORD_BOUNDARY, /* 5 \b */ - OP_NOT_DIGIT, /* 6 \D */ - OP_DIGIT, /* 7 \d */ - OP_NOT_WHITESPACE, /* 8 \S */ - OP_WHITESPACE, /* 9 \s */ - OP_NOT_WORDCHAR, /* 10 \W */ - OP_WORDCHAR, /* 11 \w */ - - OP_ANY, /* 12 Match any character except newline (\N) */ - OP_ALLANY, /* 13 Match any character */ - OP_ANYBYTE, /* 14 Match any byte (\C); different to OP_ANY for UTF-8 */ - OP_NOTPROP, /* 15 \P (not Unicode property) */ - OP_PROP, /* 16 \p (Unicode property) */ - OP_ANYNL, /* 17 \R (any newline sequence) */ - OP_NOT_HSPACE, /* 18 \H (not horizontal whitespace) */ - OP_HSPACE, /* 19 \h (horizontal whitespace) */ - OP_NOT_VSPACE, /* 20 \V (not vertical whitespace) */ - OP_VSPACE, /* 21 \v (vertical whitespace) */ - OP_EXTUNI, /* 22 \X (extended Unicode sequence */ - OP_EODN, /* 23 End of data or \n at end of data (\Z) */ - OP_EOD, /* 24 End of data (\z) */ - - /* Line end assertions */ - - OP_DOLL, /* 25 End of line - not multiline */ - OP_DOLLM, /* 26 End of line - multiline */ - OP_CIRC, /* 27 Start of line - not multiline */ - OP_CIRCM, /* 28 Start of line - multiline */ - - /* Single characters; caseful must precede the caseless ones, and these - must remain in this order, and adjacent. */ - - OP_CHAR, /* 29 Match one character, casefully */ - OP_CHARI, /* 30 Match one character, caselessly */ - OP_NOT, /* 31 Match one character, not the given one, casefully */ - OP_NOTI, /* 32 Match one character, not the given one, caselessly */ - - /* The following sets of 13 opcodes must always be kept in step because - the offset from the first one is used to generate the others. */ - - /* Repeated characters; caseful must precede the caseless ones */ - - OP_STAR, /* 33 The maximizing and minimizing versions of */ - OP_MINSTAR, /* 34 these six opcodes must come in pairs, with */ - OP_PLUS, /* 35 the minimizing one second. */ - OP_MINPLUS, /* 36 */ - OP_QUERY, /* 37 */ - OP_MINQUERY, /* 38 */ - - OP_UPTO, /* 39 From 0 to n matches of one character, caseful*/ - OP_MINUPTO, /* 40 */ - OP_EXACT, /* 41 Exactly n matches */ - - OP_POSSTAR, /* 42 Possessified star, caseful */ - OP_POSPLUS, /* 43 Possessified plus, caseful */ - OP_POSQUERY, /* 44 Posesssified query, caseful */ - OP_POSUPTO, /* 45 Possessified upto, caseful */ - - /* Repeated characters; caseless must follow the caseful ones */ - - OP_STARI, /* 46 */ - OP_MINSTARI, /* 47 */ - OP_PLUSI, /* 48 */ - OP_MINPLUSI, /* 49 */ - OP_QUERYI, /* 50 */ - OP_MINQUERYI, /* 51 */ - - OP_UPTOI, /* 52 From 0 to n matches of one character, caseless */ - OP_MINUPTOI, /* 53 */ - OP_EXACTI, /* 54 */ - - OP_POSSTARI, /* 55 Possessified star, caseless */ - OP_POSPLUSI, /* 56 Possessified plus, caseless */ - OP_POSQUERYI, /* 57 Posesssified query, caseless */ - OP_POSUPTOI, /* 58 Possessified upto, caseless */ - - /* The negated ones must follow the non-negated ones, and match them */ - /* Negated repeated character, caseful; must precede the caseless ones */ - - OP_NOTSTAR, /* 59 The maximizing and minimizing versions of */ - OP_NOTMINSTAR, /* 60 these six opcodes must come in pairs, with */ - OP_NOTPLUS, /* 61 the minimizing one second. They must be in */ - OP_NOTMINPLUS, /* 62 exactly the same order as those above. */ - OP_NOTQUERY, /* 63 */ - OP_NOTMINQUERY, /* 64 */ - - OP_NOTUPTO, /* 65 From 0 to n matches, caseful */ - OP_NOTMINUPTO, /* 66 */ - OP_NOTEXACT, /* 67 Exactly n matches */ - - OP_NOTPOSSTAR, /* 68 Possessified versions, caseful */ - OP_NOTPOSPLUS, /* 69 */ - OP_NOTPOSQUERY, /* 70 */ - OP_NOTPOSUPTO, /* 71 */ - - /* Negated repeated character, caseless; must follow the caseful ones */ - - OP_NOTSTARI, /* 72 */ - OP_NOTMINSTARI, /* 73 */ - OP_NOTPLUSI, /* 74 */ - OP_NOTMINPLUSI, /* 75 */ - OP_NOTQUERYI, /* 76 */ - OP_NOTMINQUERYI, /* 77 */ - - OP_NOTUPTOI, /* 78 From 0 to n matches, caseless */ - OP_NOTMINUPTOI, /* 79 */ - OP_NOTEXACTI, /* 80 Exactly n matches */ - - OP_NOTPOSSTARI, /* 81 Possessified versions, caseless */ - OP_NOTPOSPLUSI, /* 82 */ - OP_NOTPOSQUERYI, /* 83 */ - OP_NOTPOSUPTOI, /* 84 */ - - /* Character types */ - - OP_TYPESTAR, /* 85 The maximizing and minimizing versions of */ - OP_TYPEMINSTAR, /* 86 these six opcodes must come in pairs, with */ - OP_TYPEPLUS, /* 87 the minimizing one second. These codes must */ - OP_TYPEMINPLUS, /* 88 be in exactly the same order as those above. */ - OP_TYPEQUERY, /* 89 */ - OP_TYPEMINQUERY, /* 90 */ - - OP_TYPEUPTO, /* 91 From 0 to n matches */ - OP_TYPEMINUPTO, /* 92 */ - OP_TYPEEXACT, /* 93 Exactly n matches */ - - OP_TYPEPOSSTAR, /* 94 Possessified versions */ - OP_TYPEPOSPLUS, /* 95 */ - OP_TYPEPOSQUERY, /* 96 */ - OP_TYPEPOSUPTO, /* 97 */ - - /* These are used for character classes and back references; only the - first six are the same as the sets above. */ - - OP_CRSTAR, /* 98 The maximizing and minimizing versions of */ - OP_CRMINSTAR, /* 99 all these opcodes must come in pairs, with */ - OP_CRPLUS, /* 100 the minimizing one second. These codes must */ - OP_CRMINPLUS, /* 101 be in exactly the same order as those above. */ - OP_CRQUERY, /* 102 */ - OP_CRMINQUERY, /* 103 */ - - OP_CRRANGE, /* 104 These are different to the three sets above. */ - OP_CRMINRANGE, /* 105 */ - - OP_CRPOSSTAR, /* 106 Possessified versions */ - OP_CRPOSPLUS, /* 107 */ - OP_CRPOSQUERY, /* 108 */ - OP_CRPOSRANGE, /* 109 */ - - /* End of quantifier opcodes */ - - OP_CLASS, /* 110 Match a character class, chars < 256 only */ - OP_NCLASS, /* 111 Same, but the bitmap was created from a negative - class - the difference is relevant only when a - character > 255 is encountered. */ - OP_XCLASS, /* 112 Extended class for handling > 255 chars within the - class. This does both positive and negative. */ - OP_REF, /* 113 Match a back reference, casefully */ - OP_REFI, /* 114 Match a back reference, caselessly */ - OP_DNREF, /* 115 Match a duplicate name backref, casefully */ - OP_DNREFI, /* 116 Match a duplicate name backref, caselessly */ - OP_RECURSE, /* 117 Match a numbered subpattern (possibly recursive) */ - OP_CALLOUT, /* 118 Call out to external function if provided */ - OP_CALLOUT_STR, /* 119 Call out with string argument */ - - OP_ALT, /* 120 Start of alternation */ - OP_KET, /* 121 End of group that doesn't have an unbounded repeat */ - OP_KETRMAX, /* 122 These two must remain together and in this */ - OP_KETRMIN, /* 123 order. They are for groups the repeat for ever. */ - OP_KETRPOS, /* 124 Possessive unlimited repeat. */ - - /* The assertions must come before BRA, CBRA, ONCE, and COND. */ - - OP_REVERSE, /* 125 Move pointer back - used in lookbehind assertions */ - OP_ASSERT, /* 126 Positive lookahead */ - OP_ASSERT_NOT, /* 127 Negative lookahead */ - OP_ASSERTBACK, /* 128 Positive lookbehind */ - OP_ASSERTBACK_NOT, /* 129 Negative lookbehind */ - OP_ASSERT_NA, /* 130 Positive non-atomic lookahead */ - OP_ASSERTBACK_NA, /* 131 Positive non-atomic lookbehind */ - - /* ONCE, SCRIPT_RUN, BRA, BRAPOS, CBRA, CBRAPOS, and COND must come - immediately after the assertions, with ONCE first, as there's a test for >= - ONCE for a subpattern that isn't an assertion. The POS versions must - immediately follow the non-POS versions in each case. */ - - OP_ONCE, /* 132 Atomic group, contains captures */ - OP_SCRIPT_RUN, /* 133 Non-capture, but check characters' scripts */ - OP_BRA, /* 134 Start of non-capturing bracket */ - OP_BRAPOS, /* 135 Ditto, with unlimited, possessive repeat */ - OP_CBRA, /* 136 Start of capturing bracket */ - OP_CBRAPOS, /* 137 Ditto, with unlimited, possessive repeat */ - OP_COND, /* 138 Conditional group */ - - /* These five must follow the previous five, in the same order. There's a - check for >= SBRA to distinguish the two sets. */ - - OP_SBRA, /* 139 Start of non-capturing bracket, check empty */ - OP_SBRAPOS, /* 149 Ditto, with unlimited, possessive repeat */ - OP_SCBRA, /* 141 Start of capturing bracket, check empty */ - OP_SCBRAPOS, /* 142 Ditto, with unlimited, possessive repeat */ - OP_SCOND, /* 143 Conditional group, check empty */ - - /* The next two pairs must (respectively) be kept together. */ - - OP_CREF, /* 144 Used to hold a capture number as condition */ - OP_DNCREF, /* 145 Used to point to duplicate names as a condition */ - OP_RREF, /* 146 Used to hold a recursion number as condition */ - OP_DNRREF, /* 147 Used to point to duplicate names as a condition */ - OP_FALSE, /* 148 Always false (used by DEFINE and VERSION) */ - OP_TRUE, /* 149 Always true (used by VERSION) */ - - OP_BRAZERO, /* 150 These two must remain together and in this */ - OP_BRAMINZERO, /* 151 order. */ - OP_BRAPOSZERO, /* 152 */ - - /* These are backtracking control verbs */ - - OP_MARK, /* 153 always has an argument */ - OP_PRUNE, /* 154 */ - OP_PRUNE_ARG, /* 155 same, but with argument */ - OP_SKIP, /* 156 */ - OP_SKIP_ARG, /* 157 same, but with argument */ - OP_THEN, /* 158 */ - OP_THEN_ARG, /* 159 same, but with argument */ - OP_COMMIT, /* 160 */ - OP_COMMIT_ARG, /* 161 same, but with argument */ - - /* These are forced failure and success verbs. FAIL and ACCEPT do accept an - argument, but these cases can be compiled as, for example, (*MARK:X)(*FAIL) - without the need for a special opcode. */ - - OP_FAIL, /* 162 */ - OP_ACCEPT, /* 163 */ - OP_ASSERT_ACCEPT, /* 164 Used inside assertions */ - OP_CLOSE, /* 165 Used before OP_ACCEPT to close open captures */ - - /* This is used to skip a subpattern with a {0} quantifier */ - - OP_SKIPZERO, /* 166 */ - - /* This is used to identify a DEFINE group during compilation so that it can - be checked for having only one branch. It is changed to OP_FALSE before - compilation finishes. */ - - OP_DEFINE, /* 167 */ - - /* This is not an opcode, but is used to check that tables indexed by opcode - are the correct length, in order to catch updating errors - there have been - some in the past. */ - - OP_TABLE_LENGTH - -}; - -/* *** NOTE NOTE NOTE *** Whenever the list above is updated, the two macro -definitions that follow must also be updated to match. There are also tables -called "opcode_possessify" in pcre2_compile.c and "coptable" and "poptable" in -pcre2_dfa_match.c that must be updated. */ - - -/* This macro defines textual names for all the opcodes. These are used only -for debugging, and some of them are only partial names. The macro is referenced -only in pcre2_printint.c, which fills out the full names in many cases (and in -some cases doesn't actually use these names at all). */ - -#define OP_NAME_LIST \ - "End", "\\A", "\\G", "\\K", "\\B", "\\b", "\\D", "\\d", \ - "\\S", "\\s", "\\W", "\\w", "Any", "AllAny", "Anybyte", \ - "notprop", "prop", "\\R", "\\H", "\\h", "\\V", "\\v", \ - "extuni", "\\Z", "\\z", \ - "$", "$", "^", "^", "char", "chari", "not", "noti", \ - "*", "*?", "+", "+?", "?", "??", \ - "{", "{", "{", \ - "*+","++", "?+", "{", \ - "*", "*?", "+", "+?", "?", "??", \ - "{", "{", "{", \ - "*+","++", "?+", "{", \ - "*", "*?", "+", "+?", "?", "??", \ - "{", "{", "{", \ - "*+","++", "?+", "{", \ - "*", "*?", "+", "+?", "?", "??", \ - "{", "{", "{", \ - "*+","++", "?+", "{", \ - "*", "*?", "+", "+?", "?", "??", "{", "{", "{", \ - "*+","++", "?+", "{", \ - "*", "*?", "+", "+?", "?", "??", "{", "{", \ - "*+","++", "?+", "{", \ - "class", "nclass", "xclass", "Ref", "Refi", "DnRef", "DnRefi", \ - "Recurse", "Callout", "CalloutStr", \ - "Alt", "Ket", "KetRmax", "KetRmin", "KetRpos", \ - "Reverse", "Assert", "Assert not", \ - "Assert back", "Assert back not", \ - "Non-atomic assert", "Non-atomic assert back", \ - "Once", \ - "Script run", \ - "Bra", "BraPos", "CBra", "CBraPos", \ - "Cond", \ - "SBra", "SBraPos", "SCBra", "SCBraPos", \ - "SCond", \ - "Cond ref", "Cond dnref", "Cond rec", "Cond dnrec", \ - "Cond false", "Cond true", \ - "Brazero", "Braminzero", "Braposzero", \ - "*MARK", "*PRUNE", "*PRUNE", "*SKIP", "*SKIP", \ - "*THEN", "*THEN", "*COMMIT", "*COMMIT", "*FAIL", \ - "*ACCEPT", "*ASSERT_ACCEPT", \ - "Close", "Skip zero", "Define" - - -/* This macro defines the length of fixed length operations in the compiled -regex. The lengths are used when searching for specific things, and also in the -debugging printing of a compiled regex. We use a macro so that it can be -defined close to the definitions of the opcodes themselves. - -As things have been extended, some of these are no longer fixed lenths, but are -minima instead. For example, the length of a single-character repeat may vary -in UTF-8 mode. The code that uses this table must know about such things. */ - -#define OP_LENGTHS \ - 1, /* End */ \ - 1, 1, 1, 1, 1, /* \A, \G, \K, \B, \b */ \ - 1, 1, 1, 1, 1, 1, /* \D, \d, \S, \s, \W, \w */ \ - 1, 1, 1, /* Any, AllAny, Anybyte */ \ - 3, 3, /* \P, \p */ \ - 1, 1, 1, 1, 1, /* \R, \H, \h, \V, \v */ \ - 1, /* \X */ \ - 1, 1, 1, 1, 1, 1, /* \Z, \z, $, $M ^, ^M */ \ - 2, /* Char - the minimum length */ \ - 2, /* Chari - the minimum length */ \ - 2, /* not */ \ - 2, /* noti */ \ - /* Positive single-char repeats ** These are */ \ - 2, 2, 2, 2, 2, 2, /* *, *?, +, +?, ?, ?? ** minima in */ \ - 2+IMM2_SIZE, 2+IMM2_SIZE, /* upto, minupto ** mode */ \ - 2+IMM2_SIZE, /* exact */ \ - 2, 2, 2, 2+IMM2_SIZE, /* *+, ++, ?+, upto+ */ \ - 2, 2, 2, 2, 2, 2, /* *I, *?I, +I, +?I, ?I, ??I ** UTF-8 */ \ - 2+IMM2_SIZE, 2+IMM2_SIZE, /* upto I, minupto I */ \ - 2+IMM2_SIZE, /* exact I */ \ - 2, 2, 2, 2+IMM2_SIZE, /* *+I, ++I, ?+I, upto+I */ \ - /* Negative single-char repeats - only for chars < 256 */ \ - 2, 2, 2, 2, 2, 2, /* NOT *, *?, +, +?, ?, ?? */ \ - 2+IMM2_SIZE, 2+IMM2_SIZE, /* NOT upto, minupto */ \ - 2+IMM2_SIZE, /* NOT exact */ \ - 2, 2, 2, 2+IMM2_SIZE, /* Possessive NOT *, +, ?, upto */ \ - 2, 2, 2, 2, 2, 2, /* NOT *I, *?I, +I, +?I, ?I, ??I */ \ - 2+IMM2_SIZE, 2+IMM2_SIZE, /* NOT upto I, minupto I */ \ - 2+IMM2_SIZE, /* NOT exact I */ \ - 2, 2, 2, 2+IMM2_SIZE, /* Possessive NOT *I, +I, ?I, upto I */ \ - /* Positive type repeats */ \ - 2, 2, 2, 2, 2, 2, /* Type *, *?, +, +?, ?, ?? */ \ - 2+IMM2_SIZE, 2+IMM2_SIZE, /* Type upto, minupto */ \ - 2+IMM2_SIZE, /* Type exact */ \ - 2, 2, 2, 2+IMM2_SIZE, /* Possessive *+, ++, ?+, upto+ */ \ - /* Character class & ref repeats */ \ - 1, 1, 1, 1, 1, 1, /* *, *?, +, +?, ?, ?? */ \ - 1+2*IMM2_SIZE, 1+2*IMM2_SIZE, /* CRRANGE, CRMINRANGE */ \ - 1, 1, 1, 1+2*IMM2_SIZE, /* Possessive *+, ++, ?+, CRPOSRANGE */ \ - 1+(32/sizeof(PCRE2_UCHAR)), /* CLASS */ \ - 1+(32/sizeof(PCRE2_UCHAR)), /* NCLASS */ \ - 0, /* XCLASS - variable length */ \ - 1+IMM2_SIZE, /* REF */ \ - 1+IMM2_SIZE, /* REFI */ \ - 1+2*IMM2_SIZE, /* DNREF */ \ - 1+2*IMM2_SIZE, /* DNREFI */ \ - 1+LINK_SIZE, /* RECURSE */ \ - 1+2*LINK_SIZE+1, /* CALLOUT */ \ - 0, /* CALLOUT_STR - variable length */ \ - 1+LINK_SIZE, /* Alt */ \ - 1+LINK_SIZE, /* Ket */ \ - 1+LINK_SIZE, /* KetRmax */ \ - 1+LINK_SIZE, /* KetRmin */ \ - 1+LINK_SIZE, /* KetRpos */ \ - 1+LINK_SIZE, /* Reverse */ \ - 1+LINK_SIZE, /* Assert */ \ - 1+LINK_SIZE, /* Assert not */ \ - 1+LINK_SIZE, /* Assert behind */ \ - 1+LINK_SIZE, /* Assert behind not */ \ - 1+LINK_SIZE, /* NA Assert */ \ - 1+LINK_SIZE, /* NA Assert behind */ \ - 1+LINK_SIZE, /* ONCE */ \ - 1+LINK_SIZE, /* SCRIPT_RUN */ \ - 1+LINK_SIZE, /* BRA */ \ - 1+LINK_SIZE, /* BRAPOS */ \ - 1+LINK_SIZE+IMM2_SIZE, /* CBRA */ \ - 1+LINK_SIZE+IMM2_SIZE, /* CBRAPOS */ \ - 1+LINK_SIZE, /* COND */ \ - 1+LINK_SIZE, /* SBRA */ \ - 1+LINK_SIZE, /* SBRAPOS */ \ - 1+LINK_SIZE+IMM2_SIZE, /* SCBRA */ \ - 1+LINK_SIZE+IMM2_SIZE, /* SCBRAPOS */ \ - 1+LINK_SIZE, /* SCOND */ \ - 1+IMM2_SIZE, 1+2*IMM2_SIZE, /* CREF, DNCREF */ \ - 1+IMM2_SIZE, 1+2*IMM2_SIZE, /* RREF, DNRREF */ \ - 1, 1, /* FALSE, TRUE */ \ - 1, 1, 1, /* BRAZERO, BRAMINZERO, BRAPOSZERO */ \ - 3, 1, 3, /* MARK, PRUNE, PRUNE_ARG */ \ - 1, 3, /* SKIP, SKIP_ARG */ \ - 1, 3, /* THEN, THEN_ARG */ \ - 1, 3, /* COMMIT, COMMIT_ARG */ \ - 1, 1, 1, /* FAIL, ACCEPT, ASSERT_ACCEPT */ \ - 1+IMM2_SIZE, 1, /* CLOSE, SKIPZERO */ \ - 1 /* DEFINE */ - -/* A magic value for OP_RREF to indicate the "any recursion" condition. */ - -#define RREF_ANY 0xffff - - -/* ---------- Private structures that are mode-independent. ---------- */ - -/* Structure to hold data for custom memory management. */ - -typedef struct pcre2_memctl { - void * (*malloc)(size_t, void *); - void (*free)(void *, void *); - void *memory_data; -} pcre2_memctl; - -/* Structure for building a chain of open capturing subpatterns during -compiling, so that instructions to close them can be compiled when (*ACCEPT) is -encountered. */ - -typedef struct open_capitem { - struct open_capitem *next; /* Chain link */ - uint16_t number; /* Capture number */ - uint16_t assert_depth; /* Assertion depth when opened */ -} open_capitem; - -/* Layout of the UCP type table that translates property names into types and -codes. Each entry used to point directly to a name, but to reduce the number of -relocations in shared libraries, it now has an offset into a single string -instead. */ - -typedef struct { - uint16_t name_offset; - uint16_t type; - uint16_t value; -} ucp_type_table; - -/* Unicode character database (UCD) record format */ - -typedef struct { - uint8_t script; /* ucp_Arabic, etc. */ - uint8_t chartype; /* ucp_Cc, etc. (general categories) */ - uint8_t gbprop; /* ucp_gbControl, etc. (grapheme break property) */ - uint8_t caseset; /* offset to multichar other cases or zero */ - int32_t other_case; /* offset to other case, or zero if none */ - uint16_t scriptx_bidiclass; /* script extension (11 bit) and bidi class (5 bit) values */ - uint16_t bprops; /* binary properties offset */ -} ucd_record; - -/* UCD access macros */ - -#define UCD_BLOCK_SIZE 128 -#define REAL_GET_UCD(ch) (PRIV(ucd_records) + \ - PRIV(ucd_stage2)[PRIV(ucd_stage1)[(int)(ch) / UCD_BLOCK_SIZE] * \ - UCD_BLOCK_SIZE + (int)(ch) % UCD_BLOCK_SIZE]) - -#if PCRE2_CODE_UNIT_WIDTH == 32 -#define GET_UCD(ch) ((ch > MAX_UTF_CODE_POINT)? \ - PRIV(dummy_ucd_record) : REAL_GET_UCD(ch)) -#else -#define GET_UCD(ch) REAL_GET_UCD(ch) -#endif - -#define UCD_SCRIPTX_MASK 0x3ff -#define UCD_BIDICLASS_SHIFT 11 -#define UCD_BPROPS_MASK 0xfff - -#define UCD_SCRIPTX_PROP(prop) ((prop)->scriptx_bidiclass & UCD_SCRIPTX_MASK) -#define UCD_BIDICLASS_PROP(prop) ((prop)->scriptx_bidiclass >> UCD_BIDICLASS_SHIFT) -#define UCD_BPROPS_PROP(prop) ((prop)->bprops & UCD_BPROPS_MASK) - -#define UCD_CHARTYPE(ch) GET_UCD(ch)->chartype -#define UCD_SCRIPT(ch) GET_UCD(ch)->script -#define UCD_CATEGORY(ch) PRIV(ucp_gentype)[UCD_CHARTYPE(ch)] -#define UCD_GRAPHBREAK(ch) GET_UCD(ch)->gbprop -#define UCD_CASESET(ch) GET_UCD(ch)->caseset -#define UCD_OTHERCASE(ch) ((uint32_t)((int)ch + (int)(GET_UCD(ch)->other_case))) -#define UCD_SCRIPTX(ch) UCD_SCRIPTX_PROP(GET_UCD(ch)) -#define UCD_BPROPS(ch) UCD_BPROPS_PROP(GET_UCD(ch)) -#define UCD_BIDICLASS(ch) UCD_BIDICLASS_PROP(GET_UCD(ch)) - -/* The "scriptx" and bprops fields contain offsets into vectors of 32-bit words -that form a bitmap representing a list of scripts or boolean properties. These -macros test or set a bit in the map by number. */ - -#define MAPBIT(map,n) ((map)[(n)/32]&(1u<<((n)%32))) -#define MAPSET(map,n) ((map)[(n)/32]|=(1u<<((n)%32))) - -/* Header for serialized pcre2 codes. */ - -typedef struct pcre2_serialized_data { - uint32_t magic; - uint32_t version; - uint32_t config; - int32_t number_of_codes; -} pcre2_serialized_data; - - - -/* ----------------- Items that need PCRE2_CODE_UNIT_WIDTH ----------------- */ - -/* When this file is included by pcre2test, PCRE2_CODE_UNIT_WIDTH is defined as -0, so the following items are omitted. */ - -#if defined PCRE2_CODE_UNIT_WIDTH && PCRE2_CODE_UNIT_WIDTH != 0 - -/* EBCDIC is supported only for the 8-bit library. */ - -#if defined EBCDIC && PCRE2_CODE_UNIT_WIDTH != 8 -#error EBCDIC is not supported for the 16-bit or 32-bit libraries -#endif - -/* This is the largest non-UTF code point. */ - -#define MAX_NON_UTF_CHAR (0xffffffffU >> (32 - PCRE2_CODE_UNIT_WIDTH)) - -/* Internal shared data tables and variables. These are used by more than one -of the exported public functions. They have to be "external" in the C sense, -but are not part of the PCRE2 public API. Although the data for some of them is -identical in all libraries, they must have different names so that multiple -libraries can be simultaneously linked to a single application. However, UTF-8 -tables are needed only when compiling the 8-bit library. */ - -#if PCRE2_CODE_UNIT_WIDTH == 8 -extern const int PRIV(utf8_table1)[]; -extern const int PRIV(utf8_table1_size); -extern const int PRIV(utf8_table2)[]; -extern const int PRIV(utf8_table3)[]; -extern const uint8_t PRIV(utf8_table4)[]; -#endif - -#define _pcre2_OP_lengths PCRE2_SUFFIX(_pcre2_OP_lengths_) -#define _pcre2_callout_end_delims PCRE2_SUFFIX(_pcre2_callout_end_delims_) -#define _pcre2_callout_start_delims PCRE2_SUFFIX(_pcre2_callout_start_delims_) -#define _pcre2_default_compile_context PCRE2_SUFFIX(_pcre2_default_compile_context_) -#define _pcre2_default_convert_context PCRE2_SUFFIX(_pcre2_default_convert_context_) -#define _pcre2_default_match_context PCRE2_SUFFIX(_pcre2_default_match_context_) -#define _pcre2_default_tables PCRE2_SUFFIX(_pcre2_default_tables_) -#if PCRE2_CODE_UNIT_WIDTH == 32 -#define _pcre2_dummy_ucd_record PCRE2_SUFFIX(_pcre2_dummy_ucd_record_) -#endif -#define _pcre2_hspace_list PCRE2_SUFFIX(_pcre2_hspace_list_) -#define _pcre2_vspace_list PCRE2_SUFFIX(_pcre2_vspace_list_) -#define _pcre2_ucd_boolprop_sets PCRE2_SUFFIX(_pcre2_ucd_boolprop_sets_) -#define _pcre2_ucd_caseless_sets PCRE2_SUFFIX(_pcre2_ucd_caseless_sets_) -#define _pcre2_ucd_digit_sets PCRE2_SUFFIX(_pcre2_ucd_digit_sets_) -#define _pcre2_ucd_script_sets PCRE2_SUFFIX(_pcre2_ucd_script_sets_) -#define _pcre2_ucd_records PCRE2_SUFFIX(_pcre2_ucd_records_) -#define _pcre2_ucd_stage1 PCRE2_SUFFIX(_pcre2_ucd_stage1_) -#define _pcre2_ucd_stage2 PCRE2_SUFFIX(_pcre2_ucd_stage2_) -#define _pcre2_ucp_gbtable PCRE2_SUFFIX(_pcre2_ucp_gbtable_) -#define _pcre2_ucp_gentype PCRE2_SUFFIX(_pcre2_ucp_gentype_) -#define _pcre2_ucp_typerange PCRE2_SUFFIX(_pcre2_ucp_typerange_) -#define _pcre2_unicode_version PCRE2_SUFFIX(_pcre2_unicode_version_) -#define _pcre2_utt PCRE2_SUFFIX(_pcre2_utt_) -#define _pcre2_utt_names PCRE2_SUFFIX(_pcre2_utt_names_) -#define _pcre2_utt_size PCRE2_SUFFIX(_pcre2_utt_size_) - -extern const uint8_t PRIV(OP_lengths)[]; -extern const uint32_t PRIV(callout_end_delims)[]; -extern const uint32_t PRIV(callout_start_delims)[]; -extern const pcre2_compile_context PRIV(default_compile_context); -extern const pcre2_convert_context PRIV(default_convert_context); -extern const pcre2_match_context PRIV(default_match_context); -extern const uint8_t PRIV(default_tables)[]; -extern const uint32_t PRIV(hspace_list)[]; -extern const uint32_t PRIV(vspace_list)[]; -extern const uint32_t PRIV(ucd_boolprop_sets)[]; -extern const uint32_t PRIV(ucd_caseless_sets)[]; -extern const uint32_t PRIV(ucd_digit_sets)[]; -extern const uint32_t PRIV(ucd_script_sets)[]; -extern const ucd_record PRIV(ucd_records)[]; -#if PCRE2_CODE_UNIT_WIDTH == 32 -extern const ucd_record PRIV(dummy_ucd_record)[]; -#endif -extern const uint16_t PRIV(ucd_stage1)[]; -extern const uint16_t PRIV(ucd_stage2)[]; -extern const uint32_t PRIV(ucp_gbtable)[]; -extern const uint32_t PRIV(ucp_gentype)[]; -#ifdef SUPPORT_JIT -extern const int PRIV(ucp_typerange)[]; -#endif -extern const char *PRIV(unicode_version); -extern const ucp_type_table PRIV(utt)[]; -extern const char PRIV(utt_names)[]; -extern const size_t PRIV(utt_size); - -/* Mode-dependent macros and hidden and private structures are defined in a -separate file so that pcre2test can include them at all supported widths. When -compiling the library, PCRE2_CODE_UNIT_WIDTH will be defined, and we can -include them at the appropriate width, after setting up suffix macros for the -private structures. */ - -#define branch_chain PCRE2_SUFFIX(branch_chain_) -#define compile_block PCRE2_SUFFIX(compile_block_) -#define dfa_match_block PCRE2_SUFFIX(dfa_match_block_) -#define match_block PCRE2_SUFFIX(match_block_) -#define named_group PCRE2_SUFFIX(named_group_) - -#include "pcre2_intmodedep.h" - -/* Private "external" functions. These are internal functions that are called -from modules other than the one in which they are defined. They have to be -"external" in the C sense, but are not part of the PCRE2 public API. They are -not referenced from pcre2test, and must not be defined when no code unit width -is available. */ - -#define _pcre2_auto_possessify PCRE2_SUFFIX(_pcre2_auto_possessify_) -#define _pcre2_check_escape PCRE2_SUFFIX(_pcre2_check_escape_) -#define _pcre2_extuni PCRE2_SUFFIX(_pcre2_extuni_) -#define _pcre2_find_bracket PCRE2_SUFFIX(_pcre2_find_bracket_) -#define _pcre2_is_newline PCRE2_SUFFIX(_pcre2_is_newline_) -#define _pcre2_jit_free_rodata PCRE2_SUFFIX(_pcre2_jit_free_rodata_) -#define _pcre2_jit_free PCRE2_SUFFIX(_pcre2_jit_free_) -#define _pcre2_jit_get_size PCRE2_SUFFIX(_pcre2_jit_get_size_) -#define _pcre2_jit_get_target PCRE2_SUFFIX(_pcre2_jit_get_target_) -#define _pcre2_memctl_malloc PCRE2_SUFFIX(_pcre2_memctl_malloc_) -#define _pcre2_ord2utf PCRE2_SUFFIX(_pcre2_ord2utf_) -#define _pcre2_script_run PCRE2_SUFFIX(_pcre2_script_run_) -#define _pcre2_strcmp PCRE2_SUFFIX(_pcre2_strcmp_) -#define _pcre2_strcmp_c8 PCRE2_SUFFIX(_pcre2_strcmp_c8_) -#define _pcre2_strcpy_c8 PCRE2_SUFFIX(_pcre2_strcpy_c8_) -#define _pcre2_strlen PCRE2_SUFFIX(_pcre2_strlen_) -#define _pcre2_strncmp PCRE2_SUFFIX(_pcre2_strncmp_) -#define _pcre2_strncmp_c8 PCRE2_SUFFIX(_pcre2_strncmp_c8_) -#define _pcre2_study PCRE2_SUFFIX(_pcre2_study_) -#define _pcre2_valid_utf PCRE2_SUFFIX(_pcre2_valid_utf_) -#define _pcre2_was_newline PCRE2_SUFFIX(_pcre2_was_newline_) -#define _pcre2_xclass PCRE2_SUFFIX(_pcre2_xclass_) - -extern int _pcre2_auto_possessify(PCRE2_UCHAR *, - const compile_block *); -extern int _pcre2_check_escape(PCRE2_SPTR *, PCRE2_SPTR, uint32_t *, - int *, uint32_t, uint32_t, BOOL, compile_block *); -extern PCRE2_SPTR _pcre2_extuni(uint32_t, PCRE2_SPTR, PCRE2_SPTR, PCRE2_SPTR, - BOOL, int *); -extern PCRE2_SPTR _pcre2_find_bracket(PCRE2_SPTR, BOOL, int); -extern BOOL _pcre2_is_newline(PCRE2_SPTR, uint32_t, PCRE2_SPTR, - uint32_t *, BOOL); -extern void _pcre2_jit_free_rodata(void *, void *); -extern void _pcre2_jit_free(void *, pcre2_memctl *); -extern size_t _pcre2_jit_get_size(void *); -const char * _pcre2_jit_get_target(void); -extern void * _pcre2_memctl_malloc(size_t, pcre2_memctl *); -extern unsigned int _pcre2_ord2utf(uint32_t, PCRE2_UCHAR *); -extern BOOL _pcre2_script_run(PCRE2_SPTR, PCRE2_SPTR, BOOL); -extern int _pcre2_strcmp(PCRE2_SPTR, PCRE2_SPTR); -extern int _pcre2_strcmp_c8(PCRE2_SPTR, const char *); -extern PCRE2_SIZE _pcre2_strcpy_c8(PCRE2_UCHAR *, const char *); -extern PCRE2_SIZE _pcre2_strlen(PCRE2_SPTR); -extern int _pcre2_strncmp(PCRE2_SPTR, PCRE2_SPTR, size_t); -extern int _pcre2_strncmp_c8(PCRE2_SPTR, const char *, size_t); -extern int _pcre2_study(pcre2_real_code *); -extern int _pcre2_valid_utf(PCRE2_SPTR, PCRE2_SIZE, PCRE2_SIZE *); -extern BOOL _pcre2_was_newline(PCRE2_SPTR, uint32_t, PCRE2_SPTR, - uint32_t *, BOOL); -extern BOOL _pcre2_xclass(uint32_t, PCRE2_SPTR, BOOL); - -/* This function is needed only when memmove() is not available. */ - -#if !defined(VPCOMPAT) && !defined(HAVE_MEMMOVE) -#define _pcre2_memmove PCRE2_SUFFIX(_pcre2_memmove) -extern void * _pcre2_memmove(void *, const void *, size_t); -#endif - -#endif /* PCRE2_CODE_UNIT_WIDTH */ -#endif /* PCRE2_INTERNAL_H_IDEMPOTENT_GUARD */ - -/* End of pcre2_internal.h */ diff --git a/modules/regex/pcre2/src/pcre2_intmodedep.h b/modules/regex/pcre2/src/pcre2_intmodedep.h deleted file mode 100644 index 390e737..0000000 --- a/modules/regex/pcre2/src/pcre2_intmodedep.h +++ /dev/null @@ -1,934 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -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-2022 University of Cambridge - ------------------------------------------------------------------------------ -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 OWNER 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. ------------------------------------------------------------------------------ -*/ - - -/* This module contains mode-dependent macro and structure definitions. The -file is #included by pcre2_internal.h if PCRE2_CODE_UNIT_WIDTH is defined. -These mode-dependent items are kept in a separate file so that they can also be -#included multiple times for different code unit widths by pcre2test in order -to have access to the hidden structures at all supported widths. - -Some of the mode-dependent macros are required at different widths for -different parts of the pcre2test code (in particular, the included -pcre_printint.c file). We undefine them here so that they can be re-defined for -multiple inclusions. Not all of these are used in pcre2test, but it's easier -just to undefine them all. */ - -#undef ACROSSCHAR -#undef BACKCHAR -#undef BYTES2CU -#undef CHMAX_255 -#undef CU2BYTES -#undef FORWARDCHAR -#undef FORWARDCHARTEST -#undef GET -#undef GET2 -#undef GETCHAR -#undef GETCHARINC -#undef GETCHARINCTEST -#undef GETCHARLEN -#undef GETCHARLENTEST -#undef GETCHARTEST -#undef GET_EXTRALEN -#undef HAS_EXTRALEN -#undef IMM2_SIZE -#undef MAX_255 -#undef MAX_MARK -#undef MAX_PATTERN_SIZE -#undef MAX_UTF_SINGLE_CU -#undef NOT_FIRSTCU -#undef PUT -#undef PUT2 -#undef PUT2INC -#undef PUTCHAR -#undef PUTINC -#undef TABLE_GET - - - -/* -------------------------- MACROS ----------------------------- */ - -/* PCRE keeps offsets in its compiled code as at least 16-bit quantities -(always stored in big-endian order in 8-bit mode) by default. These are used, -for example, to link from the start of a subpattern to its alternatives and its -end. The use of 16 bits per offset limits the size of an 8-bit compiled regex -to around 64K, which is big enough for almost everybody. However, I received a -request for an even bigger limit. For this reason, and also to make the code -easier to maintain, the storing and loading of offsets from the compiled code -unit string is now handled by the macros that are defined here. - -The macros are controlled by the value of LINK_SIZE. This defaults to 2, but -values of 3 or 4 are also supported. */ - -/* ------------------- 8-bit support ------------------ */ - -#if PCRE2_CODE_UNIT_WIDTH == 8 - -#if LINK_SIZE == 2 -#define PUT(a,n,d) \ - (a[n] = (PCRE2_UCHAR)((d) >> 8)), \ - (a[(n)+1] = (PCRE2_UCHAR)((d) & 255)) -#define GET(a,n) \ - (unsigned int)(((a)[n] << 8) | (a)[(n)+1]) -#define MAX_PATTERN_SIZE (1 << 16) - -#elif LINK_SIZE == 3 -#define PUT(a,n,d) \ - (a[n] = (PCRE2_UCHAR)((d) >> 16)), \ - (a[(n)+1] = (PCRE2_UCHAR)((d) >> 8)), \ - (a[(n)+2] = (PCRE2_UCHAR)((d) & 255)) -#define GET(a,n) \ - (unsigned int)(((a)[n] << 16) | ((a)[(n)+1] << 8) | (a)[(n)+2]) -#define MAX_PATTERN_SIZE (1 << 24) - -#elif LINK_SIZE == 4 -#define PUT(a,n,d) \ - (a[n] = (PCRE2_UCHAR)((d) >> 24)), \ - (a[(n)+1] = (PCRE2_UCHAR)((d) >> 16)), \ - (a[(n)+2] = (PCRE2_UCHAR)((d) >> 8)), \ - (a[(n)+3] = (PCRE2_UCHAR)((d) & 255)) -#define GET(a,n) \ - (unsigned int)(((a)[n] << 24) | ((a)[(n)+1] << 16) | ((a)[(n)+2] << 8) | (a)[(n)+3]) -#define MAX_PATTERN_SIZE (1 << 30) /* Keep it positive */ - -#else -#error LINK_SIZE must be 2, 3, or 4 -#endif - - -/* ------------------- 16-bit support ------------------ */ - -#elif PCRE2_CODE_UNIT_WIDTH == 16 - -#if LINK_SIZE == 2 -#undef LINK_SIZE -#define LINK_SIZE 1 -#define PUT(a,n,d) \ - (a[n] = (PCRE2_UCHAR)(d)) -#define GET(a,n) \ - (a[n]) -#define MAX_PATTERN_SIZE (1 << 16) - -#elif LINK_SIZE == 3 || LINK_SIZE == 4 -#undef LINK_SIZE -#define LINK_SIZE 2 -#define PUT(a,n,d) \ - (a[n] = (PCRE2_UCHAR)((d) >> 16)), \ - (a[(n)+1] = (PCRE2_UCHAR)((d) & 65535)) -#define GET(a,n) \ - (unsigned int)(((a)[n] << 16) | (a)[(n)+1]) -#define MAX_PATTERN_SIZE (1 << 30) /* Keep it positive */ - -#else -#error LINK_SIZE must be 2, 3, or 4 -#endif - - -/* ------------------- 32-bit support ------------------ */ - -#elif PCRE2_CODE_UNIT_WIDTH == 32 -#undef LINK_SIZE -#define LINK_SIZE 1 -#define PUT(a,n,d) \ - (a[n] = (d)) -#define GET(a,n) \ - (a[n]) -#define MAX_PATTERN_SIZE (1 << 30) /* Keep it positive */ - -#else -#error Unsupported compiling mode -#endif - - -/* --------------- Other mode-specific macros ----------------- */ - -/* PCRE uses some other (at least) 16-bit quantities that do not change when -the size of offsets changes. There are used for repeat counts and for other -things such as capturing parenthesis numbers in back references. - -Define the number of code units required to hold a 16-bit count/offset, and -macros to load and store such a value. For reasons that I do not understand, -the expression in the 8-bit GET2 macro is treated by gcc as a signed -expression, even when a is declared as unsigned. It seems that any kind of -arithmetic results in a signed value. Hence the cast. */ - -#if PCRE2_CODE_UNIT_WIDTH == 8 -#define IMM2_SIZE 2 -#define GET2(a,n) (unsigned int)(((a)[n] << 8) | (a)[(n)+1]) -#define PUT2(a,n,d) a[n] = (d) >> 8, a[(n)+1] = (d) & 255 - -#else /* Code units are 16 or 32 bits */ -#define IMM2_SIZE 1 -#define GET2(a,n) a[n] -#define PUT2(a,n,d) a[n] = d -#endif - -/* Other macros that are different for 8-bit mode. The MAX_255 macro checks -whether its argument, which is assumed to be one code unit, is less than 256. -The CHMAX_255 macro does not assume one code unit. The maximum length of a MARK -name must fit in one code unit; currently it is set to 255 or 65535. The -TABLE_GET macro is used to access elements of tables containing exactly 256 -items. Its argument is a code unit. When code points can be greater than 255, a -check is needed before accessing these tables. */ - -#if PCRE2_CODE_UNIT_WIDTH == 8 -#define MAX_255(c) TRUE -#define MAX_MARK ((1u << 8) - 1) -#define TABLE_GET(c, table, default) ((table)[c]) -#ifdef SUPPORT_UNICODE -#define SUPPORT_WIDE_CHARS -#define CHMAX_255(c) ((c) <= 255u) -#else -#define CHMAX_255(c) TRUE -#endif /* SUPPORT_UNICODE */ - -#else /* Code units are 16 or 32 bits */ -#define CHMAX_255(c) ((c) <= 255u) -#define MAX_255(c) ((c) <= 255u) -#define MAX_MARK ((1u << 16) - 1) -#define SUPPORT_WIDE_CHARS -#define TABLE_GET(c, table, default) (MAX_255(c)? ((table)[c]):(default)) -#endif - - -/* ----------------- Character-handling macros ----------------- */ - -/* There is a proposed future special "UTF-21" mode, in which only the lowest -21 bits of a 32-bit character are interpreted as UTF, with the remaining 11 -high-order bits available to the application for other uses. In preparation for -the future implementation of this mode, there are macros that load a data item -and, if in this special mode, mask it to 21 bits. These macros all have names -starting with UCHAR21. In all other modes, including the normal 32-bit -library, the macros all have the same simple definitions. When the new mode is -implemented, it is expected that these definitions will be varied appropriately -using #ifdef when compiling the library that supports the special mode. */ - -#define UCHAR21(eptr) (*(eptr)) -#define UCHAR21TEST(eptr) (*(eptr)) -#define UCHAR21INC(eptr) (*(eptr)++) -#define UCHAR21INCTEST(eptr) (*(eptr)++) - -/* When UTF encoding is being used, a character is no longer just a single -byte in 8-bit mode or a single short in 16-bit mode. The macros for character -handling generate simple sequences when used in the basic mode, and more -complicated ones for UTF characters. GETCHARLENTEST and other macros are not -used when UTF is not supported. To make sure they can never even appear when -UTF support is omitted, we don't even define them. */ - -#ifndef SUPPORT_UNICODE - -/* #define MAX_UTF_SINGLE_CU */ -/* #define HAS_EXTRALEN(c) */ -/* #define GET_EXTRALEN(c) */ -/* #define NOT_FIRSTCU(c) */ -#define GETCHAR(c, eptr) c = *eptr; -#define GETCHARTEST(c, eptr) c = *eptr; -#define GETCHARINC(c, eptr) c = *eptr++; -#define GETCHARINCTEST(c, eptr) c = *eptr++; -#define GETCHARLEN(c, eptr, len) c = *eptr; -#define PUTCHAR(c, p) (*p = c, 1) -/* #define GETCHARLENTEST(c, eptr, len) */ -/* #define BACKCHAR(eptr) */ -/* #define FORWARDCHAR(eptr) */ -/* #define FORWARCCHARTEST(eptr,end) */ -/* #define ACROSSCHAR(condition, eptr, action) */ - -#else /* SUPPORT_UNICODE */ - -/* ------------------- 8-bit support ------------------ */ - -#if PCRE2_CODE_UNIT_WIDTH == 8 -#define MAYBE_UTF_MULTI /* UTF chars may use multiple code units */ - -/* The largest UTF code point that can be encoded as a single code unit. */ - -#define MAX_UTF_SINGLE_CU 127 - -/* Tests whether the code point needs extra characters to decode. */ - -#define HAS_EXTRALEN(c) HASUTF8EXTRALEN(c) - -/* Returns with the additional number of characters if IS_MULTICHAR(c) is TRUE. -Otherwise it has an undefined behaviour. */ - -#define GET_EXTRALEN(c) (PRIV(utf8_table4)[(c) & 0x3fu]) - -/* Returns TRUE, if the given value is not the first code unit of a UTF -sequence. */ - -#define NOT_FIRSTCU(c) (((c) & 0xc0u) == 0x80u) - -/* Get the next UTF-8 character, not advancing the pointer. This is called when -we know we are in UTF-8 mode. */ - -#define GETCHAR(c, eptr) \ - c = *eptr; \ - if (c >= 0xc0u) GETUTF8(c, eptr); - -/* Get the next UTF-8 character, testing for UTF-8 mode, and not advancing the -pointer. */ - -#define GETCHARTEST(c, eptr) \ - c = *eptr; \ - if (utf && c >= 0xc0u) GETUTF8(c, eptr); - -/* Get the next UTF-8 character, advancing the pointer. This is called when we -know we are in UTF-8 mode. */ - -#define GETCHARINC(c, eptr) \ - c = *eptr++; \ - if (c >= 0xc0u) GETUTF8INC(c, eptr); - -/* Get the next character, testing for UTF-8 mode, and advancing the pointer. -This is called when we don't know if we are in UTF-8 mode. */ - -#define GETCHARINCTEST(c, eptr) \ - c = *eptr++; \ - if (utf && c >= 0xc0u) GETUTF8INC(c, eptr); - -/* Get the next UTF-8 character, not advancing the pointer, incrementing length -if there are extra bytes. This is called when we know we are in UTF-8 mode. */ - -#define GETCHARLEN(c, eptr, len) \ - c = *eptr; \ - if (c >= 0xc0u) GETUTF8LEN(c, eptr, len); - -/* Get the next UTF-8 character, testing for UTF-8 mode, not advancing the -pointer, incrementing length if there are extra bytes. This is called when we -do not know if we are in UTF-8 mode. */ - -#define GETCHARLENTEST(c, eptr, len) \ - c = *eptr; \ - if (utf && c >= 0xc0u) GETUTF8LEN(c, eptr, len); - -/* If the pointer is not at the start of a character, move it back until -it is. This is called only in UTF-8 mode - we don't put a test within the macro -because almost all calls are already within a block of UTF-8 only code. */ - -#define BACKCHAR(eptr) while((*eptr & 0xc0u) == 0x80u) eptr-- - -/* Same as above, just in the other direction. */ -#define FORWARDCHAR(eptr) while((*eptr & 0xc0u) == 0x80u) eptr++ -#define FORWARDCHARTEST(eptr,end) while(eptr < end && (*eptr & 0xc0u) == 0x80u) eptr++ - -/* Same as above, but it allows a fully customizable form. */ -#define ACROSSCHAR(condition, eptr, action) \ - while((condition) && ((*eptr) & 0xc0u) == 0x80u) action - -/* Deposit a character into memory, returning the number of code units. */ - -#define PUTCHAR(c, p) ((utf && c > MAX_UTF_SINGLE_CU)? \ - PRIV(ord2utf)(c,p) : (*p = c, 1)) - - -/* ------------------- 16-bit support ------------------ */ - -#elif PCRE2_CODE_UNIT_WIDTH == 16 -#define MAYBE_UTF_MULTI /* UTF chars may use multiple code units */ - -/* The largest UTF code point that can be encoded as a single code unit. */ - -#define MAX_UTF_SINGLE_CU 65535 - -/* Tests whether the code point needs extra characters to decode. */ - -#define HAS_EXTRALEN(c) (((c) & 0xfc00u) == 0xd800u) - -/* Returns with the additional number of characters if IS_MULTICHAR(c) is TRUE. -Otherwise it has an undefined behaviour. */ - -#define GET_EXTRALEN(c) 1 - -/* Returns TRUE, if the given value is not the first code unit of a UTF -sequence. */ - -#define NOT_FIRSTCU(c) (((c) & 0xfc00u) == 0xdc00u) - -/* Base macro to pick up the low surrogate of a UTF-16 character, not -advancing the pointer. */ - -#define GETUTF16(c, eptr) \ - { c = (((c & 0x3ffu) << 10) | (eptr[1] & 0x3ffu)) + 0x10000u; } - -/* Get the next UTF-16 character, not advancing the pointer. This is called when -we know we are in UTF-16 mode. */ - -#define GETCHAR(c, eptr) \ - c = *eptr; \ - if ((c & 0xfc00u) == 0xd800u) GETUTF16(c, eptr); - -/* Get the next UTF-16 character, testing for UTF-16 mode, and not advancing the -pointer. */ - -#define GETCHARTEST(c, eptr) \ - c = *eptr; \ - if (utf && (c & 0xfc00u) == 0xd800u) GETUTF16(c, eptr); - -/* Base macro to pick up the low surrogate of a UTF-16 character, advancing -the pointer. */ - -#define GETUTF16INC(c, eptr) \ - { c = (((c & 0x3ffu) << 10) | (*eptr++ & 0x3ffu)) + 0x10000u; } - -/* Get the next UTF-16 character, advancing the pointer. This is called when we -know we are in UTF-16 mode. */ - -#define GETCHARINC(c, eptr) \ - c = *eptr++; \ - if ((c & 0xfc00u) == 0xd800u) GETUTF16INC(c, eptr); - -/* Get the next character, testing for UTF-16 mode, and advancing the pointer. -This is called when we don't know if we are in UTF-16 mode. */ - -#define GETCHARINCTEST(c, eptr) \ - c = *eptr++; \ - if (utf && (c & 0xfc00u) == 0xd800u) GETUTF16INC(c, eptr); - -/* Base macro to pick up the low surrogate of a UTF-16 character, not -advancing the pointer, incrementing the length. */ - -#define GETUTF16LEN(c, eptr, len) \ - { c = (((c & 0x3ffu) << 10) | (eptr[1] & 0x3ffu)) + 0x10000u; len++; } - -/* Get the next UTF-16 character, not advancing the pointer, incrementing -length if there is a low surrogate. This is called when we know we are in -UTF-16 mode. */ - -#define GETCHARLEN(c, eptr, len) \ - c = *eptr; \ - if ((c & 0xfc00u) == 0xd800u) GETUTF16LEN(c, eptr, len); - -/* Get the next UTF-816character, testing for UTF-16 mode, not advancing the -pointer, incrementing length if there is a low surrogate. This is called when -we do not know if we are in UTF-16 mode. */ - -#define GETCHARLENTEST(c, eptr, len) \ - c = *eptr; \ - if (utf && (c & 0xfc00u) == 0xd800u) GETUTF16LEN(c, eptr, len); - -/* If the pointer is not at the start of a character, move it back until -it is. This is called only in UTF-16 mode - we don't put a test within the -macro because almost all calls are already within a block of UTF-16 only -code. */ - -#define BACKCHAR(eptr) if ((*eptr & 0xfc00u) == 0xdc00u) eptr-- - -/* Same as above, just in the other direction. */ -#define FORWARDCHAR(eptr) if ((*eptr & 0xfc00u) == 0xdc00u) eptr++ -#define FORWARDCHARTEST(eptr,end) if (eptr < end && (*eptr & 0xfc00u) == 0xdc00u) eptr++ - -/* Same as above, but it allows a fully customizable form. */ -#define ACROSSCHAR(condition, eptr, action) \ - if ((condition) && ((*eptr) & 0xfc00u) == 0xdc00u) action - -/* Deposit a character into memory, returning the number of code units. */ - -#define PUTCHAR(c, p) ((utf && c > MAX_UTF_SINGLE_CU)? \ - PRIV(ord2utf)(c,p) : (*p = c, 1)) - - -/* ------------------- 32-bit support ------------------ */ - -#else - -/* These are trivial for the 32-bit library, since all UTF-32 characters fit -into one PCRE2_UCHAR unit. */ - -#define MAX_UTF_SINGLE_CU (0x10ffffu) -#define HAS_EXTRALEN(c) (0) -#define GET_EXTRALEN(c) (0) -#define NOT_FIRSTCU(c) (0) - -/* Get the next UTF-32 character, not advancing the pointer. This is called when -we know we are in UTF-32 mode. */ - -#define GETCHAR(c, eptr) \ - c = *(eptr); - -/* Get the next UTF-32 character, testing for UTF-32 mode, and not advancing the -pointer. */ - -#define GETCHARTEST(c, eptr) \ - c = *(eptr); - -/* Get the next UTF-32 character, advancing the pointer. This is called when we -know we are in UTF-32 mode. */ - -#define GETCHARINC(c, eptr) \ - c = *((eptr)++); - -/* Get the next character, testing for UTF-32 mode, and advancing the pointer. -This is called when we don't know if we are in UTF-32 mode. */ - -#define GETCHARINCTEST(c, eptr) \ - c = *((eptr)++); - -/* Get the next UTF-32 character, not advancing the pointer, not incrementing -length (since all UTF-32 is of length 1). This is called when we know we are in -UTF-32 mode. */ - -#define GETCHARLEN(c, eptr, len) \ - GETCHAR(c, eptr) - -/* Get the next UTF-32character, testing for UTF-32 mode, not advancing the -pointer, not incrementing the length (since all UTF-32 is of length 1). -This is called when we do not know if we are in UTF-32 mode. */ - -#define GETCHARLENTEST(c, eptr, len) \ - GETCHARTEST(c, eptr) - -/* If the pointer is not at the start of a character, move it back until -it is. This is called only in UTF-32 mode - we don't put a test within the -macro because almost all calls are already within a block of UTF-32 only -code. - -These are all no-ops since all UTF-32 characters fit into one PCRE2_UCHAR. */ - -#define BACKCHAR(eptr) do { } while (0) - -/* Same as above, just in the other direction. */ - -#define FORWARDCHAR(eptr) do { } while (0) -#define FORWARDCHARTEST(eptr,end) do { } while (0) - -/* Same as above, but it allows a fully customizable form. */ - -#define ACROSSCHAR(condition, eptr, action) do { } while (0) - -/* Deposit a character into memory, returning the number of code units. */ - -#define PUTCHAR(c, p) (*p = c, 1) - -#endif /* UTF-32 character handling */ -#endif /* SUPPORT_UNICODE */ - - -/* Mode-dependent macros that have the same definition in all modes. */ - -#define CU2BYTES(x) ((x)*((PCRE2_CODE_UNIT_WIDTH/8))) -#define BYTES2CU(x) ((x)/((PCRE2_CODE_UNIT_WIDTH/8))) -#define PUTINC(a,n,d) PUT(a,n,d), a += LINK_SIZE -#define PUT2INC(a,n,d) PUT2(a,n,d), a += IMM2_SIZE - - -/* ----------------------- HIDDEN STRUCTURES ----------------------------- */ - -/* NOTE: All these structures *must* start with a pcre2_memctl structure. The -code that uses them is simpler because it assumes this. */ - -/* The real general context structure. At present it holds only data for custom -memory control. */ - -typedef struct pcre2_real_general_context { - pcre2_memctl memctl; -} pcre2_real_general_context; - -/* The real compile context structure */ - -typedef struct pcre2_real_compile_context { - pcre2_memctl memctl; - int (*stack_guard)(uint32_t, void *); - void *stack_guard_data; - const uint8_t *tables; - PCRE2_SIZE max_pattern_length; - uint16_t bsr_convention; - uint16_t newline_convention; - uint32_t parens_nest_limit; - uint32_t extra_options; -} pcre2_real_compile_context; - -/* The real match context structure. */ - -typedef struct pcre2_real_match_context { - pcre2_memctl memctl; -#ifdef SUPPORT_JIT - pcre2_jit_callback jit_callback; - void *jit_callback_data; -#endif - int (*callout)(pcre2_callout_block *, void *); - void *callout_data; - int (*substitute_callout)(pcre2_substitute_callout_block *, void *); - void *substitute_callout_data; - PCRE2_SIZE offset_limit; - uint32_t heap_limit; - uint32_t match_limit; - uint32_t depth_limit; -} pcre2_real_match_context; - -/* The real convert context structure. */ - -typedef struct pcre2_real_convert_context { - pcre2_memctl memctl; - uint32_t glob_separator; - uint32_t glob_escape; -} pcre2_real_convert_context; - -/* The real compiled code structure. The type for the blocksize field is -defined specially because it is required in pcre2_serialize_decode() when -copying the size from possibly unaligned memory into a variable of the same -type. Use a macro rather than a typedef to avoid compiler warnings when this -file is included multiple times by pcre2test. LOOKBEHIND_MAX specifies the -largest lookbehind that is supported. (OP_REVERSE in a pattern has a 16-bit -argument in 8-bit and 16-bit modes, so we need no more than a 16-bit field -here.) */ - -#undef CODE_BLOCKSIZE_TYPE -#define CODE_BLOCKSIZE_TYPE size_t - -#undef LOOKBEHIND_MAX -#define LOOKBEHIND_MAX UINT16_MAX - -typedef struct pcre2_real_code { - pcre2_memctl memctl; /* Memory control fields */ - const uint8_t *tables; /* The character tables */ - void *executable_jit; /* Pointer to JIT code */ - uint8_t start_bitmap[32]; /* Bitmap for starting code unit < 256 */ - CODE_BLOCKSIZE_TYPE blocksize; /* Total (bytes) that was malloc-ed */ - uint32_t magic_number; /* Paranoid and endianness check */ - uint32_t compile_options; /* Options passed to pcre2_compile() */ - uint32_t overall_options; /* Options after processing the pattern */ - uint32_t extra_options; /* Taken from compile_context */ - uint32_t flags; /* Various state flags */ - uint32_t limit_heap; /* Limit set in the pattern */ - uint32_t limit_match; /* Limit set in the pattern */ - uint32_t limit_depth; /* Limit set in the pattern */ - uint32_t first_codeunit; /* Starting code unit */ - uint32_t last_codeunit; /* This codeunit must be seen */ - uint16_t bsr_convention; /* What \R matches */ - uint16_t newline_convention; /* What is a newline? */ - uint16_t max_lookbehind; /* Longest lookbehind (characters) */ - uint16_t minlength; /* Minimum length of match */ - uint16_t top_bracket; /* Highest numbered group */ - uint16_t top_backref; /* Highest numbered back reference */ - uint16_t name_entry_size; /* Size (code units) of table entries */ - uint16_t name_count; /* Number of name entries in the table */ -} pcre2_real_code; - -/* The real match data structure. Define ovector as large as it can ever -actually be so that array bound checkers don't grumble. Memory for this -structure is obtained by calling pcre2_match_data_create(), which sets the size -as the offset of ovector plus a pair of elements for each capturable string, so -the size varies from call to call. As the maximum number of capturing -subpatterns is 65535 we must allow for 65536 strings to include the overall -match. (See also the heapframe structure below.) */ - -struct heapframe; /* Forward reference */ - -typedef struct pcre2_real_match_data { - pcre2_memctl memctl; /* Memory control fields */ - const pcre2_real_code *code; /* The pattern used for the match */ - PCRE2_SPTR subject; /* The subject that was matched */ - PCRE2_SPTR mark; /* Pointer to last mark */ - struct heapframe *heapframes; /* Backtracking frames heap memory */ - PCRE2_SIZE heapframes_size; /* Malloc-ed size */ - PCRE2_SIZE leftchar; /* Offset to leftmost code unit */ - PCRE2_SIZE rightchar; /* Offset to rightmost code unit */ - PCRE2_SIZE startchar; /* Offset to starting code unit */ - uint8_t matchedby; /* Type of match (normal, JIT, DFA) */ - uint8_t flags; /* Various flags */ - uint16_t oveccount; /* Number of pairs */ - int rc; /* The return code from the match */ - PCRE2_SIZE ovector[131072]; /* Must be last in the structure */ -} pcre2_real_match_data; - - -/* ----------------------- PRIVATE STRUCTURES ----------------------------- */ - -/* These structures are not needed for pcre2test. */ - -#ifndef PCRE2_PCRE2TEST - -/* Structures for checking for mutual recursion when scanning compiled or -parsed code. */ - -typedef struct recurse_check { - struct recurse_check *prev; - PCRE2_SPTR group; -} recurse_check; - -typedef struct parsed_recurse_check { - struct parsed_recurse_check *prev; - uint32_t *groupptr; -} parsed_recurse_check; - -/* Structure for building a cache when filling in recursion offsets. */ - -typedef struct recurse_cache { - PCRE2_SPTR group; - int groupnumber; -} recurse_cache; - -/* Structure for maintaining a chain of pointers to the currently incomplete -branches, for testing for left recursion while compiling. */ - -typedef struct branch_chain { - struct branch_chain *outer; - PCRE2_UCHAR *current_branch; -} branch_chain; - -/* Structure for building a list of named groups during the first pass of -compiling. */ - -typedef struct named_group { - PCRE2_SPTR name; /* Points to the name in the pattern */ - uint32_t number; /* Group number */ - uint16_t length; /* Length of the name */ - uint16_t isdup; /* TRUE if a duplicate */ -} named_group; - -/* Structure for passing "static" information around between the functions -doing the compiling, so that they are thread-safe. */ - -typedef struct compile_block { - pcre2_real_compile_context *cx; /* Points to the compile context */ - const uint8_t *lcc; /* Points to lower casing table */ - const uint8_t *fcc; /* Points to case-flipping table */ - const uint8_t *cbits; /* Points to character type table */ - const uint8_t *ctypes; /* Points to table of type maps */ - PCRE2_SPTR start_workspace; /* The start of working space */ - PCRE2_SPTR start_code; /* The start of the compiled code */ - PCRE2_SPTR start_pattern; /* The start of the pattern */ - PCRE2_SPTR end_pattern; /* The end of the pattern */ - PCRE2_UCHAR *name_table; /* The name/number table */ - PCRE2_SIZE workspace_size; /* Size of workspace */ - PCRE2_SIZE small_ref_offset[10]; /* Offsets for \1 to \9 */ - PCRE2_SIZE erroroffset; /* Offset of error in pattern */ - uint16_t names_found; /* Number of entries so far */ - uint16_t name_entry_size; /* Size of each entry */ - uint16_t parens_depth; /* Depth of nested parentheses */ - uint16_t assert_depth; /* Depth of nested assertions */ - open_capitem *open_caps; /* Chain of open capture items */ - named_group *named_groups; /* Points to vector in pre-compile */ - uint32_t named_group_list_size; /* Number of entries in the list */ - uint32_t external_options; /* External (initial) options */ - uint32_t external_flags; /* External flag bits to be set */ - uint32_t bracount; /* Count of capturing parentheses */ - uint32_t lastcapture; /* Last capture encountered */ - uint32_t *parsed_pattern; /* Parsed pattern buffer */ - uint32_t *parsed_pattern_end; /* Parsed pattern should not get here */ - uint32_t *groupinfo; /* Group info vector */ - uint32_t top_backref; /* Maximum back reference */ - uint32_t backref_map; /* Bitmap of low back refs */ - uint32_t nltype; /* Newline type */ - uint32_t nllen; /* Newline string length */ - uint32_t class_range_start; /* Overall class range start */ - uint32_t class_range_end; /* Overall class range end */ - PCRE2_UCHAR nl[4]; /* Newline string when fixed length */ - uint32_t req_varyopt; /* "After variable item" flag for reqbyte */ - int max_lookbehind; /* Maximum lookbehind (characters) */ - BOOL had_accept; /* (*ACCEPT) encountered */ - BOOL had_pruneorskip; /* (*PRUNE) or (*SKIP) encountered */ - BOOL had_recurse; /* Had a recursion or subroutine call */ - BOOL dupnames; /* Duplicate names exist */ -} compile_block; - -/* Structure for keeping the properties of the in-memory stack used -by the JIT matcher. */ - -typedef struct pcre2_real_jit_stack { - pcre2_memctl memctl; - void* stack; -} pcre2_real_jit_stack; - -/* Structure for items in a linked list that represents an explicit recursive -call within the pattern when running pcre2_dfa_match(). */ - -typedef struct dfa_recursion_info { - struct dfa_recursion_info *prevrec; - PCRE2_SPTR subject_position; - uint32_t group_num; -} dfa_recursion_info; - -/* Structure for "stack" frames that are used for remembering backtracking -positions during matching. As these are used in a vector, with the ovector item -being extended, the size of the structure must be a multiple of PCRE2_SIZE. The -only way to check this at compile time is to force an error by generating an -array with a negative size. By putting this in a typedef (which is never used), -we don't generate any code when all is well. */ - -typedef struct heapframe { - - /* The first set of fields are variables that have to be preserved over calls - to RRMATCH(), but which do not need to be copied to new frames. */ - - PCRE2_SPTR ecode; /* The current position in the pattern */ - PCRE2_SPTR temp_sptr[2]; /* Used for short-term PCRE_SPTR values */ - PCRE2_SIZE length; /* Used for character, string, or code lengths */ - PCRE2_SIZE back_frame; /* Amount to subtract on RRETURN */ - PCRE2_SIZE temp_size; /* Used for short-term PCRE2_SIZE values */ - uint32_t rdepth; /* "Recursion" depth */ - uint32_t group_frame_type; /* Type information for group frames */ - uint32_t temp_32[4]; /* Used for short-term 32-bit or BOOL values */ - uint8_t return_id; /* Where to go on in internal "return" */ - uint8_t op; /* Processing opcode */ - - /* At this point, the structure is 16-bit aligned. On most architectures - the alignment requirement for a pointer will ensure that the eptr field below - is 32-bit or 64-bit aligned. However, on m68k it is fine to have a pointer - that is 16-bit aligned. We must therefore ensure that what comes between here - and eptr is an odd multiple of 16 bits so as to get back into 32-bit - alignment. This happens naturally when PCRE2_UCHAR is 8 bits wide, but needs - fudges in the other cases. In the 32-bit case the padding comes first so that - the occu field itself is 32-bit aligned. Without the padding, this structure - is no longer a multiple of PCRE2_SIZE on m68k, and the check below fails. */ - -#if PCRE2_CODE_UNIT_WIDTH == 8 - PCRE2_UCHAR occu[6]; /* Used for other case code units */ -#elif PCRE2_CODE_UNIT_WIDTH == 16 - PCRE2_UCHAR occu[2]; /* Used for other case code units */ - uint8_t unused[2]; /* Ensure 32-bit alignment (see above) */ -#else - uint8_t unused[2]; /* Ensure 32-bit alignment (see above) */ - PCRE2_UCHAR occu[1]; /* Used for other case code units */ -#endif - - /* The rest have to be copied from the previous frame whenever a new frame - becomes current. The final field is specified as a large vector so that - runtime array bound checks don't catch references to it. However, for any - specific call to pcre2_match() the memory allocated for each frame structure - allows for exactly the right size ovector for the number of capturing - parentheses. (See also the comment for pcre2_real_match_data above.) */ - - PCRE2_SPTR eptr; /* MUST BE FIRST */ - PCRE2_SPTR start_match; /* Can be adjusted by \K */ - PCRE2_SPTR mark; /* Most recent mark on the success path */ - uint32_t current_recurse; /* Current (deepest) recursion number */ - uint32_t capture_last; /* Most recent capture */ - PCRE2_SIZE last_group_offset; /* Saved offset to most recent group frame */ - PCRE2_SIZE offset_top; /* Offset after highest capture */ - PCRE2_SIZE ovector[131072]; /* Must be last in the structure */ -} heapframe; - -/* This typedef is a check that the size of the heapframe structure is a -multiple of PCRE2_SIZE. See various comments above. */ - -typedef char check_heapframe_size[ - ((sizeof(heapframe) % sizeof(PCRE2_SIZE)) == 0)? (+1):(-1)]; - -/* Structure for computing the alignment of heapframe. */ - -typedef struct heapframe_align { - char unalign; /* Completely unalign the current offset */ - heapframe frame; /* Offset is its alignment */ -} heapframe_align; - -/* This define is the minimum alignment required for a heapframe, in bytes. */ - -#define HEAPFRAME_ALIGNMENT offsetof(heapframe_align, frame) - -/* Structure for passing "static" information around between the functions -doing traditional NFA matching (pcre2_match() and friends). */ - -typedef struct match_block { - pcre2_memctl memctl; /* For general use */ - PCRE2_SIZE heap_limit; /* As it says */ - uint32_t match_limit; /* As it says */ - uint32_t match_limit_depth; /* As it says */ - uint32_t match_call_count; /* Number of times a new frame is created */ - BOOL hitend; /* Hit the end of the subject at some point */ - BOOL hasthen; /* Pattern contains (*THEN) */ - BOOL allowemptypartial; /* Allow empty hard partial */ - const uint8_t *lcc; /* Points to lower casing table */ - const uint8_t *fcc; /* Points to case-flipping table */ - const uint8_t *ctypes; /* Points to table of type maps */ - PCRE2_SIZE start_offset; /* The start offset value */ - PCRE2_SIZE end_offset_top; /* Highwater mark at end of match */ - uint16_t partial; /* PARTIAL options */ - uint16_t bsr_convention; /* \R interpretation */ - uint16_t name_count; /* Number of names in name table */ - uint16_t name_entry_size; /* Size of entry in names table */ - PCRE2_SPTR name_table; /* Table of group names */ - PCRE2_SPTR start_code; /* For use when recursing */ - PCRE2_SPTR start_subject; /* Start of the subject string */ - PCRE2_SPTR check_subject; /* Where UTF-checked from */ - PCRE2_SPTR end_subject; /* End of the subject string */ - PCRE2_SPTR end_match_ptr; /* Subject position at end match */ - PCRE2_SPTR start_used_ptr; /* Earliest consulted character */ - PCRE2_SPTR last_used_ptr; /* Latest consulted character */ - PCRE2_SPTR mark; /* Mark pointer to pass back on success */ - PCRE2_SPTR nomatch_mark; /* Mark pointer to pass back on failure */ - PCRE2_SPTR verb_ecode_ptr; /* For passing back info */ - PCRE2_SPTR verb_skip_ptr; /* For passing back a (*SKIP) name */ - uint32_t verb_current_recurse; /* Current recurse when (*VERB) happens */ - uint32_t moptions; /* Match options */ - uint32_t poptions; /* Pattern options */ - uint32_t skip_arg_count; /* For counting SKIP_ARGs */ - uint32_t ignore_skip_arg; /* For re-run when SKIP arg name not found */ - uint32_t nltype; /* Newline type */ - uint32_t nllen; /* Newline string length */ - PCRE2_UCHAR nl[4]; /* Newline string when fixed */ - pcre2_callout_block *cb; /* Points to a callout block */ - void *callout_data; /* To pass back to callouts */ - int (*callout)(pcre2_callout_block *,void *); /* Callout function or NULL */ -} match_block; - -/* A similar structure is used for the same purpose by the DFA matching -functions. */ - -typedef struct dfa_match_block { - pcre2_memctl memctl; /* For general use */ - PCRE2_SPTR start_code; /* Start of the compiled pattern */ - PCRE2_SPTR start_subject ; /* Start of the subject string */ - PCRE2_SPTR end_subject; /* End of subject string */ - PCRE2_SPTR start_used_ptr; /* Earliest consulted character */ - PCRE2_SPTR last_used_ptr; /* Latest consulted character */ - const uint8_t *tables; /* Character tables */ - PCRE2_SIZE start_offset; /* The start offset value */ - PCRE2_SIZE heap_limit; /* As it says */ - PCRE2_SIZE heap_used; /* As it says */ - uint32_t match_limit; /* As it says */ - uint32_t match_limit_depth; /* As it says */ - uint32_t match_call_count; /* Number of calls of internal function */ - uint32_t moptions; /* Match options */ - uint32_t poptions; /* Pattern options */ - uint32_t nltype; /* Newline type */ - uint32_t nllen; /* Newline string length */ - BOOL allowemptypartial; /* Allow empty hard partial */ - PCRE2_UCHAR nl[4]; /* Newline string when fixed */ - uint16_t bsr_convention; /* \R interpretation */ - pcre2_callout_block *cb; /* Points to a callout block */ - void *callout_data; /* To pass back to callouts */ - int (*callout)(pcre2_callout_block *,void *); /* Callout function or NULL */ - dfa_recursion_info *recursive; /* Linked list of recursion data */ -} dfa_match_block; - -#endif /* PCRE2_PCRE2TEST */ - -/* End of pcre2_intmodedep.h */ diff --git a/modules/regex/pcre2/src/pcre2_jit_compile.c b/modules/regex/pcre2/src/pcre2_jit_compile.c deleted file mode 100644 index 0afd27c..0000000 --- a/modules/regex/pcre2/src/pcre2_jit_compile.c +++ /dev/null @@ -1,14507 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -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 - ------------------------------------------------------------------------------ -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 OWNER 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. ------------------------------------------------------------------------------ -*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "pcre2_internal.h" - -#ifdef SUPPORT_JIT - -/* All-in-one: Since we use the JIT compiler only from here, -we just include it. This way we don't need to touch the build -system files. */ - -#define SLJIT_CONFIG_AUTO 1 -#define SLJIT_CONFIG_STATIC 1 -#define SLJIT_VERBOSE 0 - -#ifdef PCRE2_DEBUG -#define SLJIT_DEBUG 1 -#else -#define SLJIT_DEBUG 0 -#endif - -#define SLJIT_MALLOC(size, allocator_data) pcre2_jit_malloc(size, allocator_data) -#define SLJIT_FREE(ptr, allocator_data) pcre2_jit_free(ptr, allocator_data) - -static void * pcre2_jit_malloc(size_t size, void *allocator_data) -{ -pcre2_memctl *allocator = ((pcre2_memctl*)allocator_data); -return allocator->malloc(size, allocator->memory_data); -} - -static void pcre2_jit_free(void *ptr, void *allocator_data) -{ -pcre2_memctl *allocator = ((pcre2_memctl*)allocator_data); -allocator->free(ptr, allocator->memory_data); -} - -#include "sljit/sljitLir.c" - -#if defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED -#error Unsupported architecture -#endif - -/* Defines for debugging purposes. */ - -/* 1 - Use unoptimized capturing brackets. - 2 - Enable capture_last_ptr (includes option 1). */ -/* #define DEBUG_FORCE_UNOPTIMIZED_CBRAS 2 */ - -/* 1 - Always have a control head. */ -/* #define DEBUG_FORCE_CONTROL_HEAD 1 */ - -/* Allocate memory for the regex stack on the real machine stack. -Fast, but limited size. */ -#define MACHINE_STACK_SIZE 32768 - -/* Growth rate for stack allocated by the OS. Should be the multiply -of page size. */ -#define STACK_GROWTH_RATE 8192 - -/* Enable to check that the allocation could destroy temporaries. */ -#if defined SLJIT_DEBUG && SLJIT_DEBUG -#define DESTROY_REGISTERS 1 -#endif - -/* -Short summary about the backtracking mechanism empolyed by the jit code generator: - -The code generator follows the recursive nature of the PERL compatible regular -expressions. The basic blocks of regular expressions are condition checkers -whose execute different commands depending on the result of the condition check. -The relationship between the operators can be horizontal (concatenation) and -vertical (sub-expression) (See struct backtrack_common for more details). - - 'ab' - 'a' and 'b' regexps are concatenated - 'a+' - 'a' is the sub-expression of the '+' operator - -The condition checkers are boolean (true/false) checkers. Machine code is generated -for the checker itself and for the actions depending on the result of the checker. -The 'true' case is called as the matching path (expected path), and the other is called as -the 'backtrack' path. Branch instructions are expesive for all CPUs, so we avoid taken -branches on the matching path. - - Greedy star operator (*) : - Matching path: match happens. - Backtrack path: match failed. - Non-greedy star operator (*?) : - Matching path: no need to perform a match. - Backtrack path: match is required. - -The following example shows how the code generated for a capturing bracket -with two alternatives. Let A, B, C, D are arbirary regular expressions, and -we have the following regular expression: - - A(B|C)D - -The generated code will be the following: - - A matching path - '(' matching path (pushing arguments to the stack) - B matching path - ')' matching path (pushing arguments to the stack) - D matching path - return with successful match - - D backtrack path - ')' backtrack path (If we arrived from "C" jump to the backtrack of "C") - B backtrack path - C expected path - jump to D matching path - C backtrack path - A backtrack path - - Notice, that the order of backtrack code paths are the opposite of the fast - code paths. In this way the topmost value on the stack is always belong - to the current backtrack code path. The backtrack path must check - whether there is a next alternative. If so, it needs to jump back to - the matching path eventually. Otherwise it needs to clear out its own stack - frame and continue the execution on the backtrack code paths. -*/ - -/* -Saved stack frames: - -Atomic blocks and asserts require reloading the values of private data -when the backtrack mechanism performed. Because of OP_RECURSE, the data -are not necessarly known in compile time, thus we need a dynamic restore -mechanism. - -The stack frames are stored in a chain list, and have the following format: -([ capturing bracket offset ][ start value ][ end value ])+ ... [ 0 ] [ previous head ] - -Thus we can restore the private data to a particular point in the stack. -*/ - -typedef struct jit_arguments { - /* Pointers first. */ - struct sljit_stack *stack; - PCRE2_SPTR str; - PCRE2_SPTR begin; - PCRE2_SPTR end; - pcre2_match_data *match_data; - PCRE2_SPTR startchar_ptr; - PCRE2_UCHAR *mark_ptr; - int (*callout)(pcre2_callout_block *, void *); - void *callout_data; - /* Everything else after. */ - sljit_uw offset_limit; - sljit_u32 limit_match; - sljit_u32 oveccount; - sljit_u32 options; -} jit_arguments; - -#define JIT_NUMBER_OF_COMPILE_MODES 3 - -typedef struct executable_functions { - void *executable_funcs[JIT_NUMBER_OF_COMPILE_MODES]; - void *read_only_data_heads[JIT_NUMBER_OF_COMPILE_MODES]; - sljit_uw executable_sizes[JIT_NUMBER_OF_COMPILE_MODES]; - sljit_u32 top_bracket; - sljit_u32 limit_match; -} executable_functions; - -typedef struct jump_list { - struct sljit_jump *jump; - struct jump_list *next; -} jump_list; - -typedef struct stub_list { - struct sljit_jump *start; - struct sljit_label *quit; - struct stub_list *next; -} stub_list; - -enum frame_types { - no_frame = -1, - no_stack = -2 -}; - -enum control_types { - type_mark = 0, - type_then_trap = 1 -}; - -enum early_fail_types { - type_skip = 0, - type_fail = 1, - type_fail_range = 2 -}; - -typedef int (SLJIT_FUNC *jit_function)(jit_arguments *args); - -/* The following structure is the key data type for the recursive -code generator. It is allocated by compile_matchingpath, and contains -the arguments for compile_backtrackingpath. Must be the first member -of its descendants. */ -typedef struct backtrack_common { - /* Concatenation stack. */ - struct backtrack_common *prev; - jump_list *nextbacktracks; - /* Internal stack (for component operators). */ - struct backtrack_common *top; - jump_list *topbacktracks; - /* Opcode pointer. */ - PCRE2_SPTR cc; -} backtrack_common; - -typedef struct assert_backtrack { - backtrack_common common; - jump_list *condfailed; - /* Less than 0 if a frame is not needed. */ - int framesize; - /* Points to our private memory word on the stack. */ - int private_data_ptr; - /* For iterators. */ - struct sljit_label *matchingpath; -} assert_backtrack; - -typedef struct bracket_backtrack { - backtrack_common common; - /* Where to coninue if an alternative is successfully matched. */ - struct sljit_label *alternative_matchingpath; - /* For rmin and rmax iterators. */ - struct sljit_label *recursive_matchingpath; - /* For greedy ? operator. */ - struct sljit_label *zero_matchingpath; - /* Contains the branches of a failed condition. */ - union { - /* Both for OP_COND, OP_SCOND. */ - jump_list *condfailed; - assert_backtrack *assert; - /* For OP_ONCE. Less than 0 if not needed. */ - int framesize; - /* For brackets with >3 alternatives. */ - struct sljit_put_label *matching_put_label; - } u; - /* Points to our private memory word on the stack. */ - int private_data_ptr; -} bracket_backtrack; - -typedef struct bracketpos_backtrack { - backtrack_common common; - /* Points to our private memory word on the stack. */ - int private_data_ptr; - /* Reverting stack is needed. */ - int framesize; - /* Allocated stack size. */ - int stacksize; -} bracketpos_backtrack; - -typedef struct braminzero_backtrack { - backtrack_common common; - struct sljit_label *matchingpath; -} braminzero_backtrack; - -typedef struct char_iterator_backtrack { - backtrack_common common; - /* Next iteration. */ - struct sljit_label *matchingpath; - union { - jump_list *backtracks; - struct { - unsigned int othercasebit; - PCRE2_UCHAR chr; - BOOL enabled; - } charpos; - } u; -} char_iterator_backtrack; - -typedef struct ref_iterator_backtrack { - backtrack_common common; - /* Next iteration. */ - struct sljit_label *matchingpath; -} ref_iterator_backtrack; - -typedef struct recurse_entry { - struct recurse_entry *next; - /* Contains the function entry label. */ - struct sljit_label *entry_label; - /* Contains the function entry label. */ - struct sljit_label *backtrack_label; - /* Collects the entry calls until the function is not created. */ - jump_list *entry_calls; - /* Collects the backtrack calls until the function is not created. */ - jump_list *backtrack_calls; - /* Points to the starting opcode. */ - sljit_sw start; -} recurse_entry; - -typedef struct recurse_backtrack { - backtrack_common common; - /* Return to the matching path. */ - struct sljit_label *matchingpath; - /* Recursive pattern. */ - recurse_entry *entry; - /* Pattern is inlined. */ - BOOL inlined_pattern; -} recurse_backtrack; - -#define OP_THEN_TRAP OP_TABLE_LENGTH - -typedef struct then_trap_backtrack { - backtrack_common common; - /* If then_trap is not NULL, this structure contains the real - then_trap for the backtracking path. */ - struct then_trap_backtrack *then_trap; - /* Points to the starting opcode. */ - sljit_sw start; - /* Exit point for the then opcodes of this alternative. */ - jump_list *quit; - /* Frame size of the current alternative. */ - int framesize; -} then_trap_backtrack; - -#define MAX_N_CHARS 12 -#define MAX_DIFF_CHARS 5 - -typedef struct fast_forward_char_data { - /* Number of characters in the chars array, 255 for any character. */ - sljit_u8 count; - /* Number of last UTF-8 characters in the chars array. */ - sljit_u8 last_count; - /* Available characters in the current position. */ - PCRE2_UCHAR chars[MAX_DIFF_CHARS]; -} fast_forward_char_data; - -#define MAX_CLASS_RANGE_SIZE 4 -#define MAX_CLASS_CHARS_SIZE 3 - -typedef struct compiler_common { - /* The sljit ceneric compiler. */ - struct sljit_compiler *compiler; - /* Compiled regular expression. */ - pcre2_real_code *re; - /* First byte code. */ - PCRE2_SPTR start; - /* Maps private data offset to each opcode. */ - sljit_s32 *private_data_ptrs; - /* Chain list of read-only data ptrs. */ - void *read_only_data_head; - /* Tells whether the capturing bracket is optimized. */ - sljit_u8 *optimized_cbracket; - /* Tells whether the starting offset is a target of then. */ - sljit_u8 *then_offsets; - /* Current position where a THEN must jump. */ - then_trap_backtrack *then_trap; - /* Starting offset of private data for capturing brackets. */ - sljit_s32 cbra_ptr; - /* Output vector starting point. Must be divisible by 2. */ - sljit_s32 ovector_start; - /* Points to the starting character of the current match. */ - sljit_s32 start_ptr; - /* Last known position of the requested byte. */ - sljit_s32 req_char_ptr; - /* Head of the last recursion. */ - sljit_s32 recursive_head_ptr; - /* First inspected character for partial matching. - (Needed for avoiding zero length partial matches.) */ - sljit_s32 start_used_ptr; - /* Starting pointer for partial soft matches. */ - sljit_s32 hit_start; - /* Pointer of the match end position. */ - sljit_s32 match_end_ptr; - /* Points to the marked string. */ - sljit_s32 mark_ptr; - /* Recursive control verb management chain. */ - sljit_s32 control_head_ptr; - /* Points to the last matched capture block index. */ - sljit_s32 capture_last_ptr; - /* Fast forward skipping byte code pointer. */ - PCRE2_SPTR fast_forward_bc_ptr; - /* Locals used by fast fail optimization. */ - sljit_s32 early_fail_start_ptr; - sljit_s32 early_fail_end_ptr; - /* Variables used by recursive call generator. */ - sljit_s32 recurse_bitset_size; - uint8_t *recurse_bitset; - - /* Flipped and lower case tables. */ - const sljit_u8 *fcc; - sljit_sw lcc; - /* Mode can be PCRE2_JIT_COMPLETE and others. */ - int mode; - /* TRUE, when empty match is accepted for partial matching. */ - BOOL allow_empty_partial; - /* TRUE, when minlength is greater than 0. */ - BOOL might_be_empty; - /* \K is found in the pattern. */ - BOOL has_set_som; - /* (*SKIP:arg) is found in the pattern. */ - BOOL has_skip_arg; - /* (*THEN) is found in the pattern. */ - BOOL has_then; - /* (*SKIP) or (*SKIP:arg) is found in lookbehind assertion. */ - BOOL has_skip_in_assert_back; - /* Quit is redirected by recurse, negative assertion, or positive assertion in conditional block. */ - BOOL local_quit_available; - /* Currently in a positive assertion. */ - BOOL in_positive_assertion; - /* Newline control. */ - int nltype; - sljit_u32 nlmax; - sljit_u32 nlmin; - int newline; - int bsr_nltype; - sljit_u32 bsr_nlmax; - sljit_u32 bsr_nlmin; - /* Dollar endonly. */ - int endonly; - /* Tables. */ - sljit_sw ctypes; - /* Named capturing brackets. */ - PCRE2_SPTR name_table; - sljit_sw name_count; - sljit_sw name_entry_size; - - /* Labels and jump lists. */ - struct sljit_label *partialmatchlabel; - struct sljit_label *quit_label; - struct sljit_label *abort_label; - struct sljit_label *accept_label; - struct sljit_label *ff_newline_shortcut; - stub_list *stubs; - recurse_entry *entries; - recurse_entry *currententry; - jump_list *partialmatch; - jump_list *quit; - jump_list *positive_assertion_quit; - jump_list *abort; - jump_list *failed_match; - jump_list *accept; - jump_list *calllimit; - jump_list *stackalloc; - jump_list *revertframes; - jump_list *wordboundary; - jump_list *anynewline; - jump_list *hspace; - jump_list *vspace; - jump_list *casefulcmp; - jump_list *caselesscmp; - jump_list *reset_match; - BOOL unset_backref; - BOOL alt_circumflex; -#ifdef SUPPORT_UNICODE - BOOL utf; - BOOL invalid_utf; - BOOL ucp; - /* Points to saving area for iref. */ - sljit_s32 iref_ptr; - jump_list *getucd; - jump_list *getucdtype; -#if PCRE2_CODE_UNIT_WIDTH == 8 - jump_list *utfreadchar; - jump_list *utfreadtype8; - jump_list *utfpeakcharback; -#endif -#if PCRE2_CODE_UNIT_WIDTH == 8 || PCRE2_CODE_UNIT_WIDTH == 16 - jump_list *utfreadchar_invalid; - jump_list *utfreadnewline_invalid; - jump_list *utfmoveback_invalid; - jump_list *utfpeakcharback_invalid; -#endif -#endif /* SUPPORT_UNICODE */ -} compiler_common; - -/* For byte_sequence_compare. */ - -typedef struct compare_context { - int length; - int sourcereg; -#if defined SLJIT_UNALIGNED && SLJIT_UNALIGNED - int ucharptr; - union { - sljit_s32 asint; - sljit_u16 asushort; -#if PCRE2_CODE_UNIT_WIDTH == 8 - sljit_u8 asbyte; - sljit_u8 asuchars[4]; -#elif PCRE2_CODE_UNIT_WIDTH == 16 - sljit_u16 asuchars[2]; -#elif PCRE2_CODE_UNIT_WIDTH == 32 - sljit_u32 asuchars[1]; -#endif - } c; - union { - sljit_s32 asint; - sljit_u16 asushort; -#if PCRE2_CODE_UNIT_WIDTH == 8 - sljit_u8 asbyte; - sljit_u8 asuchars[4]; -#elif PCRE2_CODE_UNIT_WIDTH == 16 - sljit_u16 asuchars[2]; -#elif PCRE2_CODE_UNIT_WIDTH == 32 - sljit_u32 asuchars[1]; -#endif - } oc; -#endif -} compare_context; - -/* Undefine sljit macros. */ -#undef CMP - -/* Used for accessing the elements of the stack. */ -#define STACK(i) ((i) * SSIZE_OF(sw)) - -#ifdef SLJIT_PREF_SHIFT_REG -#if SLJIT_PREF_SHIFT_REG == SLJIT_R2 -/* Nothing. */ -#elif SLJIT_PREF_SHIFT_REG == SLJIT_R3 -#define SHIFT_REG_IS_R3 -#else -#error "Unsupported shift register" -#endif -#endif - -#define TMP1 SLJIT_R0 -#ifdef SHIFT_REG_IS_R3 -#define TMP2 SLJIT_R3 -#define TMP3 SLJIT_R2 -#else -#define TMP2 SLJIT_R2 -#define TMP3 SLJIT_R3 -#endif -#define STR_PTR SLJIT_R1 -#define STR_END SLJIT_S0 -#define STACK_TOP SLJIT_S1 -#define STACK_LIMIT SLJIT_S2 -#define COUNT_MATCH SLJIT_S3 -#define ARGUMENTS SLJIT_S4 -#define RETURN_ADDR SLJIT_R4 - -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) -#define HAS_VIRTUAL_REGISTERS 1 -#else -#define HAS_VIRTUAL_REGISTERS 0 -#endif - -/* Local space layout. */ -/* These two locals can be used by the current opcode. */ -#define LOCALS0 (0 * sizeof(sljit_sw)) -#define LOCALS1 (1 * sizeof(sljit_sw)) -/* Two local variables for possessive quantifiers (char1 cannot use them). */ -#define POSSESSIVE0 (2 * sizeof(sljit_sw)) -#define POSSESSIVE1 (3 * sizeof(sljit_sw)) -/* Max limit of recursions. */ -#define LIMIT_MATCH (4 * sizeof(sljit_sw)) -/* The output vector is stored on the stack, and contains pointers -to characters. The vector data is divided into two groups: the first -group contains the start / end character pointers, and the second is -the start pointers when the end of the capturing group has not yet reached. */ -#define OVECTOR_START (common->ovector_start) -#define OVECTOR(i) (OVECTOR_START + (i) * SSIZE_OF(sw)) -#define OVECTOR_PRIV(i) (common->cbra_ptr + (i) * SSIZE_OF(sw)) -#define PRIVATE_DATA(cc) (common->private_data_ptrs[(cc) - common->start]) - -#if PCRE2_CODE_UNIT_WIDTH == 8 -#define MOV_UCHAR SLJIT_MOV_U8 -#define IN_UCHARS(x) (x) -#elif PCRE2_CODE_UNIT_WIDTH == 16 -#define MOV_UCHAR SLJIT_MOV_U16 -#define UCHAR_SHIFT (1) -#define IN_UCHARS(x) ((x) * 2) -#elif PCRE2_CODE_UNIT_WIDTH == 32 -#define MOV_UCHAR SLJIT_MOV_U32 -#define UCHAR_SHIFT (2) -#define IN_UCHARS(x) ((x) * 4) -#else -#error Unsupported compiling mode -#endif - -/* Shortcuts. */ -#define DEFINE_COMPILER \ - struct sljit_compiler *compiler = common->compiler -#define OP1(op, dst, dstw, src, srcw) \ - sljit_emit_op1(compiler, (op), (dst), (dstw), (src), (srcw)) -#define OP2(op, dst, dstw, src1, src1w, src2, src2w) \ - sljit_emit_op2(compiler, (op), (dst), (dstw), (src1), (src1w), (src2), (src2w)) -#define OP2U(op, src1, src1w, src2, src2w) \ - sljit_emit_op2u(compiler, (op), (src1), (src1w), (src2), (src2w)) -#define OP_SRC(op, src, srcw) \ - sljit_emit_op_src(compiler, (op), (src), (srcw)) -#define LABEL() \ - sljit_emit_label(compiler) -#define JUMP(type) \ - sljit_emit_jump(compiler, (type)) -#define JUMPTO(type, label) \ - sljit_set_label(sljit_emit_jump(compiler, (type)), (label)) -#define JUMPHERE(jump) \ - sljit_set_label((jump), sljit_emit_label(compiler)) -#define SET_LABEL(jump, label) \ - sljit_set_label((jump), (label)) -#define CMP(type, src1, src1w, src2, src2w) \ - sljit_emit_cmp(compiler, (type), (src1), (src1w), (src2), (src2w)) -#define CMPTO(type, src1, src1w, src2, src2w, label) \ - sljit_set_label(sljit_emit_cmp(compiler, (type), (src1), (src1w), (src2), (src2w)), (label)) -#define OP_FLAGS(op, dst, dstw, type) \ - sljit_emit_op_flags(compiler, (op), (dst), (dstw), (type)) -#define CMOV(type, dst_reg, src, srcw) \ - sljit_emit_cmov(compiler, (type), (dst_reg), (src), (srcw)) -#define GET_LOCAL_BASE(dst, dstw, offset) \ - sljit_get_local_base(compiler, (dst), (dstw), (offset)) - -#define READ_CHAR_MAX 0x7fffffff - -#define INVALID_UTF_CHAR -1 -#define UNASSIGNED_UTF_CHAR 888 - -#if defined SUPPORT_UNICODE -#if PCRE2_CODE_UNIT_WIDTH == 8 - -#define GETCHARINC_INVALID(c, ptr, end, invalid_action) \ - { \ - if (ptr[0] <= 0x7f) \ - c = *ptr++; \ - else if (ptr + 1 < end && ptr[1] >= 0x80 && ptr[1] < 0xc0) \ - { \ - c = ptr[1] - 0x80; \ - \ - if (ptr[0] >= 0xc2 && ptr[0] <= 0xdf) \ - { \ - c |= (ptr[0] - 0xc0) << 6; \ - ptr += 2; \ - } \ - else if (ptr + 2 < end && ptr[2] >= 0x80 && ptr[2] < 0xc0) \ - { \ - c = c << 6 | (ptr[2] - 0x80); \ - \ - if (ptr[0] >= 0xe0 && ptr[0] <= 0xef) \ - { \ - c |= (ptr[0] - 0xe0) << 12; \ - ptr += 3; \ - \ - if (c < 0x800 || (c >= 0xd800 && c < 0xe000)) \ - { \ - invalid_action; \ - } \ - } \ - else if (ptr + 3 < end && ptr[3] >= 0x80 && ptr[3] < 0xc0) \ - { \ - c = c << 6 | (ptr[3] - 0x80); \ - \ - if (ptr[0] >= 0xf0 && ptr[0] <= 0xf4) \ - { \ - c |= (ptr[0] - 0xf0) << 18; \ - ptr += 4; \ - \ - if (c >= 0x110000 || c < 0x10000) \ - { \ - invalid_action; \ - } \ - } \ - else \ - { \ - invalid_action; \ - } \ - } \ - else \ - { \ - invalid_action; \ - } \ - } \ - else \ - { \ - invalid_action; \ - } \ - } \ - else \ - { \ - invalid_action; \ - } \ - } - -#define GETCHARBACK_INVALID(c, ptr, start, invalid_action) \ - { \ - c = ptr[-1]; \ - if (c <= 0x7f) \ - ptr--; \ - else if (ptr - 1 > start && ptr[-1] >= 0x80 && ptr[-1] < 0xc0) \ - { \ - c -= 0x80; \ - \ - if (ptr[-2] >= 0xc2 && ptr[-2] <= 0xdf) \ - { \ - c |= (ptr[-2] - 0xc0) << 6; \ - ptr -= 2; \ - } \ - else if (ptr - 2 > start && ptr[-2] >= 0x80 && ptr[-2] < 0xc0) \ - { \ - c = c << 6 | (ptr[-2] - 0x80); \ - \ - if (ptr[-3] >= 0xe0 && ptr[-3] <= 0xef) \ - { \ - c |= (ptr[-3] - 0xe0) << 12; \ - ptr -= 3; \ - \ - if (c < 0x800 || (c >= 0xd800 && c < 0xe000)) \ - { \ - invalid_action; \ - } \ - } \ - else if (ptr - 3 > start && ptr[-3] >= 0x80 && ptr[-3] < 0xc0) \ - { \ - c = c << 6 | (ptr[-3] - 0x80); \ - \ - if (ptr[-4] >= 0xf0 && ptr[-4] <= 0xf4) \ - { \ - c |= (ptr[-4] - 0xf0) << 18; \ - ptr -= 4; \ - \ - if (c >= 0x110000 || c < 0x10000) \ - { \ - invalid_action; \ - } \ - } \ - else \ - { \ - invalid_action; \ - } \ - } \ - else \ - { \ - invalid_action; \ - } \ - } \ - else \ - { \ - invalid_action; \ - } \ - } \ - else \ - { \ - invalid_action; \ - } \ - } - -#elif PCRE2_CODE_UNIT_WIDTH == 16 - -#define GETCHARINC_INVALID(c, ptr, end, invalid_action) \ - { \ - if (ptr[0] < 0xd800 || ptr[0] >= 0xe000) \ - c = *ptr++; \ - else if (ptr[0] < 0xdc00 && ptr + 1 < end && ptr[1] >= 0xdc00 && ptr[1] < 0xe000) \ - { \ - c = (((ptr[0] - 0xd800) << 10) | (ptr[1] - 0xdc00)) + 0x10000; \ - ptr += 2; \ - } \ - else \ - { \ - invalid_action; \ - } \ - } - -#define GETCHARBACK_INVALID(c, ptr, start, invalid_action) \ - { \ - c = ptr[-1]; \ - if (c < 0xd800 || c >= 0xe000) \ - ptr--; \ - else if (c >= 0xdc00 && ptr - 1 > start && ptr[-2] >= 0xd800 && ptr[-2] < 0xdc00) \ - { \ - c = (((ptr[-2] - 0xd800) << 10) | (c - 0xdc00)) + 0x10000; \ - ptr -= 2; \ - } \ - else \ - { \ - invalid_action; \ - } \ - } - - -#elif PCRE2_CODE_UNIT_WIDTH == 32 - -#define GETCHARINC_INVALID(c, ptr, end, invalid_action) \ - { \ - if (ptr[0] < 0xd800 || (ptr[0] >= 0xe000 && ptr[0] < 0x110000)) \ - c = *ptr++; \ - else \ - { \ - invalid_action; \ - } \ - } - -#define GETCHARBACK_INVALID(c, ptr, start, invalid_action) \ - { \ - c = ptr[-1]; \ - if (ptr[-1] < 0xd800 || (ptr[-1] >= 0xe000 && ptr[-1] < 0x110000)) \ - ptr--; \ - else \ - { \ - invalid_action; \ - } \ - } - -#endif /* PCRE2_CODE_UNIT_WIDTH == [8|16|32] */ -#endif /* SUPPORT_UNICODE */ - -static PCRE2_SPTR bracketend(PCRE2_SPTR cc) -{ -SLJIT_ASSERT((*cc >= OP_ASSERT && *cc <= OP_ASSERTBACK_NA) || (*cc >= OP_ONCE && *cc <= OP_SCOND)); -do cc += GET(cc, 1); while (*cc == OP_ALT); -SLJIT_ASSERT(*cc >= OP_KET && *cc <= OP_KETRPOS); -cc += 1 + LINK_SIZE; -return cc; -} - -static int no_alternatives(PCRE2_SPTR cc) -{ -int count = 0; -SLJIT_ASSERT((*cc >= OP_ASSERT && *cc <= OP_ASSERTBACK_NA) || (*cc >= OP_ONCE && *cc <= OP_SCOND)); -do - { - cc += GET(cc, 1); - count++; - } -while (*cc == OP_ALT); -SLJIT_ASSERT(*cc >= OP_KET && *cc <= OP_KETRPOS); -return count; -} - -/* Functions whose might need modification for all new supported opcodes: - next_opcode - check_opcode_types - set_private_data_ptrs - get_framesize - init_frame - get_recurse_data_length - copy_recurse_data - compile_matchingpath - compile_backtrackingpath -*/ - -static PCRE2_SPTR next_opcode(compiler_common *common, PCRE2_SPTR cc) -{ -SLJIT_UNUSED_ARG(common); -switch(*cc) - { - case OP_SOD: - case OP_SOM: - case OP_SET_SOM: - case OP_NOT_WORD_BOUNDARY: - case OP_WORD_BOUNDARY: - case OP_NOT_DIGIT: - case OP_DIGIT: - case OP_NOT_WHITESPACE: - case OP_WHITESPACE: - case OP_NOT_WORDCHAR: - case OP_WORDCHAR: - case OP_ANY: - case OP_ALLANY: - case OP_NOTPROP: - case OP_PROP: - case OP_ANYNL: - case OP_NOT_HSPACE: - case OP_HSPACE: - case OP_NOT_VSPACE: - case OP_VSPACE: - case OP_EXTUNI: - case OP_EODN: - case OP_EOD: - case OP_CIRC: - case OP_CIRCM: - case OP_DOLL: - case OP_DOLLM: - case OP_CRSTAR: - case OP_CRMINSTAR: - case OP_CRPLUS: - case OP_CRMINPLUS: - case OP_CRQUERY: - case OP_CRMINQUERY: - case OP_CRRANGE: - case OP_CRMINRANGE: - case OP_CRPOSSTAR: - case OP_CRPOSPLUS: - case OP_CRPOSQUERY: - case OP_CRPOSRANGE: - case OP_CLASS: - case OP_NCLASS: - case OP_REF: - case OP_REFI: - case OP_DNREF: - case OP_DNREFI: - case OP_RECURSE: - case OP_CALLOUT: - case OP_ALT: - case OP_KET: - case OP_KETRMAX: - case OP_KETRMIN: - case OP_KETRPOS: - case OP_REVERSE: - case OP_ASSERT: - case OP_ASSERT_NOT: - case OP_ASSERTBACK: - case OP_ASSERTBACK_NOT: - case OP_ASSERT_NA: - case OP_ASSERTBACK_NA: - case OP_ONCE: - case OP_SCRIPT_RUN: - case OP_BRA: - case OP_BRAPOS: - case OP_CBRA: - case OP_CBRAPOS: - case OP_COND: - case OP_SBRA: - case OP_SBRAPOS: - case OP_SCBRA: - case OP_SCBRAPOS: - case OP_SCOND: - case OP_CREF: - case OP_DNCREF: - case OP_RREF: - case OP_DNRREF: - case OP_FALSE: - case OP_TRUE: - case OP_BRAZERO: - case OP_BRAMINZERO: - case OP_BRAPOSZERO: - case OP_PRUNE: - case OP_SKIP: - case OP_THEN: - case OP_COMMIT: - case OP_FAIL: - case OP_ACCEPT: - case OP_ASSERT_ACCEPT: - case OP_CLOSE: - case OP_SKIPZERO: - return cc + PRIV(OP_lengths)[*cc]; - - case OP_CHAR: - case OP_CHARI: - case OP_NOT: - case OP_NOTI: - case OP_STAR: - case OP_MINSTAR: - case OP_PLUS: - case OP_MINPLUS: - case OP_QUERY: - case OP_MINQUERY: - case OP_UPTO: - case OP_MINUPTO: - case OP_EXACT: - case OP_POSSTAR: - case OP_POSPLUS: - case OP_POSQUERY: - case OP_POSUPTO: - case OP_STARI: - case OP_MINSTARI: - case OP_PLUSI: - case OP_MINPLUSI: - case OP_QUERYI: - case OP_MINQUERYI: - case OP_UPTOI: - case OP_MINUPTOI: - case OP_EXACTI: - case OP_POSSTARI: - case OP_POSPLUSI: - case OP_POSQUERYI: - case OP_POSUPTOI: - case OP_NOTSTAR: - case OP_NOTMINSTAR: - case OP_NOTPLUS: - case OP_NOTMINPLUS: - case OP_NOTQUERY: - case OP_NOTMINQUERY: - case OP_NOTUPTO: - case OP_NOTMINUPTO: - case OP_NOTEXACT: - case OP_NOTPOSSTAR: - case OP_NOTPOSPLUS: - case OP_NOTPOSQUERY: - case OP_NOTPOSUPTO: - case OP_NOTSTARI: - case OP_NOTMINSTARI: - case OP_NOTPLUSI: - case OP_NOTMINPLUSI: - case OP_NOTQUERYI: - case OP_NOTMINQUERYI: - case OP_NOTUPTOI: - case OP_NOTMINUPTOI: - case OP_NOTEXACTI: - case OP_NOTPOSSTARI: - case OP_NOTPOSPLUSI: - case OP_NOTPOSQUERYI: - case OP_NOTPOSUPTOI: - cc += PRIV(OP_lengths)[*cc]; -#ifdef SUPPORT_UNICODE - if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); -#endif - return cc; - - /* Special cases. */ - case OP_TYPESTAR: - case OP_TYPEMINSTAR: - case OP_TYPEPLUS: - case OP_TYPEMINPLUS: - case OP_TYPEQUERY: - case OP_TYPEMINQUERY: - case OP_TYPEUPTO: - case OP_TYPEMINUPTO: - case OP_TYPEEXACT: - case OP_TYPEPOSSTAR: - case OP_TYPEPOSPLUS: - case OP_TYPEPOSQUERY: - case OP_TYPEPOSUPTO: - return cc + PRIV(OP_lengths)[*cc] - 1; - - case OP_ANYBYTE: -#ifdef SUPPORT_UNICODE - if (common->utf) return NULL; -#endif - return cc + 1; - - case OP_CALLOUT_STR: - return cc + GET(cc, 1 + 2*LINK_SIZE); - -#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8 - case OP_XCLASS: - return cc + GET(cc, 1); -#endif - - case OP_MARK: - case OP_COMMIT_ARG: - case OP_PRUNE_ARG: - case OP_SKIP_ARG: - case OP_THEN_ARG: - return cc + 1 + 2 + cc[1]; - - default: - SLJIT_UNREACHABLE(); - return NULL; - } -} - -static BOOL check_opcode_types(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend) -{ -int count; -PCRE2_SPTR slot; -PCRE2_SPTR assert_back_end = cc - 1; -PCRE2_SPTR assert_na_end = cc - 1; - -/* Calculate important variables (like stack size) and checks whether all opcodes are supported. */ -while (cc < ccend) - { - switch(*cc) - { - case OP_SET_SOM: - common->has_set_som = TRUE; - common->might_be_empty = TRUE; - cc += 1; - break; - - case OP_REFI: -#ifdef SUPPORT_UNICODE - if (common->iref_ptr == 0) - { - common->iref_ptr = common->ovector_start; - common->ovector_start += 3 * sizeof(sljit_sw); - } -#endif /* SUPPORT_UNICODE */ - /* Fall through. */ - case OP_REF: - common->optimized_cbracket[GET2(cc, 1)] = 0; - cc += 1 + IMM2_SIZE; - break; - - case OP_ASSERT_NA: - case OP_ASSERTBACK_NA: - slot = bracketend(cc); - if (slot > assert_na_end) - assert_na_end = slot; - cc += 1 + LINK_SIZE; - break; - - case OP_CBRAPOS: - case OP_SCBRAPOS: - common->optimized_cbracket[GET2(cc, 1 + LINK_SIZE)] = 0; - cc += 1 + LINK_SIZE + IMM2_SIZE; - break; - - case OP_COND: - case OP_SCOND: - /* Only AUTO_CALLOUT can insert this opcode. We do - not intend to support this case. */ - if (cc[1 + LINK_SIZE] == OP_CALLOUT || cc[1 + LINK_SIZE] == OP_CALLOUT_STR) - return FALSE; - cc += 1 + LINK_SIZE; - break; - - case OP_CREF: - common->optimized_cbracket[GET2(cc, 1)] = 0; - cc += 1 + IMM2_SIZE; - break; - - case OP_DNREF: - case OP_DNREFI: - case OP_DNCREF: - count = GET2(cc, 1 + IMM2_SIZE); - slot = common->name_table + GET2(cc, 1) * common->name_entry_size; - while (count-- > 0) - { - common->optimized_cbracket[GET2(slot, 0)] = 0; - slot += common->name_entry_size; - } - cc += 1 + 2 * IMM2_SIZE; - break; - - case OP_RECURSE: - /* Set its value only once. */ - if (common->recursive_head_ptr == 0) - { - common->recursive_head_ptr = common->ovector_start; - common->ovector_start += sizeof(sljit_sw); - } - cc += 1 + LINK_SIZE; - break; - - case OP_CALLOUT: - case OP_CALLOUT_STR: - if (common->capture_last_ptr == 0) - { - common->capture_last_ptr = common->ovector_start; - common->ovector_start += sizeof(sljit_sw); - } - cc += (*cc == OP_CALLOUT) ? PRIV(OP_lengths)[OP_CALLOUT] : GET(cc, 1 + 2*LINK_SIZE); - break; - - case OP_ASSERTBACK: - slot = bracketend(cc); - if (slot > assert_back_end) - assert_back_end = slot; - cc += 1 + LINK_SIZE; - break; - - case OP_THEN_ARG: - common->has_then = TRUE; - common->control_head_ptr = 1; - /* Fall through. */ - - case OP_COMMIT_ARG: - case OP_PRUNE_ARG: - if (cc < assert_na_end) - return FALSE; - /* Fall through */ - case OP_MARK: - if (common->mark_ptr == 0) - { - common->mark_ptr = common->ovector_start; - common->ovector_start += sizeof(sljit_sw); - } - cc += 1 + 2 + cc[1]; - break; - - case OP_THEN: - common->has_then = TRUE; - common->control_head_ptr = 1; - cc += 1; - break; - - case OP_SKIP: - if (cc < assert_back_end) - common->has_skip_in_assert_back = TRUE; - if (cc < assert_na_end) - return FALSE; - cc += 1; - break; - - case OP_SKIP_ARG: - common->control_head_ptr = 1; - common->has_skip_arg = TRUE; - if (cc < assert_back_end) - common->has_skip_in_assert_back = TRUE; - if (cc < assert_na_end) - return FALSE; - cc += 1 + 2 + cc[1]; - break; - - case OP_PRUNE: - case OP_COMMIT: - case OP_ASSERT_ACCEPT: - if (cc < assert_na_end) - return FALSE; - cc++; - break; - - default: - cc = next_opcode(common, cc); - if (cc == NULL) - return FALSE; - break; - } - } -return TRUE; -} - -#define EARLY_FAIL_ENHANCE_MAX (1 + 3) - -/* -start: - 0 - skip / early fail allowed - 1 - only early fail with range allowed - >1 - (start - 1) early fail is processed - -return: current number of iterators enhanced with fast fail -*/ -static int detect_early_fail(compiler_common *common, PCRE2_SPTR cc, int *private_data_start, - sljit_s32 depth, int start, BOOL fast_forward_allowed) -{ -PCRE2_SPTR begin = cc; -PCRE2_SPTR next_alt; -PCRE2_SPTR end; -PCRE2_SPTR accelerated_start; -BOOL prev_fast_forward_allowed; -int result = 0; -int count; - -SLJIT_ASSERT(*cc == OP_ONCE || *cc == OP_BRA || *cc == OP_CBRA); -SLJIT_ASSERT(*cc != OP_CBRA || common->optimized_cbracket[GET2(cc, 1 + LINK_SIZE)] != 0); -SLJIT_ASSERT(start < EARLY_FAIL_ENHANCE_MAX); - -next_alt = cc + GET(cc, 1); -if (*next_alt == OP_ALT) - fast_forward_allowed = FALSE; - -do - { - count = start; - cc += 1 + LINK_SIZE + ((*cc == OP_CBRA) ? IMM2_SIZE : 0); - - while (TRUE) - { - accelerated_start = NULL; - - switch(*cc) - { - case OP_SOD: - case OP_SOM: - case OP_SET_SOM: - case OP_NOT_WORD_BOUNDARY: - case OP_WORD_BOUNDARY: - case OP_EODN: - case OP_EOD: - case OP_CIRC: - case OP_CIRCM: - case OP_DOLL: - case OP_DOLLM: - /* Zero width assertions. */ - cc++; - continue; - - case OP_NOT_DIGIT: - case OP_DIGIT: - case OP_NOT_WHITESPACE: - case OP_WHITESPACE: - case OP_NOT_WORDCHAR: - case OP_WORDCHAR: - case OP_ANY: - case OP_ALLANY: - case OP_ANYBYTE: - case OP_NOT_HSPACE: - case OP_HSPACE: - case OP_NOT_VSPACE: - case OP_VSPACE: - fast_forward_allowed = FALSE; - cc++; - continue; - - case OP_ANYNL: - case OP_EXTUNI: - fast_forward_allowed = FALSE; - if (count == 0) - count = 1; - cc++; - continue; - - case OP_NOTPROP: - case OP_PROP: - fast_forward_allowed = FALSE; - cc += 1 + 2; - continue; - - case OP_CHAR: - case OP_CHARI: - case OP_NOT: - case OP_NOTI: - fast_forward_allowed = FALSE; - cc += 2; -#ifdef SUPPORT_UNICODE - if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); -#endif - continue; - - case OP_TYPESTAR: - case OP_TYPEMINSTAR: - case OP_TYPEPLUS: - case OP_TYPEMINPLUS: - case OP_TYPEPOSSTAR: - case OP_TYPEPOSPLUS: - /* The type or prop opcode is skipped in the next iteration. */ - cc += 1; - - if (cc[0] != OP_ANYNL && cc[0] != OP_EXTUNI) - { - accelerated_start = cc - 1; - break; - } - - if (count == 0) - count = 1; - fast_forward_allowed = FALSE; - continue; - - case OP_TYPEUPTO: - case OP_TYPEMINUPTO: - case OP_TYPEEXACT: - case OP_TYPEPOSUPTO: - cc += IMM2_SIZE; - /* Fall through */ - - case OP_TYPEQUERY: - case OP_TYPEMINQUERY: - case OP_TYPEPOSQUERY: - /* The type or prop opcode is skipped in the next iteration. */ - fast_forward_allowed = FALSE; - if (count == 0) - count = 1; - cc += 1; - continue; - - case OP_STAR: - case OP_MINSTAR: - case OP_PLUS: - case OP_MINPLUS: - case OP_POSSTAR: - case OP_POSPLUS: - - case OP_STARI: - case OP_MINSTARI: - case OP_PLUSI: - case OP_MINPLUSI: - case OP_POSSTARI: - case OP_POSPLUSI: - - case OP_NOTSTAR: - case OP_NOTMINSTAR: - case OP_NOTPLUS: - case OP_NOTMINPLUS: - case OP_NOTPOSSTAR: - case OP_NOTPOSPLUS: - - case OP_NOTSTARI: - case OP_NOTMINSTARI: - case OP_NOTPLUSI: - case OP_NOTMINPLUSI: - case OP_NOTPOSSTARI: - case OP_NOTPOSPLUSI: - accelerated_start = cc; - cc += 2; -#ifdef SUPPORT_UNICODE - if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); -#endif - break; - - case OP_UPTO: - case OP_MINUPTO: - case OP_EXACT: - case OP_POSUPTO: - case OP_UPTOI: - case OP_MINUPTOI: - case OP_EXACTI: - case OP_POSUPTOI: - case OP_NOTUPTO: - case OP_NOTMINUPTO: - case OP_NOTEXACT: - case OP_NOTPOSUPTO: - case OP_NOTUPTOI: - case OP_NOTMINUPTOI: - case OP_NOTEXACTI: - case OP_NOTPOSUPTOI: - cc += IMM2_SIZE; - /* Fall through */ - - case OP_QUERY: - case OP_MINQUERY: - case OP_POSQUERY: - case OP_QUERYI: - case OP_MINQUERYI: - case OP_POSQUERYI: - case OP_NOTQUERY: - case OP_NOTMINQUERY: - case OP_NOTPOSQUERY: - case OP_NOTQUERYI: - case OP_NOTMINQUERYI: - case OP_NOTPOSQUERYI: - fast_forward_allowed = FALSE; - if (count == 0) - count = 1; - cc += 2; -#ifdef SUPPORT_UNICODE - if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); -#endif - continue; - - case OP_CLASS: - case OP_NCLASS: -#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8 - case OP_XCLASS: - accelerated_start = cc; - cc += ((*cc == OP_XCLASS) ? GET(cc, 1) : (unsigned int)(1 + (32 / sizeof(PCRE2_UCHAR)))); -#else - accelerated_start = cc; - cc += (1 + (32 / sizeof(PCRE2_UCHAR))); -#endif - - switch (*cc) - { - case OP_CRSTAR: - case OP_CRMINSTAR: - case OP_CRPLUS: - case OP_CRMINPLUS: - case OP_CRPOSSTAR: - case OP_CRPOSPLUS: - cc++; - break; - - case OP_CRRANGE: - case OP_CRMINRANGE: - case OP_CRPOSRANGE: - cc += 2 * IMM2_SIZE; - /* Fall through */ - case OP_CRQUERY: - case OP_CRMINQUERY: - case OP_CRPOSQUERY: - cc++; - if (count == 0) - count = 1; - /* Fall through */ - default: - accelerated_start = NULL; - fast_forward_allowed = FALSE; - continue; - } - break; - - case OP_ONCE: - case OP_BRA: - case OP_CBRA: - end = cc + GET(cc, 1); - - prev_fast_forward_allowed = fast_forward_allowed; - fast_forward_allowed = FALSE; - if (depth >= 4) - break; - - end = bracketend(cc) - (1 + LINK_SIZE); - if (*end != OP_KET || (*cc == OP_CBRA && common->optimized_cbracket[GET2(cc, 1 + LINK_SIZE)] == 0)) - break; - - count = detect_early_fail(common, cc, private_data_start, depth + 1, count, prev_fast_forward_allowed); - - if (PRIVATE_DATA(cc) != 0) - common->private_data_ptrs[begin - common->start] = 1; - - if (count < EARLY_FAIL_ENHANCE_MAX) - { - cc = end + (1 + LINK_SIZE); - continue; - } - break; - - case OP_KET: - SLJIT_ASSERT(PRIVATE_DATA(cc) == 0); - if (cc >= next_alt) - break; - cc += 1 + LINK_SIZE; - continue; - } - - if (accelerated_start != NULL) - { - if (count == 0) - { - count++; - - if (fast_forward_allowed) - { - common->fast_forward_bc_ptr = accelerated_start; - common->private_data_ptrs[(accelerated_start + 1) - common->start] = ((*private_data_start) << 3) | type_skip; - *private_data_start += sizeof(sljit_sw); - } - else - { - common->private_data_ptrs[(accelerated_start + 1) - common->start] = ((*private_data_start) << 3) | type_fail; - - if (common->early_fail_start_ptr == 0) - common->early_fail_start_ptr = *private_data_start; - - *private_data_start += sizeof(sljit_sw); - common->early_fail_end_ptr = *private_data_start; - - if (*private_data_start > SLJIT_MAX_LOCAL_SIZE) - return EARLY_FAIL_ENHANCE_MAX; - } - } - else - { - common->private_data_ptrs[(accelerated_start + 1) - common->start] = ((*private_data_start) << 3) | type_fail_range; - - if (common->early_fail_start_ptr == 0) - common->early_fail_start_ptr = *private_data_start; - - *private_data_start += 2 * sizeof(sljit_sw); - common->early_fail_end_ptr = *private_data_start; - - if (*private_data_start > SLJIT_MAX_LOCAL_SIZE) - return EARLY_FAIL_ENHANCE_MAX; - } - - /* Cannot be part of a repeat. */ - common->private_data_ptrs[begin - common->start] = 1; - count++; - - if (count < EARLY_FAIL_ENHANCE_MAX) - continue; - } - - break; - } - - if (*cc != OP_ALT && *cc != OP_KET) - result = EARLY_FAIL_ENHANCE_MAX; - else if (result < count) - result = count; - - cc = next_alt; - next_alt = cc + GET(cc, 1); - } -while (*cc == OP_ALT); - -return result; -} - -static int get_class_iterator_size(PCRE2_SPTR cc) -{ -sljit_u32 min; -sljit_u32 max; -switch(*cc) - { - case OP_CRSTAR: - case OP_CRPLUS: - return 2; - - case OP_CRMINSTAR: - case OP_CRMINPLUS: - case OP_CRQUERY: - case OP_CRMINQUERY: - return 1; - - case OP_CRRANGE: - case OP_CRMINRANGE: - min = GET2(cc, 1); - max = GET2(cc, 1 + IMM2_SIZE); - if (max == 0) - return (*cc == OP_CRRANGE) ? 2 : 1; - max -= min; - if (max > 2) - max = 2; - return max; - - default: - return 0; - } -} - -static BOOL detect_repeat(compiler_common *common, PCRE2_SPTR begin) -{ -PCRE2_SPTR end = bracketend(begin); -PCRE2_SPTR next; -PCRE2_SPTR next_end; -PCRE2_SPTR max_end; -PCRE2_UCHAR type; -sljit_sw length = end - begin; -sljit_s32 min, max, i; - -/* Detect fixed iterations first. */ -if (end[-(1 + LINK_SIZE)] != OP_KET || PRIVATE_DATA(begin) != 0) - return FALSE; - -/* /(?:AB){4,6}/ is currently converted to /(?:AB){3}(?AB){1,3}/ - * Skip the check of the second part. */ -if (PRIVATE_DATA(end - LINK_SIZE) != 0) - return TRUE; - -next = end; -min = 1; -while (1) - { - if (*next != *begin) - break; - next_end = bracketend(next); - if (next_end - next != length || memcmp(begin, next, IN_UCHARS(length)) != 0) - break; - next = next_end; - min++; - } - -if (min == 2) - return FALSE; - -max = 0; -max_end = next; -if (*next == OP_BRAZERO || *next == OP_BRAMINZERO) - { - type = *next; - while (1) - { - if (next[0] != type || next[1] != OP_BRA || next[2 + LINK_SIZE] != *begin) - break; - next_end = bracketend(next + 2 + LINK_SIZE); - if (next_end - next != (length + 2 + LINK_SIZE) || memcmp(begin, next + 2 + LINK_SIZE, IN_UCHARS(length)) != 0) - break; - next = next_end; - max++; - } - - if (next[0] == type && next[1] == *begin && max >= 1) - { - next_end = bracketend(next + 1); - if (next_end - next == (length + 1) && memcmp(begin, next + 1, IN_UCHARS(length)) == 0) - { - for (i = 0; i < max; i++, next_end += 1 + LINK_SIZE) - if (*next_end != OP_KET) - break; - - if (i == max) - { - common->private_data_ptrs[max_end - common->start - LINK_SIZE] = next_end - max_end; - common->private_data_ptrs[max_end - common->start - LINK_SIZE + 1] = (type == OP_BRAZERO) ? OP_UPTO : OP_MINUPTO; - /* +2 the original and the last. */ - common->private_data_ptrs[max_end - common->start - LINK_SIZE + 2] = max + 2; - if (min == 1) - return TRUE; - min--; - max_end -= (1 + LINK_SIZE) + GET(max_end, -LINK_SIZE); - } - } - } - } - -if (min >= 3) - { - common->private_data_ptrs[end - common->start - LINK_SIZE] = max_end - end; - common->private_data_ptrs[end - common->start - LINK_SIZE + 1] = OP_EXACT; - common->private_data_ptrs[end - common->start - LINK_SIZE + 2] = min; - return TRUE; - } - -return FALSE; -} - -#define CASE_ITERATOR_PRIVATE_DATA_1 \ - case OP_MINSTAR: \ - case OP_MINPLUS: \ - case OP_QUERY: \ - case OP_MINQUERY: \ - case OP_MINSTARI: \ - case OP_MINPLUSI: \ - case OP_QUERYI: \ - case OP_MINQUERYI: \ - case OP_NOTMINSTAR: \ - case OP_NOTMINPLUS: \ - case OP_NOTQUERY: \ - case OP_NOTMINQUERY: \ - case OP_NOTMINSTARI: \ - case OP_NOTMINPLUSI: \ - case OP_NOTQUERYI: \ - case OP_NOTMINQUERYI: - -#define CASE_ITERATOR_PRIVATE_DATA_2A \ - case OP_STAR: \ - case OP_PLUS: \ - case OP_STARI: \ - case OP_PLUSI: \ - case OP_NOTSTAR: \ - case OP_NOTPLUS: \ - case OP_NOTSTARI: \ - case OP_NOTPLUSI: - -#define CASE_ITERATOR_PRIVATE_DATA_2B \ - case OP_UPTO: \ - case OP_MINUPTO: \ - case OP_UPTOI: \ - case OP_MINUPTOI: \ - case OP_NOTUPTO: \ - case OP_NOTMINUPTO: \ - case OP_NOTUPTOI: \ - case OP_NOTMINUPTOI: - -#define CASE_ITERATOR_TYPE_PRIVATE_DATA_1 \ - case OP_TYPEMINSTAR: \ - case OP_TYPEMINPLUS: \ - case OP_TYPEQUERY: \ - case OP_TYPEMINQUERY: - -#define CASE_ITERATOR_TYPE_PRIVATE_DATA_2A \ - case OP_TYPESTAR: \ - case OP_TYPEPLUS: - -#define CASE_ITERATOR_TYPE_PRIVATE_DATA_2B \ - case OP_TYPEUPTO: \ - case OP_TYPEMINUPTO: - -static void set_private_data_ptrs(compiler_common *common, int *private_data_start, PCRE2_SPTR ccend) -{ -PCRE2_SPTR cc = common->start; -PCRE2_SPTR alternative; -PCRE2_SPTR end = NULL; -int private_data_ptr = *private_data_start; -int space, size, bracketlen; -BOOL repeat_check = TRUE; - -while (cc < ccend) - { - space = 0; - size = 0; - bracketlen = 0; - if (private_data_ptr > SLJIT_MAX_LOCAL_SIZE) - break; - - /* When the bracket is prefixed by a zero iteration, skip the repeat check (at this point). */ - if (repeat_check && (*cc == OP_ONCE || *cc == OP_BRA || *cc == OP_CBRA || *cc == OP_COND)) - { - if (detect_repeat(common, cc)) - { - /* These brackets are converted to repeats, so no global - based single character repeat is allowed. */ - if (cc >= end) - end = bracketend(cc); - } - } - repeat_check = TRUE; - - switch(*cc) - { - case OP_KET: - if (common->private_data_ptrs[cc + 1 - common->start] != 0) - { - common->private_data_ptrs[cc - common->start] = private_data_ptr; - private_data_ptr += sizeof(sljit_sw); - cc += common->private_data_ptrs[cc + 1 - common->start]; - } - cc += 1 + LINK_SIZE; - break; - - case OP_ASSERT: - case OP_ASSERT_NOT: - case OP_ASSERTBACK: - case OP_ASSERTBACK_NOT: - case OP_ASSERT_NA: - case OP_ASSERTBACK_NA: - case OP_ONCE: - case OP_SCRIPT_RUN: - case OP_BRAPOS: - case OP_SBRA: - case OP_SBRAPOS: - case OP_SCOND: - common->private_data_ptrs[cc - common->start] = private_data_ptr; - private_data_ptr += sizeof(sljit_sw); - bracketlen = 1 + LINK_SIZE; - break; - - case OP_CBRAPOS: - case OP_SCBRAPOS: - common->private_data_ptrs[cc - common->start] = private_data_ptr; - private_data_ptr += sizeof(sljit_sw); - bracketlen = 1 + LINK_SIZE + IMM2_SIZE; - break; - - case OP_COND: - /* Might be a hidden SCOND. */ - common->private_data_ptrs[cc - common->start] = 0; - alternative = cc + GET(cc, 1); - if (*alternative == OP_KETRMAX || *alternative == OP_KETRMIN) - { - common->private_data_ptrs[cc - common->start] = private_data_ptr; - private_data_ptr += sizeof(sljit_sw); - } - bracketlen = 1 + LINK_SIZE; - break; - - case OP_BRA: - bracketlen = 1 + LINK_SIZE; - break; - - case OP_CBRA: - case OP_SCBRA: - bracketlen = 1 + LINK_SIZE + IMM2_SIZE; - break; - - case OP_BRAZERO: - case OP_BRAMINZERO: - case OP_BRAPOSZERO: - size = 1; - repeat_check = FALSE; - break; - - CASE_ITERATOR_PRIVATE_DATA_1 - size = -2; - space = 1; - break; - - CASE_ITERATOR_PRIVATE_DATA_2A - size = -2; - space = 2; - break; - - CASE_ITERATOR_PRIVATE_DATA_2B - size = -(2 + IMM2_SIZE); - space = 2; - break; - - CASE_ITERATOR_TYPE_PRIVATE_DATA_1 - size = 1; - space = 1; - break; - - CASE_ITERATOR_TYPE_PRIVATE_DATA_2A - size = 1; - if (cc[1] != OP_ANYNL && cc[1] != OP_EXTUNI) - space = 2; - break; - - case OP_TYPEUPTO: - size = 1 + IMM2_SIZE; - if (cc[1 + IMM2_SIZE] != OP_ANYNL && cc[1 + IMM2_SIZE] != OP_EXTUNI) - space = 2; - break; - - case OP_TYPEMINUPTO: - size = 1 + IMM2_SIZE; - space = 2; - break; - - case OP_CLASS: - case OP_NCLASS: - size = 1 + 32 / sizeof(PCRE2_UCHAR); - space = get_class_iterator_size(cc + size); - break; - -#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8 - case OP_XCLASS: - size = GET(cc, 1); - space = get_class_iterator_size(cc + size); - break; -#endif - - default: - cc = next_opcode(common, cc); - SLJIT_ASSERT(cc != NULL); - break; - } - - /* Character iterators, which are not inside a repeated bracket, - gets a private slot instead of allocating it on the stack. */ - if (space > 0 && cc >= end) - { - common->private_data_ptrs[cc - common->start] = private_data_ptr; - private_data_ptr += sizeof(sljit_sw) * space; - } - - if (size != 0) - { - if (size < 0) - { - cc += -size; -#ifdef SUPPORT_UNICODE - if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); -#endif - } - else - cc += size; - } - - if (bracketlen > 0) - { - if (cc >= end) - { - end = bracketend(cc); - if (end[-1 - LINK_SIZE] == OP_KET) - end = NULL; - } - cc += bracketlen; - } - } -*private_data_start = private_data_ptr; -} - -/* Returns with a frame_types (always < 0) if no need for frame. */ -static int get_framesize(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend, BOOL recursive, BOOL *needs_control_head) -{ -int length = 0; -int possessive = 0; -BOOL stack_restore = FALSE; -BOOL setsom_found = recursive; -BOOL setmark_found = recursive; -/* The last capture is a local variable even for recursions. */ -BOOL capture_last_found = FALSE; - -#if defined DEBUG_FORCE_CONTROL_HEAD && DEBUG_FORCE_CONTROL_HEAD -SLJIT_ASSERT(common->control_head_ptr != 0); -*needs_control_head = TRUE; -#else -*needs_control_head = FALSE; -#endif - -if (ccend == NULL) - { - ccend = bracketend(cc) - (1 + LINK_SIZE); - if (!recursive && (*cc == OP_CBRAPOS || *cc == OP_SCBRAPOS)) - { - possessive = length = (common->capture_last_ptr != 0) ? 5 : 3; - /* This is correct regardless of common->capture_last_ptr. */ - capture_last_found = TRUE; - } - cc = next_opcode(common, cc); - } - -SLJIT_ASSERT(cc != NULL); -while (cc < ccend) - switch(*cc) - { - case OP_SET_SOM: - SLJIT_ASSERT(common->has_set_som); - stack_restore = TRUE; - if (!setsom_found) - { - length += 2; - setsom_found = TRUE; - } - cc += 1; - break; - - case OP_MARK: - case OP_COMMIT_ARG: - case OP_PRUNE_ARG: - case OP_THEN_ARG: - SLJIT_ASSERT(common->mark_ptr != 0); - stack_restore = TRUE; - if (!setmark_found) - { - length += 2; - setmark_found = TRUE; - } - if (common->control_head_ptr != 0) - *needs_control_head = TRUE; - cc += 1 + 2 + cc[1]; - break; - - case OP_RECURSE: - stack_restore = TRUE; - if (common->has_set_som && !setsom_found) - { - length += 2; - setsom_found = TRUE; - } - if (common->mark_ptr != 0 && !setmark_found) - { - length += 2; - setmark_found = TRUE; - } - if (common->capture_last_ptr != 0 && !capture_last_found) - { - length += 2; - capture_last_found = TRUE; - } - cc += 1 + LINK_SIZE; - break; - - case OP_CBRA: - case OP_CBRAPOS: - case OP_SCBRA: - case OP_SCBRAPOS: - stack_restore = TRUE; - if (common->capture_last_ptr != 0 && !capture_last_found) - { - length += 2; - capture_last_found = TRUE; - } - length += 3; - cc += 1 + LINK_SIZE + IMM2_SIZE; - break; - - case OP_THEN: - stack_restore = TRUE; - if (common->control_head_ptr != 0) - *needs_control_head = TRUE; - cc ++; - break; - - default: - stack_restore = TRUE; - /* Fall through. */ - - case OP_NOT_WORD_BOUNDARY: - case OP_WORD_BOUNDARY: - case OP_NOT_DIGIT: - case OP_DIGIT: - case OP_NOT_WHITESPACE: - case OP_WHITESPACE: - case OP_NOT_WORDCHAR: - case OP_WORDCHAR: - case OP_ANY: - case OP_ALLANY: - case OP_ANYBYTE: - case OP_NOTPROP: - case OP_PROP: - case OP_ANYNL: - case OP_NOT_HSPACE: - case OP_HSPACE: - case OP_NOT_VSPACE: - case OP_VSPACE: - case OP_EXTUNI: - case OP_EODN: - case OP_EOD: - case OP_CIRC: - case OP_CIRCM: - case OP_DOLL: - case OP_DOLLM: - case OP_CHAR: - case OP_CHARI: - case OP_NOT: - case OP_NOTI: - - case OP_EXACT: - case OP_POSSTAR: - case OP_POSPLUS: - case OP_POSQUERY: - case OP_POSUPTO: - - case OP_EXACTI: - case OP_POSSTARI: - case OP_POSPLUSI: - case OP_POSQUERYI: - case OP_POSUPTOI: - - case OP_NOTEXACT: - case OP_NOTPOSSTAR: - case OP_NOTPOSPLUS: - case OP_NOTPOSQUERY: - case OP_NOTPOSUPTO: - - case OP_NOTEXACTI: - case OP_NOTPOSSTARI: - case OP_NOTPOSPLUSI: - case OP_NOTPOSQUERYI: - case OP_NOTPOSUPTOI: - - case OP_TYPEEXACT: - case OP_TYPEPOSSTAR: - case OP_TYPEPOSPLUS: - case OP_TYPEPOSQUERY: - case OP_TYPEPOSUPTO: - - case OP_CLASS: - case OP_NCLASS: - case OP_XCLASS: - - case OP_CALLOUT: - case OP_CALLOUT_STR: - - cc = next_opcode(common, cc); - SLJIT_ASSERT(cc != NULL); - break; - } - -/* Possessive quantifiers can use a special case. */ -if (SLJIT_UNLIKELY(possessive == length)) - return stack_restore ? no_frame : no_stack; - -if (length > 0) - return length + 1; -return stack_restore ? no_frame : no_stack; -} - -static void init_frame(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend, int stackpos, int stacktop) -{ -DEFINE_COMPILER; -BOOL setsom_found = FALSE; -BOOL setmark_found = FALSE; -/* The last capture is a local variable even for recursions. */ -BOOL capture_last_found = FALSE; -int offset; - -/* >= 1 + shortest item size (2) */ -SLJIT_UNUSED_ARG(stacktop); -SLJIT_ASSERT(stackpos >= stacktop + 2); - -stackpos = STACK(stackpos); -if (ccend == NULL) - { - ccend = bracketend(cc) - (1 + LINK_SIZE); - if (*cc != OP_CBRAPOS && *cc != OP_SCBRAPOS) - cc = next_opcode(common, cc); - } - -SLJIT_ASSERT(cc != NULL); -while (cc < ccend) - switch(*cc) - { - case OP_SET_SOM: - SLJIT_ASSERT(common->has_set_som); - if (!setsom_found) - { - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(0)); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, -OVECTOR(0)); - stackpos -= SSIZE_OF(sw); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0); - stackpos -= SSIZE_OF(sw); - setsom_found = TRUE; - } - cc += 1; - break; - - case OP_MARK: - case OP_COMMIT_ARG: - case OP_PRUNE_ARG: - case OP_THEN_ARG: - SLJIT_ASSERT(common->mark_ptr != 0); - if (!setmark_found) - { - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->mark_ptr); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, -common->mark_ptr); - stackpos -= SSIZE_OF(sw); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0); - stackpos -= SSIZE_OF(sw); - setmark_found = TRUE; - } - cc += 1 + 2 + cc[1]; - break; - - case OP_RECURSE: - if (common->has_set_som && !setsom_found) - { - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(0)); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, -OVECTOR(0)); - stackpos -= SSIZE_OF(sw); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0); - stackpos -= SSIZE_OF(sw); - setsom_found = TRUE; - } - if (common->mark_ptr != 0 && !setmark_found) - { - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->mark_ptr); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, -common->mark_ptr); - stackpos -= SSIZE_OF(sw); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0); - stackpos -= SSIZE_OF(sw); - setmark_found = TRUE; - } - if (common->capture_last_ptr != 0 && !capture_last_found) - { - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, -common->capture_last_ptr); - stackpos -= SSIZE_OF(sw); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0); - stackpos -= SSIZE_OF(sw); - capture_last_found = TRUE; - } - cc += 1 + LINK_SIZE; - break; - - case OP_CBRA: - case OP_CBRAPOS: - case OP_SCBRA: - case OP_SCBRAPOS: - if (common->capture_last_ptr != 0 && !capture_last_found) - { - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, -common->capture_last_ptr); - stackpos -= SSIZE_OF(sw); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0); - stackpos -= SSIZE_OF(sw); - capture_last_found = TRUE; - } - offset = (GET2(cc, 1 + LINK_SIZE)) << 1; - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, OVECTOR(offset)); - stackpos -= SSIZE_OF(sw); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset)); - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1)); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0); - stackpos -= SSIZE_OF(sw); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP2, 0); - stackpos -= SSIZE_OF(sw); - - cc += 1 + LINK_SIZE + IMM2_SIZE; - break; - - default: - cc = next_opcode(common, cc); - SLJIT_ASSERT(cc != NULL); - break; - } - -OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, 0); -SLJIT_ASSERT(stackpos == STACK(stacktop)); -} - -#define RECURSE_TMP_REG_COUNT 3 - -typedef struct delayed_mem_copy_status { - struct sljit_compiler *compiler; - int store_bases[RECURSE_TMP_REG_COUNT]; - int store_offsets[RECURSE_TMP_REG_COUNT]; - int tmp_regs[RECURSE_TMP_REG_COUNT]; - int saved_tmp_regs[RECURSE_TMP_REG_COUNT]; - int next_tmp_reg; -} delayed_mem_copy_status; - -static void delayed_mem_copy_init(delayed_mem_copy_status *status, compiler_common *common) -{ -int i; - -for (i = 0; i < RECURSE_TMP_REG_COUNT; i++) - { - SLJIT_ASSERT(status->tmp_regs[i] >= 0); - SLJIT_ASSERT(sljit_get_register_index(status->saved_tmp_regs[i]) < 0 || status->tmp_regs[i] == status->saved_tmp_regs[i]); - - status->store_bases[i] = -1; - } -status->next_tmp_reg = 0; -status->compiler = common->compiler; -} - -static void delayed_mem_copy_move(delayed_mem_copy_status *status, int load_base, sljit_sw load_offset, - int store_base, sljit_sw store_offset) -{ -struct sljit_compiler *compiler = status->compiler; -int next_tmp_reg = status->next_tmp_reg; -int tmp_reg = status->tmp_regs[next_tmp_reg]; - -SLJIT_ASSERT(load_base > 0 && store_base > 0); - -if (status->store_bases[next_tmp_reg] == -1) - { - /* Preserve virtual registers. */ - if (sljit_get_register_index(status->saved_tmp_regs[next_tmp_reg]) < 0) - OP1(SLJIT_MOV, status->saved_tmp_regs[next_tmp_reg], 0, tmp_reg, 0); - } -else - OP1(SLJIT_MOV, SLJIT_MEM1(status->store_bases[next_tmp_reg]), status->store_offsets[next_tmp_reg], tmp_reg, 0); - -OP1(SLJIT_MOV, tmp_reg, 0, SLJIT_MEM1(load_base), load_offset); -status->store_bases[next_tmp_reg] = store_base; -status->store_offsets[next_tmp_reg] = store_offset; - -status->next_tmp_reg = (next_tmp_reg + 1) % RECURSE_TMP_REG_COUNT; -} - -static void delayed_mem_copy_finish(delayed_mem_copy_status *status) -{ -struct sljit_compiler *compiler = status->compiler; -int next_tmp_reg = status->next_tmp_reg; -int tmp_reg, saved_tmp_reg, i; - -for (i = 0; i < RECURSE_TMP_REG_COUNT; i++) - { - if (status->store_bases[next_tmp_reg] != -1) - { - tmp_reg = status->tmp_regs[next_tmp_reg]; - saved_tmp_reg = status->saved_tmp_regs[next_tmp_reg]; - - OP1(SLJIT_MOV, SLJIT_MEM1(status->store_bases[next_tmp_reg]), status->store_offsets[next_tmp_reg], tmp_reg, 0); - - /* Restore virtual registers. */ - if (sljit_get_register_index(saved_tmp_reg) < 0) - OP1(SLJIT_MOV, tmp_reg, 0, saved_tmp_reg, 0); - } - - next_tmp_reg = (next_tmp_reg + 1) % RECURSE_TMP_REG_COUNT; - } -} - -#undef RECURSE_TMP_REG_COUNT - -static BOOL recurse_check_bit(compiler_common *common, sljit_sw bit_index) -{ -uint8_t *byte; -uint8_t mask; - -SLJIT_ASSERT((bit_index & (sizeof(sljit_sw) - 1)) == 0); - -bit_index >>= SLJIT_WORD_SHIFT; - -SLJIT_ASSERT((bit_index >> 3) < common->recurse_bitset_size); - -mask = 1 << (bit_index & 0x7); -byte = common->recurse_bitset + (bit_index >> 3); - -if (*byte & mask) - return FALSE; - -*byte |= mask; -return TRUE; -} - -enum get_recurse_flags { - recurse_flag_quit_found = (1 << 0), - recurse_flag_accept_found = (1 << 1), - recurse_flag_setsom_found = (1 << 2), - recurse_flag_setmark_found = (1 << 3), - recurse_flag_control_head_found = (1 << 4), -}; - -static int get_recurse_data_length(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend, uint32_t *result_flags) -{ -int length = 1; -int size, offset; -PCRE2_SPTR alternative; -uint32_t recurse_flags = 0; - -memset(common->recurse_bitset, 0, common->recurse_bitset_size); - -#if defined DEBUG_FORCE_CONTROL_HEAD && DEBUG_FORCE_CONTROL_HEAD -SLJIT_ASSERT(common->control_head_ptr != 0); -recurse_flags |= recurse_flag_control_head_found; -#endif - -/* Calculate the sum of the private machine words. */ -while (cc < ccend) - { - size = 0; - switch(*cc) - { - case OP_SET_SOM: - SLJIT_ASSERT(common->has_set_som); - recurse_flags |= recurse_flag_setsom_found; - cc += 1; - break; - - case OP_RECURSE: - if (common->has_set_som) - recurse_flags |= recurse_flag_setsom_found; - if (common->mark_ptr != 0) - recurse_flags |= recurse_flag_setmark_found; - if (common->capture_last_ptr != 0 && recurse_check_bit(common, common->capture_last_ptr)) - length++; - cc += 1 + LINK_SIZE; - break; - - case OP_KET: - offset = PRIVATE_DATA(cc); - if (offset != 0) - { - if (recurse_check_bit(common, offset)) - length++; - SLJIT_ASSERT(PRIVATE_DATA(cc + 1) != 0); - cc += PRIVATE_DATA(cc + 1); - } - cc += 1 + LINK_SIZE; - break; - - case OP_ASSERT: - case OP_ASSERT_NOT: - case OP_ASSERTBACK: - case OP_ASSERTBACK_NOT: - case OP_ASSERT_NA: - case OP_ASSERTBACK_NA: - case OP_ONCE: - case OP_SCRIPT_RUN: - case OP_BRAPOS: - case OP_SBRA: - case OP_SBRAPOS: - case OP_SCOND: - SLJIT_ASSERT(PRIVATE_DATA(cc) != 0); - if (recurse_check_bit(common, PRIVATE_DATA(cc))) - length++; - cc += 1 + LINK_SIZE; - break; - - case OP_CBRA: - case OP_SCBRA: - offset = GET2(cc, 1 + LINK_SIZE); - if (recurse_check_bit(common, OVECTOR(offset << 1))) - { - SLJIT_ASSERT(recurse_check_bit(common, OVECTOR((offset << 1) + 1))); - length += 2; - } - if (common->optimized_cbracket[offset] == 0 && recurse_check_bit(common, OVECTOR_PRIV(offset))) - length++; - if (common->capture_last_ptr != 0 && recurse_check_bit(common, common->capture_last_ptr)) - length++; - cc += 1 + LINK_SIZE + IMM2_SIZE; - break; - - case OP_CBRAPOS: - case OP_SCBRAPOS: - offset = GET2(cc, 1 + LINK_SIZE); - if (recurse_check_bit(common, OVECTOR(offset << 1))) - { - SLJIT_ASSERT(recurse_check_bit(common, OVECTOR((offset << 1) + 1))); - length += 2; - } - if (recurse_check_bit(common, OVECTOR_PRIV(offset))) - length++; - if (recurse_check_bit(common, PRIVATE_DATA(cc))) - length++; - if (common->capture_last_ptr != 0 && recurse_check_bit(common, common->capture_last_ptr)) - length++; - cc += 1 + LINK_SIZE + IMM2_SIZE; - break; - - case OP_COND: - /* Might be a hidden SCOND. */ - alternative = cc + GET(cc, 1); - if ((*alternative == OP_KETRMAX || *alternative == OP_KETRMIN) && recurse_check_bit(common, PRIVATE_DATA(cc))) - length++; - cc += 1 + LINK_SIZE; - break; - - CASE_ITERATOR_PRIVATE_DATA_1 - offset = PRIVATE_DATA(cc); - if (offset != 0 && recurse_check_bit(common, offset)) - length++; - cc += 2; -#ifdef SUPPORT_UNICODE - if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); -#endif - break; - - CASE_ITERATOR_PRIVATE_DATA_2A - offset = PRIVATE_DATA(cc); - if (offset != 0 && recurse_check_bit(common, offset)) - { - SLJIT_ASSERT(recurse_check_bit(common, offset + sizeof(sljit_sw))); - length += 2; - } - cc += 2; -#ifdef SUPPORT_UNICODE - if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); -#endif - break; - - CASE_ITERATOR_PRIVATE_DATA_2B - offset = PRIVATE_DATA(cc); - if (offset != 0 && recurse_check_bit(common, offset)) - { - SLJIT_ASSERT(recurse_check_bit(common, offset + sizeof(sljit_sw))); - length += 2; - } - cc += 2 + IMM2_SIZE; -#ifdef SUPPORT_UNICODE - if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); -#endif - break; - - CASE_ITERATOR_TYPE_PRIVATE_DATA_1 - offset = PRIVATE_DATA(cc); - if (offset != 0 && recurse_check_bit(common, offset)) - length++; - cc += 1; - break; - - CASE_ITERATOR_TYPE_PRIVATE_DATA_2A - offset = PRIVATE_DATA(cc); - if (offset != 0 && recurse_check_bit(common, offset)) - { - SLJIT_ASSERT(recurse_check_bit(common, offset + sizeof(sljit_sw))); - length += 2; - } - cc += 1; - break; - - CASE_ITERATOR_TYPE_PRIVATE_DATA_2B - offset = PRIVATE_DATA(cc); - if (offset != 0 && recurse_check_bit(common, offset)) - { - SLJIT_ASSERT(recurse_check_bit(common, offset + sizeof(sljit_sw))); - length += 2; - } - cc += 1 + IMM2_SIZE; - break; - - case OP_CLASS: - case OP_NCLASS: -#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8 - case OP_XCLASS: - size = (*cc == OP_XCLASS) ? GET(cc, 1) : 1 + 32 / (int)sizeof(PCRE2_UCHAR); -#else - size = 1 + 32 / (int)sizeof(PCRE2_UCHAR); -#endif - - offset = PRIVATE_DATA(cc); - if (offset != 0 && recurse_check_bit(common, offset)) - length += get_class_iterator_size(cc + size); - cc += size; - break; - - case OP_MARK: - case OP_COMMIT_ARG: - case OP_PRUNE_ARG: - case OP_THEN_ARG: - SLJIT_ASSERT(common->mark_ptr != 0); - recurse_flags |= recurse_flag_setmark_found; - if (common->control_head_ptr != 0) - recurse_flags |= recurse_flag_control_head_found; - if (*cc != OP_MARK) - recurse_flags |= recurse_flag_quit_found; - - cc += 1 + 2 + cc[1]; - break; - - case OP_PRUNE: - case OP_SKIP: - case OP_COMMIT: - recurse_flags |= recurse_flag_quit_found; - cc++; - break; - - case OP_SKIP_ARG: - recurse_flags |= recurse_flag_quit_found; - cc += 1 + 2 + cc[1]; - break; - - case OP_THEN: - SLJIT_ASSERT(common->control_head_ptr != 0); - recurse_flags |= recurse_flag_quit_found | recurse_flag_control_head_found; - cc++; - break; - - case OP_ACCEPT: - case OP_ASSERT_ACCEPT: - recurse_flags |= recurse_flag_accept_found; - cc++; - break; - - default: - cc = next_opcode(common, cc); - SLJIT_ASSERT(cc != NULL); - break; - } - } -SLJIT_ASSERT(cc == ccend); - -if (recurse_flags & recurse_flag_control_head_found) - length++; -if (recurse_flags & recurse_flag_quit_found) - { - if (recurse_flags & recurse_flag_setsom_found) - length++; - if (recurse_flags & recurse_flag_setmark_found) - length++; - } - -*result_flags = recurse_flags; -return length; -} - -enum copy_recurse_data_types { - recurse_copy_from_global, - recurse_copy_private_to_global, - recurse_copy_shared_to_global, - recurse_copy_kept_shared_to_global, - recurse_swap_global -}; - -static void copy_recurse_data(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend, - int type, int stackptr, int stacktop, uint32_t recurse_flags) -{ -delayed_mem_copy_status status; -PCRE2_SPTR alternative; -sljit_sw private_srcw[2]; -sljit_sw shared_srcw[3]; -sljit_sw kept_shared_srcw[2]; -int private_count, shared_count, kept_shared_count; -int from_sp, base_reg, offset, i; - -memset(common->recurse_bitset, 0, common->recurse_bitset_size); - -#if defined DEBUG_FORCE_CONTROL_HEAD && DEBUG_FORCE_CONTROL_HEAD -SLJIT_ASSERT(common->control_head_ptr != 0); -recurse_check_bit(common, common->control_head_ptr); -#endif - -switch (type) - { - case recurse_copy_from_global: - from_sp = TRUE; - base_reg = STACK_TOP; - break; - - case recurse_copy_private_to_global: - case recurse_copy_shared_to_global: - case recurse_copy_kept_shared_to_global: - from_sp = FALSE; - base_reg = STACK_TOP; - break; - - default: - SLJIT_ASSERT(type == recurse_swap_global); - from_sp = FALSE; - base_reg = TMP2; - break; - } - -stackptr = STACK(stackptr); -stacktop = STACK(stacktop); - -status.tmp_regs[0] = TMP1; -status.saved_tmp_regs[0] = TMP1; - -if (base_reg != TMP2) - { - status.tmp_regs[1] = TMP2; - status.saved_tmp_regs[1] = TMP2; - } -else - { - status.saved_tmp_regs[1] = RETURN_ADDR; - if (HAS_VIRTUAL_REGISTERS) - status.tmp_regs[1] = STR_PTR; - else - status.tmp_regs[1] = RETURN_ADDR; - } - -status.saved_tmp_regs[2] = TMP3; -if (HAS_VIRTUAL_REGISTERS) - status.tmp_regs[2] = STR_END; -else - status.tmp_regs[2] = TMP3; - -delayed_mem_copy_init(&status, common); - -if (type != recurse_copy_shared_to_global && type != recurse_copy_kept_shared_to_global) - { - SLJIT_ASSERT(type == recurse_copy_from_global || type == recurse_copy_private_to_global || type == recurse_swap_global); - - if (!from_sp) - delayed_mem_copy_move(&status, base_reg, stackptr, SLJIT_SP, common->recursive_head_ptr); - - if (from_sp || type == recurse_swap_global) - delayed_mem_copy_move(&status, SLJIT_SP, common->recursive_head_ptr, base_reg, stackptr); - } - -stackptr += sizeof(sljit_sw); - -#if defined DEBUG_FORCE_CONTROL_HEAD && DEBUG_FORCE_CONTROL_HEAD -if (type != recurse_copy_shared_to_global) - { - if (!from_sp) - delayed_mem_copy_move(&status, base_reg, stackptr, SLJIT_SP, common->control_head_ptr); - - if (from_sp || type == recurse_swap_global) - delayed_mem_copy_move(&status, SLJIT_SP, common->control_head_ptr, base_reg, stackptr); - } - -stackptr += sizeof(sljit_sw); -#endif - -while (cc < ccend) - { - private_count = 0; - shared_count = 0; - kept_shared_count = 0; - - switch(*cc) - { - case OP_SET_SOM: - SLJIT_ASSERT(common->has_set_som); - if ((recurse_flags & recurse_flag_quit_found) && recurse_check_bit(common, OVECTOR(0))) - { - kept_shared_srcw[0] = OVECTOR(0); - kept_shared_count = 1; - } - cc += 1; - break; - - case OP_RECURSE: - if (recurse_flags & recurse_flag_quit_found) - { - if (common->has_set_som && recurse_check_bit(common, OVECTOR(0))) - { - kept_shared_srcw[0] = OVECTOR(0); - kept_shared_count = 1; - } - if (common->mark_ptr != 0 && recurse_check_bit(common, common->mark_ptr)) - { - kept_shared_srcw[kept_shared_count] = common->mark_ptr; - kept_shared_count++; - } - } - if (common->capture_last_ptr != 0 && recurse_check_bit(common, common->capture_last_ptr)) - { - shared_srcw[0] = common->capture_last_ptr; - shared_count = 1; - } - cc += 1 + LINK_SIZE; - break; - - case OP_KET: - private_srcw[0] = PRIVATE_DATA(cc); - if (private_srcw[0] != 0) - { - if (recurse_check_bit(common, private_srcw[0])) - private_count = 1; - SLJIT_ASSERT(PRIVATE_DATA(cc + 1) != 0); - cc += PRIVATE_DATA(cc + 1); - } - cc += 1 + LINK_SIZE; - break; - - case OP_ASSERT: - case OP_ASSERT_NOT: - case OP_ASSERTBACK: - case OP_ASSERTBACK_NOT: - case OP_ASSERT_NA: - case OP_ASSERTBACK_NA: - case OP_ONCE: - case OP_SCRIPT_RUN: - case OP_BRAPOS: - case OP_SBRA: - case OP_SBRAPOS: - case OP_SCOND: - private_srcw[0] = PRIVATE_DATA(cc); - if (recurse_check_bit(common, private_srcw[0])) - private_count = 1; - cc += 1 + LINK_SIZE; - break; - - case OP_CBRA: - case OP_SCBRA: - offset = GET2(cc, 1 + LINK_SIZE); - shared_srcw[0] = OVECTOR(offset << 1); - if (recurse_check_bit(common, shared_srcw[0])) - { - shared_srcw[1] = shared_srcw[0] + sizeof(sljit_sw); - SLJIT_ASSERT(recurse_check_bit(common, shared_srcw[1])); - shared_count = 2; - } - - if (common->capture_last_ptr != 0 && recurse_check_bit(common, common->capture_last_ptr)) - { - shared_srcw[shared_count] = common->capture_last_ptr; - shared_count++; - } - - if (common->optimized_cbracket[offset] == 0) - { - private_srcw[0] = OVECTOR_PRIV(offset); - if (recurse_check_bit(common, private_srcw[0])) - private_count = 1; - } - - cc += 1 + LINK_SIZE + IMM2_SIZE; - break; - - case OP_CBRAPOS: - case OP_SCBRAPOS: - offset = GET2(cc, 1 + LINK_SIZE); - shared_srcw[0] = OVECTOR(offset << 1); - if (recurse_check_bit(common, shared_srcw[0])) - { - shared_srcw[1] = shared_srcw[0] + sizeof(sljit_sw); - SLJIT_ASSERT(recurse_check_bit(common, shared_srcw[1])); - shared_count = 2; - } - - if (common->capture_last_ptr != 0 && recurse_check_bit(common, common->capture_last_ptr)) - { - shared_srcw[shared_count] = common->capture_last_ptr; - shared_count++; - } - - private_srcw[0] = PRIVATE_DATA(cc); - if (recurse_check_bit(common, private_srcw[0])) - private_count = 1; - - offset = OVECTOR_PRIV(offset); - if (recurse_check_bit(common, offset)) - { - private_srcw[private_count] = offset; - private_count++; - } - cc += 1 + LINK_SIZE + IMM2_SIZE; - break; - - case OP_COND: - /* Might be a hidden SCOND. */ - alternative = cc + GET(cc, 1); - if (*alternative == OP_KETRMAX || *alternative == OP_KETRMIN) - { - private_srcw[0] = PRIVATE_DATA(cc); - if (recurse_check_bit(common, private_srcw[0])) - private_count = 1; - } - cc += 1 + LINK_SIZE; - break; - - CASE_ITERATOR_PRIVATE_DATA_1 - private_srcw[0] = PRIVATE_DATA(cc); - if (private_srcw[0] != 0 && recurse_check_bit(common, private_srcw[0])) - private_count = 1; - cc += 2; -#ifdef SUPPORT_UNICODE - if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); -#endif - break; - - CASE_ITERATOR_PRIVATE_DATA_2A - private_srcw[0] = PRIVATE_DATA(cc); - if (private_srcw[0] != 0 && recurse_check_bit(common, private_srcw[0])) - { - private_count = 2; - private_srcw[1] = private_srcw[0] + sizeof(sljit_sw); - SLJIT_ASSERT(recurse_check_bit(common, private_srcw[1])); - } - cc += 2; -#ifdef SUPPORT_UNICODE - if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); -#endif - break; - - CASE_ITERATOR_PRIVATE_DATA_2B - private_srcw[0] = PRIVATE_DATA(cc); - if (private_srcw[0] != 0 && recurse_check_bit(common, private_srcw[0])) - { - private_count = 2; - private_srcw[1] = private_srcw[0] + sizeof(sljit_sw); - SLJIT_ASSERT(recurse_check_bit(common, private_srcw[1])); - } - cc += 2 + IMM2_SIZE; -#ifdef SUPPORT_UNICODE - if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); -#endif - break; - - CASE_ITERATOR_TYPE_PRIVATE_DATA_1 - private_srcw[0] = PRIVATE_DATA(cc); - if (private_srcw[0] != 0 && recurse_check_bit(common, private_srcw[0])) - private_count = 1; - cc += 1; - break; - - CASE_ITERATOR_TYPE_PRIVATE_DATA_2A - private_srcw[0] = PRIVATE_DATA(cc); - if (private_srcw[0] != 0 && recurse_check_bit(common, private_srcw[0])) - { - private_count = 2; - private_srcw[1] = private_srcw[0] + sizeof(sljit_sw); - SLJIT_ASSERT(recurse_check_bit(common, private_srcw[1])); - } - cc += 1; - break; - - CASE_ITERATOR_TYPE_PRIVATE_DATA_2B - private_srcw[0] = PRIVATE_DATA(cc); - if (private_srcw[0] != 0 && recurse_check_bit(common, private_srcw[0])) - { - private_count = 2; - private_srcw[1] = private_srcw[0] + sizeof(sljit_sw); - SLJIT_ASSERT(recurse_check_bit(common, private_srcw[1])); - } - cc += 1 + IMM2_SIZE; - break; - - case OP_CLASS: - case OP_NCLASS: -#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8 - case OP_XCLASS: - i = (*cc == OP_XCLASS) ? GET(cc, 1) : 1 + 32 / (int)sizeof(PCRE2_UCHAR); -#else - i = 1 + 32 / (int)sizeof(PCRE2_UCHAR); -#endif - if (PRIVATE_DATA(cc) != 0) - { - private_count = 1; - private_srcw[0] = PRIVATE_DATA(cc); - switch(get_class_iterator_size(cc + i)) - { - case 1: - break; - - case 2: - if (recurse_check_bit(common, private_srcw[0])) - { - private_count = 2; - private_srcw[1] = private_srcw[0] + sizeof(sljit_sw); - SLJIT_ASSERT(recurse_check_bit(common, private_srcw[1])); - } - break; - - default: - SLJIT_UNREACHABLE(); - break; - } - } - cc += i; - break; - - case OP_MARK: - case OP_COMMIT_ARG: - case OP_PRUNE_ARG: - case OP_THEN_ARG: - SLJIT_ASSERT(common->mark_ptr != 0); - if ((recurse_flags & recurse_flag_quit_found) && recurse_check_bit(common, common->mark_ptr)) - { - kept_shared_srcw[0] = common->mark_ptr; - kept_shared_count = 1; - } - if (common->control_head_ptr != 0 && recurse_check_bit(common, common->control_head_ptr)) - { - private_srcw[0] = common->control_head_ptr; - private_count = 1; - } - cc += 1 + 2 + cc[1]; - break; - - case OP_THEN: - SLJIT_ASSERT(common->control_head_ptr != 0); - if (recurse_check_bit(common, common->control_head_ptr)) - { - private_srcw[0] = common->control_head_ptr; - private_count = 1; - } - cc++; - break; - - default: - cc = next_opcode(common, cc); - SLJIT_ASSERT(cc != NULL); - continue; - } - - if (type != recurse_copy_shared_to_global && type != recurse_copy_kept_shared_to_global) - { - SLJIT_ASSERT(type == recurse_copy_from_global || type == recurse_copy_private_to_global || type == recurse_swap_global); - - for (i = 0; i < private_count; i++) - { - SLJIT_ASSERT(private_srcw[i] != 0); - - if (!from_sp) - delayed_mem_copy_move(&status, base_reg, stackptr, SLJIT_SP, private_srcw[i]); - - if (from_sp || type == recurse_swap_global) - delayed_mem_copy_move(&status, SLJIT_SP, private_srcw[i], base_reg, stackptr); - - stackptr += sizeof(sljit_sw); - } - } - else - stackptr += sizeof(sljit_sw) * private_count; - - if (type != recurse_copy_private_to_global && type != recurse_copy_kept_shared_to_global) - { - SLJIT_ASSERT(type == recurse_copy_from_global || type == recurse_copy_shared_to_global || type == recurse_swap_global); - - for (i = 0; i < shared_count; i++) - { - SLJIT_ASSERT(shared_srcw[i] != 0); - - if (!from_sp) - delayed_mem_copy_move(&status, base_reg, stackptr, SLJIT_SP, shared_srcw[i]); - - if (from_sp || type == recurse_swap_global) - delayed_mem_copy_move(&status, SLJIT_SP, shared_srcw[i], base_reg, stackptr); - - stackptr += sizeof(sljit_sw); - } - } - else - stackptr += sizeof(sljit_sw) * shared_count; - - if (type != recurse_copy_private_to_global && type != recurse_swap_global) - { - SLJIT_ASSERT(type == recurse_copy_from_global || type == recurse_copy_shared_to_global || type == recurse_copy_kept_shared_to_global); - - for (i = 0; i < kept_shared_count; i++) - { - SLJIT_ASSERT(kept_shared_srcw[i] != 0); - - if (!from_sp) - delayed_mem_copy_move(&status, base_reg, stackptr, SLJIT_SP, kept_shared_srcw[i]); - - if (from_sp || type == recurse_swap_global) - delayed_mem_copy_move(&status, SLJIT_SP, kept_shared_srcw[i], base_reg, stackptr); - - stackptr += sizeof(sljit_sw); - } - } - else - stackptr += sizeof(sljit_sw) * kept_shared_count; - } - -SLJIT_ASSERT(cc == ccend && stackptr == stacktop); - -delayed_mem_copy_finish(&status); -} - -static SLJIT_INLINE PCRE2_SPTR set_then_offsets(compiler_common *common, PCRE2_SPTR cc, sljit_u8 *current_offset) -{ -PCRE2_SPTR end = bracketend(cc); -BOOL has_alternatives = cc[GET(cc, 1)] == OP_ALT; - -/* Assert captures then. */ -if (*cc >= OP_ASSERT && *cc <= OP_ASSERTBACK_NA) - current_offset = NULL; -/* Conditional block does not. */ -if (*cc == OP_COND || *cc == OP_SCOND) - has_alternatives = FALSE; - -cc = next_opcode(common, cc); -if (has_alternatives) - current_offset = common->then_offsets + (cc - common->start); - -while (cc < end) - { - if ((*cc >= OP_ASSERT && *cc <= OP_ASSERTBACK_NA) || (*cc >= OP_ONCE && *cc <= OP_SCOND)) - cc = set_then_offsets(common, cc, current_offset); - else - { - if (*cc == OP_ALT && has_alternatives) - current_offset = common->then_offsets + (cc + 1 + LINK_SIZE - common->start); - if (*cc >= OP_THEN && *cc <= OP_THEN_ARG && current_offset != NULL) - *current_offset = 1; - cc = next_opcode(common, cc); - } - } - -return end; -} - -#undef CASE_ITERATOR_PRIVATE_DATA_1 -#undef CASE_ITERATOR_PRIVATE_DATA_2A -#undef CASE_ITERATOR_PRIVATE_DATA_2B -#undef CASE_ITERATOR_TYPE_PRIVATE_DATA_1 -#undef CASE_ITERATOR_TYPE_PRIVATE_DATA_2A -#undef CASE_ITERATOR_TYPE_PRIVATE_DATA_2B - -static SLJIT_INLINE BOOL is_powerof2(unsigned int value) -{ -return (value & (value - 1)) == 0; -} - -static SLJIT_INLINE void set_jumps(jump_list *list, struct sljit_label *label) -{ -while (list) - { - /* sljit_set_label is clever enough to do nothing - if either the jump or the label is NULL. */ - SET_LABEL(list->jump, label); - list = list->next; - } -} - -static SLJIT_INLINE void add_jump(struct sljit_compiler *compiler, jump_list **list, struct sljit_jump *jump) -{ -jump_list *list_item = sljit_alloc_memory(compiler, sizeof(jump_list)); -if (list_item) - { - list_item->next = *list; - list_item->jump = jump; - *list = list_item; - } -} - -static void add_stub(compiler_common *common, struct sljit_jump *start) -{ -DEFINE_COMPILER; -stub_list *list_item = sljit_alloc_memory(compiler, sizeof(stub_list)); - -if (list_item) - { - list_item->start = start; - list_item->quit = LABEL(); - list_item->next = common->stubs; - common->stubs = list_item; - } -} - -static void flush_stubs(compiler_common *common) -{ -DEFINE_COMPILER; -stub_list *list_item = common->stubs; - -while (list_item) - { - JUMPHERE(list_item->start); - add_jump(compiler, &common->stackalloc, JUMP(SLJIT_FAST_CALL)); - JUMPTO(SLJIT_JUMP, list_item->quit); - list_item = list_item->next; - } -common->stubs = NULL; -} - -static SLJIT_INLINE void count_match(compiler_common *common) -{ -DEFINE_COMPILER; - -OP2(SLJIT_SUB | SLJIT_SET_Z, COUNT_MATCH, 0, COUNT_MATCH, 0, SLJIT_IMM, 1); -add_jump(compiler, &common->calllimit, JUMP(SLJIT_ZERO)); -} - -static SLJIT_INLINE void allocate_stack(compiler_common *common, int size) -{ -/* May destroy all locals and registers except TMP2. */ -DEFINE_COMPILER; - -SLJIT_ASSERT(size > 0); -OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, size * SSIZE_OF(sw)); -#ifdef DESTROY_REGISTERS -OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 12345); -OP1(SLJIT_MOV, TMP3, 0, TMP1, 0); -OP1(SLJIT_MOV, RETURN_ADDR, 0, TMP1, 0); -OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS0, TMP1, 0); -OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS1, TMP1, 0); -#endif -add_stub(common, CMP(SLJIT_LESS, STACK_TOP, 0, STACK_LIMIT, 0)); -} - -static SLJIT_INLINE void free_stack(compiler_common *common, int size) -{ -DEFINE_COMPILER; - -SLJIT_ASSERT(size > 0); -OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, size * SSIZE_OF(sw)); -} - -static sljit_uw * allocate_read_only_data(compiler_common *common, sljit_uw size) -{ -DEFINE_COMPILER; -sljit_uw *result; - -if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) - return NULL; - -result = (sljit_uw *)SLJIT_MALLOC(size + sizeof(sljit_uw), compiler->allocator_data); -if (SLJIT_UNLIKELY(result == NULL)) - { - sljit_set_compiler_memory_error(compiler); - return NULL; - } - -*(void**)result = common->read_only_data_head; -common->read_only_data_head = (void *)result; -return result + 1; -} - -static SLJIT_INLINE void reset_ovector(compiler_common *common, int length) -{ -DEFINE_COMPILER; -struct sljit_label *loop; -sljit_s32 i; - -/* At this point we can freely use all temporary registers. */ -SLJIT_ASSERT(length > 1); -/* TMP1 returns with begin - 1. */ -OP2(SLJIT_SUB, SLJIT_R0, 0, SLJIT_MEM1(SLJIT_S0), SLJIT_OFFSETOF(jit_arguments, begin), SLJIT_IMM, IN_UCHARS(1)); -if (length < 8) - { - for (i = 1; i < length; i++) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(i), SLJIT_R0, 0); - } -else - { - if (sljit_emit_mem_update(compiler, SLJIT_MOV | SLJIT_MEM_SUPP | SLJIT_MEM_STORE | SLJIT_MEM_PRE, SLJIT_R0, SLJIT_MEM1(SLJIT_R1), sizeof(sljit_sw)) == SLJIT_SUCCESS) - { - GET_LOCAL_BASE(SLJIT_R1, 0, OVECTOR_START); - OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_IMM, length - 1); - loop = LABEL(); - sljit_emit_mem_update(compiler, SLJIT_MOV | SLJIT_MEM_STORE | SLJIT_MEM_PRE, SLJIT_R0, SLJIT_MEM1(SLJIT_R1), sizeof(sljit_sw)); - OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_R2, 0, SLJIT_R2, 0, SLJIT_IMM, 1); - JUMPTO(SLJIT_NOT_ZERO, loop); - } - else - { - GET_LOCAL_BASE(SLJIT_R1, 0, OVECTOR_START + sizeof(sljit_sw)); - OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_IMM, length - 1); - loop = LABEL(); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_R1), 0, SLJIT_R0, 0); - OP2(SLJIT_ADD, SLJIT_R1, 0, SLJIT_R1, 0, SLJIT_IMM, sizeof(sljit_sw)); - OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_R2, 0, SLJIT_R2, 0, SLJIT_IMM, 1); - JUMPTO(SLJIT_NOT_ZERO, loop); - } - } -} - -static SLJIT_INLINE void reset_early_fail(compiler_common *common) -{ -DEFINE_COMPILER; -sljit_u32 size = (sljit_u32)(common->early_fail_end_ptr - common->early_fail_start_ptr); -sljit_u32 uncleared_size; -sljit_s32 src = SLJIT_IMM; -sljit_s32 i; -struct sljit_label *loop; - -SLJIT_ASSERT(common->early_fail_start_ptr < common->early_fail_end_ptr); - -if (size == sizeof(sljit_sw)) - { - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->early_fail_start_ptr, SLJIT_IMM, 0); - return; - } - -if (sljit_get_register_index(TMP3) >= 0 && !sljit_has_cpu_feature(SLJIT_HAS_ZERO_REGISTER)) - { - OP1(SLJIT_MOV, TMP3, 0, SLJIT_IMM, 0); - src = TMP3; - } - -if (size <= 6 * sizeof(sljit_sw)) - { - for (i = common->early_fail_start_ptr; i < common->early_fail_end_ptr; i += sizeof(sljit_sw)) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), i, src, 0); - return; - } - -GET_LOCAL_BASE(TMP1, 0, common->early_fail_start_ptr); - -uncleared_size = ((size / sizeof(sljit_sw)) % 3) * sizeof(sljit_sw); - -OP2(SLJIT_ADD, TMP2, 0, TMP1, 0, SLJIT_IMM, size - uncleared_size); - -loop = LABEL(); -OP1(SLJIT_MOV, SLJIT_MEM1(TMP1), 0, src, 0); -OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 3 * sizeof(sljit_sw)); -OP1(SLJIT_MOV, SLJIT_MEM1(TMP1), -2 * SSIZE_OF(sw), src, 0); -OP1(SLJIT_MOV, SLJIT_MEM1(TMP1), -1 * SSIZE_OF(sw), src, 0); -CMPTO(SLJIT_LESS, TMP1, 0, TMP2, 0, loop); - -if (uncleared_size >= sizeof(sljit_sw)) - OP1(SLJIT_MOV, SLJIT_MEM1(TMP1), 0, src, 0); - -if (uncleared_size >= 2 * sizeof(sljit_sw)) - OP1(SLJIT_MOV, SLJIT_MEM1(TMP1), sizeof(sljit_sw), src, 0); -} - -static SLJIT_INLINE void do_reset_match(compiler_common *common, int length) -{ -DEFINE_COMPILER; -struct sljit_label *loop; -int i; - -SLJIT_ASSERT(length > 1); -/* OVECTOR(1) contains the "string begin - 1" constant. */ -if (length > 2) - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(1)); -if (length < 8) - { - for (i = 2; i < length; i++) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(i), TMP1, 0); - } -else - { - if (sljit_emit_mem_update(compiler, SLJIT_MOV | SLJIT_MEM_SUPP | SLJIT_MEM_STORE | SLJIT_MEM_PRE, TMP1, SLJIT_MEM1(TMP2), sizeof(sljit_sw)) == SLJIT_SUCCESS) - { - GET_LOCAL_BASE(TMP2, 0, OVECTOR_START + sizeof(sljit_sw)); - OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_IMM, length - 2); - loop = LABEL(); - sljit_emit_mem_update(compiler, SLJIT_MOV | SLJIT_MEM_STORE | SLJIT_MEM_PRE, TMP1, SLJIT_MEM1(TMP2), sizeof(sljit_sw)); - OP2(SLJIT_SUB | SLJIT_SET_Z, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, 1); - JUMPTO(SLJIT_NOT_ZERO, loop); - } - else - { - GET_LOCAL_BASE(TMP2, 0, OVECTOR_START + 2 * sizeof(sljit_sw)); - OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_IMM, length - 2); - loop = LABEL(); - OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), 0, TMP1, 0); - OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, SLJIT_IMM, sizeof(sljit_sw)); - OP2(SLJIT_SUB | SLJIT_SET_Z, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, 1); - JUMPTO(SLJIT_NOT_ZERO, loop); - } - } - -if (!HAS_VIRTUAL_REGISTERS) - OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, stack)); -else - OP1(SLJIT_MOV, STACK_TOP, 0, ARGUMENTS, 0); - -if (common->mark_ptr != 0) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->mark_ptr, SLJIT_IMM, 0); -if (common->control_head_ptr != 0) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_IMM, 0); -if (HAS_VIRTUAL_REGISTERS) - OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(STACK_TOP), SLJIT_OFFSETOF(jit_arguments, stack)); - -OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->start_ptr); -OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(STACK_TOP), SLJIT_OFFSETOF(struct sljit_stack, end)); -} - -static sljit_sw SLJIT_FUNC do_search_mark(sljit_sw *current, PCRE2_SPTR skip_arg) -{ -while (current != NULL) - { - switch (current[1]) - { - case type_then_trap: - break; - - case type_mark: - if (PRIV(strcmp)(skip_arg, (PCRE2_SPTR)current[2]) == 0) - return current[3]; - break; - - default: - SLJIT_UNREACHABLE(); - break; - } - SLJIT_ASSERT(current[0] == 0 || current < (sljit_sw*)current[0]); - current = (sljit_sw*)current[0]; - } -return 0; -} - -static SLJIT_INLINE void copy_ovector(compiler_common *common, int topbracket) -{ -DEFINE_COMPILER; -struct sljit_label *loop; -BOOL has_pre; - -/* At this point we can freely use all registers. */ -OP1(SLJIT_MOV, SLJIT_S2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(1)); -OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(1), STR_PTR, 0); - -if (HAS_VIRTUAL_REGISTERS) - { - OP1(SLJIT_MOV, SLJIT_R0, 0, ARGUMENTS, 0); - OP1(SLJIT_MOV, SLJIT_S0, 0, SLJIT_MEM1(SLJIT_SP), common->start_ptr); - if (common->mark_ptr != 0) - OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_SP), common->mark_ptr); - OP1(SLJIT_MOV_U32, SLJIT_R1, 0, SLJIT_MEM1(SLJIT_R0), SLJIT_OFFSETOF(jit_arguments, oveccount)); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_R0), SLJIT_OFFSETOF(jit_arguments, startchar_ptr), SLJIT_S0, 0); - if (common->mark_ptr != 0) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_R0), SLJIT_OFFSETOF(jit_arguments, mark_ptr), SLJIT_R2, 0); - OP2(SLJIT_ADD, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_R0), SLJIT_OFFSETOF(jit_arguments, match_data), - SLJIT_IMM, SLJIT_OFFSETOF(pcre2_match_data, ovector) - sizeof(PCRE2_SIZE)); - } -else - { - OP1(SLJIT_MOV, SLJIT_S0, 0, SLJIT_MEM1(SLJIT_SP), common->start_ptr); - OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, match_data)); - if (common->mark_ptr != 0) - OP1(SLJIT_MOV, SLJIT_R0, 0, SLJIT_MEM1(SLJIT_SP), common->mark_ptr); - OP1(SLJIT_MOV_U32, SLJIT_R1, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, oveccount)); - OP1(SLJIT_MOV, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, startchar_ptr), SLJIT_S0, 0); - if (common->mark_ptr != 0) - OP1(SLJIT_MOV, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, mark_ptr), SLJIT_R0, 0); - OP2(SLJIT_ADD, SLJIT_R2, 0, SLJIT_R2, 0, SLJIT_IMM, SLJIT_OFFSETOF(pcre2_match_data, ovector) - sizeof(PCRE2_SIZE)); - } - -has_pre = sljit_emit_mem_update(compiler, SLJIT_MOV | SLJIT_MEM_SUPP | SLJIT_MEM_PRE, SLJIT_S1, SLJIT_MEM1(SLJIT_S0), sizeof(sljit_sw)) == SLJIT_SUCCESS; - -GET_LOCAL_BASE(SLJIT_S0, 0, OVECTOR_START - (has_pre ? sizeof(sljit_sw) : 0)); -OP1(SLJIT_MOV, SLJIT_R0, 0, SLJIT_MEM1(HAS_VIRTUAL_REGISTERS ? SLJIT_R0 : ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, begin)); - -loop = LABEL(); - -if (has_pre) - sljit_emit_mem_update(compiler, SLJIT_MOV | SLJIT_MEM_PRE, SLJIT_S1, SLJIT_MEM1(SLJIT_S0), sizeof(sljit_sw)); -else - { - OP1(SLJIT_MOV, SLJIT_S1, 0, SLJIT_MEM1(SLJIT_S0), 0); - OP2(SLJIT_ADD, SLJIT_S0, 0, SLJIT_S0, 0, SLJIT_IMM, sizeof(sljit_sw)); - } - -OP2(SLJIT_ADD, SLJIT_R2, 0, SLJIT_R2, 0, SLJIT_IMM, sizeof(PCRE2_SIZE)); -OP2(SLJIT_SUB, SLJIT_S1, 0, SLJIT_S1, 0, SLJIT_R0, 0); -/* Copy the integer value to the output buffer */ -#if PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32 -OP2(SLJIT_ASHR, SLJIT_S1, 0, SLJIT_S1, 0, SLJIT_IMM, UCHAR_SHIFT); -#endif - -SLJIT_ASSERT(sizeof(PCRE2_SIZE) == 4 || sizeof(PCRE2_SIZE) == 8); -OP1(((sizeof(PCRE2_SIZE) == 4) ? SLJIT_MOV_U32 : SLJIT_MOV), SLJIT_MEM1(SLJIT_R2), 0, SLJIT_S1, 0); - -OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_R1, 0, SLJIT_R1, 0, SLJIT_IMM, 1); -JUMPTO(SLJIT_NOT_ZERO, loop); - -/* Calculate the return value, which is the maximum ovector value. */ -if (topbracket > 1) - { - if (sljit_emit_mem_update(compiler, SLJIT_MOV | SLJIT_MEM_SUPP | SLJIT_MEM_PRE, SLJIT_R2, SLJIT_MEM1(SLJIT_R0), -(2 * SSIZE_OF(sw))) == SLJIT_SUCCESS) - { - GET_LOCAL_BASE(SLJIT_R0, 0, OVECTOR_START + topbracket * 2 * sizeof(sljit_sw)); - OP1(SLJIT_MOV, SLJIT_R1, 0, SLJIT_IMM, topbracket + 1); - - /* OVECTOR(0) is never equal to SLJIT_S2. */ - loop = LABEL(); - sljit_emit_mem_update(compiler, SLJIT_MOV | SLJIT_MEM_PRE, SLJIT_R2, SLJIT_MEM1(SLJIT_R0), -(2 * SSIZE_OF(sw))); - OP2(SLJIT_SUB, SLJIT_R1, 0, SLJIT_R1, 0, SLJIT_IMM, 1); - CMPTO(SLJIT_EQUAL, SLJIT_R2, 0, SLJIT_S2, 0, loop); - OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_R1, 0); - } - else - { - GET_LOCAL_BASE(SLJIT_R0, 0, OVECTOR_START + (topbracket - 1) * 2 * sizeof(sljit_sw)); - OP1(SLJIT_MOV, SLJIT_R1, 0, SLJIT_IMM, topbracket + 1); - - /* OVECTOR(0) is never equal to SLJIT_S2. */ - loop = LABEL(); - OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_R0), 0); - OP2(SLJIT_SUB, SLJIT_R0, 0, SLJIT_R0, 0, SLJIT_IMM, 2 * SSIZE_OF(sw)); - OP2(SLJIT_SUB, SLJIT_R1, 0, SLJIT_R1, 0, SLJIT_IMM, 1); - CMPTO(SLJIT_EQUAL, SLJIT_R2, 0, SLJIT_S2, 0, loop); - OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_R1, 0); - } - } -else - OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, 1); -} - -static SLJIT_INLINE void return_with_partial_match(compiler_common *common, struct sljit_label *quit) -{ -DEFINE_COMPILER; -sljit_s32 mov_opcode; -sljit_s32 arguments_reg = !HAS_VIRTUAL_REGISTERS ? ARGUMENTS : SLJIT_R1; - -SLJIT_COMPILE_ASSERT(STR_END == SLJIT_S0, str_end_must_be_saved_reg0); -SLJIT_ASSERT(common->start_used_ptr != 0 && common->start_ptr != 0 - && (common->mode == PCRE2_JIT_PARTIAL_SOFT ? common->hit_start != 0 : common->hit_start == 0)); - -if (arguments_reg != ARGUMENTS) - OP1(SLJIT_MOV, arguments_reg, 0, ARGUMENTS, 0); -OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_SP), - common->mode == PCRE2_JIT_PARTIAL_SOFT ? common->hit_start : common->start_ptr); -OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE2_ERROR_PARTIAL); - -/* Store match begin and end. */ -OP1(SLJIT_MOV, SLJIT_S1, 0, SLJIT_MEM1(arguments_reg), SLJIT_OFFSETOF(jit_arguments, begin)); -OP1(SLJIT_MOV, SLJIT_MEM1(arguments_reg), SLJIT_OFFSETOF(jit_arguments, startchar_ptr), SLJIT_R2, 0); -OP1(SLJIT_MOV, SLJIT_R1, 0, SLJIT_MEM1(arguments_reg), SLJIT_OFFSETOF(jit_arguments, match_data)); - -mov_opcode = (sizeof(PCRE2_SIZE) == 4) ? SLJIT_MOV_U32 : SLJIT_MOV; - -OP2(SLJIT_SUB, SLJIT_R2, 0, SLJIT_R2, 0, SLJIT_S1, 0); -#if PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32 -OP2(SLJIT_ASHR, SLJIT_R2, 0, SLJIT_R2, 0, SLJIT_IMM, UCHAR_SHIFT); -#endif -OP1(mov_opcode, SLJIT_MEM1(SLJIT_R1), SLJIT_OFFSETOF(pcre2_match_data, ovector), SLJIT_R2, 0); - -OP2(SLJIT_SUB, STR_END, 0, STR_END, 0, SLJIT_S1, 0); -#if PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32 -OP2(SLJIT_ASHR, STR_END, 0, STR_END, 0, SLJIT_IMM, UCHAR_SHIFT); -#endif -OP1(mov_opcode, SLJIT_MEM1(SLJIT_R1), SLJIT_OFFSETOF(pcre2_match_data, ovector) + sizeof(PCRE2_SIZE), STR_END, 0); - -JUMPTO(SLJIT_JUMP, quit); -} - -static SLJIT_INLINE void check_start_used_ptr(compiler_common *common) -{ -/* May destroy TMP1. */ -DEFINE_COMPILER; -struct sljit_jump *jump; - -if (common->mode == PCRE2_JIT_PARTIAL_SOFT) - { - /* The value of -1 must be kept for start_used_ptr! */ - OP2(SLJIT_ADD, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, SLJIT_IMM, 1); - /* Jumps if start_used_ptr < STR_PTR, or start_used_ptr == -1. Although overwriting - is not necessary if start_used_ptr == STR_PTR, it does not hurt as well. */ - jump = CMP(SLJIT_LESS_EQUAL, TMP1, 0, STR_PTR, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0); - JUMPHERE(jump); - } -else if (common->mode == PCRE2_JIT_PARTIAL_HARD) - { - jump = CMP(SLJIT_LESS_EQUAL, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0); - JUMPHERE(jump); - } -} - -static SLJIT_INLINE BOOL char_has_othercase(compiler_common *common, PCRE2_SPTR cc) -{ -/* Detects if the character has an othercase. */ -unsigned int c; - -#ifdef SUPPORT_UNICODE -if (common->utf || common->ucp) - { - if (common->utf) - { - GETCHAR(c, cc); - } - else - c = *cc; - - if (c > 127) - return c != UCD_OTHERCASE(c); - - return common->fcc[c] != c; - } -else -#endif - c = *cc; -return MAX_255(c) ? common->fcc[c] != c : FALSE; -} - -static SLJIT_INLINE unsigned int char_othercase(compiler_common *common, unsigned int c) -{ -/* Returns with the othercase. */ -#ifdef SUPPORT_UNICODE -if ((common->utf || common->ucp) && c > 127) - return UCD_OTHERCASE(c); -#endif -return TABLE_GET(c, common->fcc, c); -} - -static unsigned int char_get_othercase_bit(compiler_common *common, PCRE2_SPTR cc) -{ -/* Detects if the character and its othercase has only 1 bit difference. */ -unsigned int c, oc, bit; -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8 -int n; -#endif - -#ifdef SUPPORT_UNICODE -if (common->utf || common->ucp) - { - if (common->utf) - { - GETCHAR(c, cc); - } - else - c = *cc; - - if (c <= 127) - oc = common->fcc[c]; - else - oc = UCD_OTHERCASE(c); - } -else - { - c = *cc; - oc = TABLE_GET(c, common->fcc, c); - } -#else -c = *cc; -oc = TABLE_GET(c, common->fcc, c); -#endif - -SLJIT_ASSERT(c != oc); - -bit = c ^ oc; -/* Optimized for English alphabet. */ -if (c <= 127 && bit == 0x20) - return (0 << 8) | 0x20; - -/* Since c != oc, they must have at least 1 bit difference. */ -if (!is_powerof2(bit)) - return 0; - -#if PCRE2_CODE_UNIT_WIDTH == 8 - -#ifdef SUPPORT_UNICODE -if (common->utf && c > 127) - { - n = GET_EXTRALEN(*cc); - while ((bit & 0x3f) == 0) - { - n--; - bit >>= 6; - } - return (n << 8) | bit; - } -#endif /* SUPPORT_UNICODE */ -return (0 << 8) | bit; - -#elif PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32 - -#ifdef SUPPORT_UNICODE -if (common->utf && c > 65535) - { - if (bit >= (1u << 10)) - bit >>= 10; - else - return (bit < 256) ? ((2 << 8) | bit) : ((3 << 8) | (bit >> 8)); - } -#endif /* SUPPORT_UNICODE */ -return (bit < 256) ? ((0u << 8) | bit) : ((1u << 8) | (bit >> 8)); - -#endif /* PCRE2_CODE_UNIT_WIDTH == [8|16|32] */ -} - -static void check_partial(compiler_common *common, BOOL force) -{ -/* Checks whether a partial matching is occurred. Does not modify registers. */ -DEFINE_COMPILER; -struct sljit_jump *jump = NULL; - -SLJIT_ASSERT(!force || common->mode != PCRE2_JIT_COMPLETE); - -if (common->mode == PCRE2_JIT_COMPLETE) - return; - -if (!force && !common->allow_empty_partial) - jump = CMP(SLJIT_GREATER_EQUAL, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0); -else if (common->mode == PCRE2_JIT_PARTIAL_SOFT) - jump = CMP(SLJIT_EQUAL, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, SLJIT_IMM, -1); - -if (common->mode == PCRE2_JIT_PARTIAL_SOFT) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->hit_start, SLJIT_IMM, 0); -else - { - if (common->partialmatchlabel != NULL) - JUMPTO(SLJIT_JUMP, common->partialmatchlabel); - else - add_jump(compiler, &common->partialmatch, JUMP(SLJIT_JUMP)); - } - -if (jump != NULL) - JUMPHERE(jump); -} - -static void check_str_end(compiler_common *common, jump_list **end_reached) -{ -/* Does not affect registers. Usually used in a tight spot. */ -DEFINE_COMPILER; -struct sljit_jump *jump; - -if (common->mode == PCRE2_JIT_COMPLETE) - { - add_jump(compiler, end_reached, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0)); - return; - } - -jump = CMP(SLJIT_LESS, STR_PTR, 0, STR_END, 0); -if (common->mode == PCRE2_JIT_PARTIAL_SOFT) - { - add_jump(compiler, end_reached, CMP(SLJIT_GREATER_EQUAL, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0)); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->hit_start, SLJIT_IMM, 0); - add_jump(compiler, end_reached, JUMP(SLJIT_JUMP)); - } -else - { - add_jump(compiler, end_reached, CMP(SLJIT_GREATER_EQUAL, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0)); - if (common->partialmatchlabel != NULL) - JUMPTO(SLJIT_JUMP, common->partialmatchlabel); - else - add_jump(compiler, &common->partialmatch, JUMP(SLJIT_JUMP)); - } -JUMPHERE(jump); -} - -static void detect_partial_match(compiler_common *common, jump_list **backtracks) -{ -DEFINE_COMPILER; -struct sljit_jump *jump; - -if (common->mode == PCRE2_JIT_COMPLETE) - { - add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0)); - return; - } - -/* Partial matching mode. */ -jump = CMP(SLJIT_LESS, STR_PTR, 0, STR_END, 0); -if (!common->allow_empty_partial) - add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0)); -else if (common->mode == PCRE2_JIT_PARTIAL_SOFT) - add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, SLJIT_IMM, -1)); - -if (common->mode == PCRE2_JIT_PARTIAL_SOFT) - { - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->hit_start, SLJIT_IMM, 0); - add_jump(compiler, backtracks, JUMP(SLJIT_JUMP)); - } -else - { - if (common->partialmatchlabel != NULL) - JUMPTO(SLJIT_JUMP, common->partialmatchlabel); - else - add_jump(compiler, &common->partialmatch, JUMP(SLJIT_JUMP)); - } -JUMPHERE(jump); -} - -static void process_partial_match(compiler_common *common) -{ -DEFINE_COMPILER; -struct sljit_jump *jump; - -/* Partial matching mode. */ -if (common->mode == PCRE2_JIT_PARTIAL_SOFT) - { - jump = CMP(SLJIT_GREATER_EQUAL, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->hit_start, SLJIT_IMM, 0); - JUMPHERE(jump); - } -else if (common->mode == PCRE2_JIT_PARTIAL_HARD) - { - if (common->partialmatchlabel != NULL) - CMPTO(SLJIT_LESS, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0, common->partialmatchlabel); - else - add_jump(compiler, &common->partialmatch, CMP(SLJIT_LESS, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0)); - } -} - -static void detect_partial_match_to(compiler_common *common, struct sljit_label *label) -{ -DEFINE_COMPILER; - -CMPTO(SLJIT_LESS, STR_PTR, 0, STR_END, 0, label); -process_partial_match(common); -} - -static void peek_char(compiler_common *common, sljit_u32 max, sljit_s32 dst, sljit_sw dstw, jump_list **backtracks) -{ -/* Reads the character into TMP1, keeps STR_PTR. -Does not check STR_END. TMP2, dst, RETURN_ADDR Destroyed. */ -DEFINE_COMPILER; -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 -struct sljit_jump *jump; -#endif /* SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 */ - -SLJIT_UNUSED_ARG(max); -SLJIT_UNUSED_ARG(dst); -SLJIT_UNUSED_ARG(dstw); -SLJIT_UNUSED_ARG(backtracks); - -OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); - -#ifdef SUPPORT_UNICODE -#if PCRE2_CODE_UNIT_WIDTH == 8 -if (common->utf) - { - if (max < 128) return; - - jump = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0x80); - OP1(SLJIT_MOV, dst, dstw, STR_PTR, 0); - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - add_jump(compiler, common->invalid_utf ? &common->utfreadchar_invalid : &common->utfreadchar, JUMP(SLJIT_FAST_CALL)); - OP1(SLJIT_MOV, STR_PTR, 0, dst, dstw); - if (backtracks && common->invalid_utf) - add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, INVALID_UTF_CHAR)); - JUMPHERE(jump); - } -#elif PCRE2_CODE_UNIT_WIDTH == 16 -if (common->utf) - { - if (max < 0xd800) return; - - OP2(SLJIT_SUB, TMP2, 0, TMP1, 0, SLJIT_IMM, 0xd800); - - if (common->invalid_utf) - { - jump = CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0xe000 - 0xd800); - OP1(SLJIT_MOV, dst, dstw, STR_PTR, 0); - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - add_jump(compiler, &common->utfreadchar_invalid, JUMP(SLJIT_FAST_CALL)); - OP1(SLJIT_MOV, STR_PTR, 0, dst, dstw); - if (backtracks && common->invalid_utf) - add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, INVALID_UTF_CHAR)); - } - else - { - /* TMP2 contains the high surrogate. */ - jump = CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0xdc00 - 0xd800); - OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1)); - OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 10); - OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x10000 - 0xdc00); - OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP2, 0); - } - - JUMPHERE(jump); - } -#elif PCRE2_CODE_UNIT_WIDTH == 32 -if (common->invalid_utf) - { - if (max < 0xd800) return; - - if (backtracks != NULL) - { - OP2(SLJIT_SUB, TMP2, 0, TMP1, 0, SLJIT_IMM, 0xd800); - add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0x110000)); - add_jump(compiler, backtracks, CMP(SLJIT_LESS, TMP2, 0, SLJIT_IMM, 0xe000 - 0xd800)); - } - else - { - OP2(SLJIT_SUB, TMP2, 0, TMP1, 0, SLJIT_IMM, 0xd800); - OP2U(SLJIT_SUB | SLJIT_SET_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0x110000); - CMOV(SLJIT_GREATER_EQUAL, TMP1, SLJIT_IMM, INVALID_UTF_CHAR); - OP2U(SLJIT_SUB | SLJIT_SET_LESS, TMP2, 0, SLJIT_IMM, 0xe000 - 0xd800); - CMOV(SLJIT_LESS, TMP1, SLJIT_IMM, INVALID_UTF_CHAR); - } - } -#endif /* PCRE2_CODE_UNIT_WIDTH == [8|16|32] */ -#endif /* SUPPORT_UNICODE */ -} - -static void peek_char_back(compiler_common *common, sljit_u32 max, jump_list **backtracks) -{ -/* Reads one character back without moving STR_PTR. TMP2 must -contain the start of the subject buffer. Affects TMP1, TMP2, and RETURN_ADDR. */ -DEFINE_COMPILER; - -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 -struct sljit_jump *jump; -#endif /* SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 */ - -SLJIT_UNUSED_ARG(max); -SLJIT_UNUSED_ARG(backtracks); - -OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-1)); - -#ifdef SUPPORT_UNICODE -#if PCRE2_CODE_UNIT_WIDTH == 8 -if (common->utf) - { - if (max < 128) return; - - jump = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0x80); - if (common->invalid_utf) - { - add_jump(compiler, &common->utfpeakcharback_invalid, JUMP(SLJIT_FAST_CALL)); - if (backtracks != NULL) - add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, INVALID_UTF_CHAR)); - } - else - add_jump(compiler, &common->utfpeakcharback, JUMP(SLJIT_FAST_CALL)); - JUMPHERE(jump); - } -#elif PCRE2_CODE_UNIT_WIDTH == 16 -if (common->utf) - { - if (max < 0xd800) return; - - if (common->invalid_utf) - { - jump = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0xd800); - add_jump(compiler, &common->utfpeakcharback_invalid, JUMP(SLJIT_FAST_CALL)); - if (backtracks != NULL) - add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, INVALID_UTF_CHAR)); - } - else - { - OP2(SLJIT_SUB, TMP2, 0, TMP1, 0, SLJIT_IMM, 0xdc00); - jump = CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0xe000 - 0xdc00); - /* TMP2 contains the low surrogate. */ - OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-2)); - OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x10000); - OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xd800); - OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 10); - OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP2, 0); - } - JUMPHERE(jump); - } -#elif PCRE2_CODE_UNIT_WIDTH == 32 -if (common->invalid_utf) - { - OP2(SLJIT_SUB, TMP2, 0, TMP1, 0, SLJIT_IMM, 0xd800); - add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0x110000)); - add_jump(compiler, backtracks, CMP(SLJIT_LESS, TMP2, 0, SLJIT_IMM, 0xe000 - 0xd800)); - } -#endif /* PCRE2_CODE_UNIT_WIDTH == [8|16|32] */ -#endif /* SUPPORT_UNICODE */ -} - -#define READ_CHAR_UPDATE_STR_PTR 0x1 -#define READ_CHAR_UTF8_NEWLINE 0x2 -#define READ_CHAR_NEWLINE (READ_CHAR_UPDATE_STR_PTR | READ_CHAR_UTF8_NEWLINE) -#define READ_CHAR_VALID_UTF 0x4 - -static void read_char(compiler_common *common, sljit_u32 min, sljit_u32 max, - jump_list **backtracks, sljit_u32 options) -{ -/* Reads the precise value of a character into TMP1, if the character is -between min and max (c >= min && c <= max). Otherwise it returns with a value -outside the range. Does not check STR_END. */ -DEFINE_COMPILER; -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 -struct sljit_jump *jump; -#endif -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8 -struct sljit_jump *jump2; -#endif - -SLJIT_UNUSED_ARG(min); -SLJIT_UNUSED_ARG(max); -SLJIT_UNUSED_ARG(backtracks); -SLJIT_UNUSED_ARG(options); -SLJIT_ASSERT(min <= max); - -OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); -OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - -#ifdef SUPPORT_UNICODE -#if PCRE2_CODE_UNIT_WIDTH == 8 -if (common->utf) - { - if (max < 128 && !(options & READ_CHAR_UPDATE_STR_PTR)) return; - - if (common->invalid_utf && !(options & READ_CHAR_VALID_UTF)) - { - jump = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0x80); - - if (options & READ_CHAR_UTF8_NEWLINE) - add_jump(compiler, &common->utfreadnewline_invalid, JUMP(SLJIT_FAST_CALL)); - else - add_jump(compiler, &common->utfreadchar_invalid, JUMP(SLJIT_FAST_CALL)); - - if (backtracks != NULL) - add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, INVALID_UTF_CHAR)); - JUMPHERE(jump); - return; - } - - jump = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0xc0); - if (min >= 0x10000) - { - OP2(SLJIT_SUB, TMP2, 0, TMP1, 0, SLJIT_IMM, 0xf0); - if (options & READ_CHAR_UPDATE_STR_PTR) - OP1(SLJIT_MOV_U8, RETURN_ADDR, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0); - OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); - jump2 = CMP(SLJIT_GREATER, TMP2, 0, SLJIT_IMM, 0x7); - OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 6); - OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x3f); - OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0); - OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1)); - OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6); - OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f); - OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0); - OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(2)); - if (!(options & READ_CHAR_UPDATE_STR_PTR)) - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(3)); - OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6); - OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f); - OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0); - JUMPHERE(jump2); - if (options & READ_CHAR_UPDATE_STR_PTR) - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, RETURN_ADDR, 0); - } - else if (min >= 0x800 && max <= 0xffff) - { - OP2(SLJIT_SUB, TMP2, 0, TMP1, 0, SLJIT_IMM, 0xe0); - if (options & READ_CHAR_UPDATE_STR_PTR) - OP1(SLJIT_MOV_U8, RETURN_ADDR, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0); - OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); - jump2 = CMP(SLJIT_GREATER, TMP2, 0, SLJIT_IMM, 0xf); - OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 6); - OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x3f); - OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0); - OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1)); - if (!(options & READ_CHAR_UPDATE_STR_PTR)) - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2)); - OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6); - OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f); - OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0); - JUMPHERE(jump2); - if (options & READ_CHAR_UPDATE_STR_PTR) - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, RETURN_ADDR, 0); - } - else if (max >= 0x800) - { - add_jump(compiler, &common->utfreadchar, JUMP(SLJIT_FAST_CALL)); - } - else if (max < 128) - { - OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0); - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0); - } - else - { - OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); - if (!(options & READ_CHAR_UPDATE_STR_PTR)) - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - else - OP1(SLJIT_MOV_U8, RETURN_ADDR, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0); - OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x3f); - OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6); - OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f); - OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0); - if (options & READ_CHAR_UPDATE_STR_PTR) - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, RETURN_ADDR, 0); - } - JUMPHERE(jump); - } -#elif PCRE2_CODE_UNIT_WIDTH == 16 -if (common->utf) - { - if (max < 0xd800 && !(options & READ_CHAR_UPDATE_STR_PTR)) return; - - if (common->invalid_utf && !(options & READ_CHAR_VALID_UTF)) - { - OP2(SLJIT_SUB, TMP2, 0, TMP1, 0, SLJIT_IMM, 0xd800); - jump = CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0xe000 - 0xd800); - - if (options & READ_CHAR_UTF8_NEWLINE) - add_jump(compiler, &common->utfreadnewline_invalid, JUMP(SLJIT_FAST_CALL)); - else - add_jump(compiler, &common->utfreadchar_invalid, JUMP(SLJIT_FAST_CALL)); - - if (backtracks != NULL) - add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, INVALID_UTF_CHAR)); - JUMPHERE(jump); - return; - } - - if (max >= 0x10000) - { - OP2(SLJIT_SUB, TMP2, 0, TMP1, 0, SLJIT_IMM, 0xd800); - jump = CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0xdc00 - 0xd800); - /* TMP2 contains the high surrogate. */ - OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); - OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 10); - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x10000 - 0xdc00); - OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP2, 0); - JUMPHERE(jump); - return; - } - - /* Skip low surrogate if necessary. */ - OP2(SLJIT_SUB, TMP2, 0, TMP1, 0, SLJIT_IMM, 0xd800); - - if (sljit_has_cpu_feature(SLJIT_HAS_CMOV) && !HAS_VIRTUAL_REGISTERS) - { - if (options & READ_CHAR_UPDATE_STR_PTR) - OP2(SLJIT_ADD, RETURN_ADDR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - OP2U(SLJIT_SUB | SLJIT_SET_LESS, TMP2, 0, SLJIT_IMM, 0x400); - if (options & READ_CHAR_UPDATE_STR_PTR) - CMOV(SLJIT_LESS, STR_PTR, RETURN_ADDR, 0); - if (max >= 0xd800) - CMOV(SLJIT_LESS, TMP1, SLJIT_IMM, 0x10000); - } - else - { - jump = CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0x400); - if (options & READ_CHAR_UPDATE_STR_PTR) - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - if (max >= 0xd800) - OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0x10000); - JUMPHERE(jump); - } - } -#elif PCRE2_CODE_UNIT_WIDTH == 32 -if (common->invalid_utf) - { - if (backtracks != NULL) - { - OP2(SLJIT_SUB, TMP2, 0, TMP1, 0, SLJIT_IMM, 0xd800); - add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0x110000)); - add_jump(compiler, backtracks, CMP(SLJIT_LESS, TMP2, 0, SLJIT_IMM, 0xe000 - 0xd800)); - } - else - { - OP2(SLJIT_SUB, TMP2, 0, TMP1, 0, SLJIT_IMM, 0xd800); - OP2U(SLJIT_SUB | SLJIT_SET_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0x110000); - CMOV(SLJIT_GREATER_EQUAL, TMP1, SLJIT_IMM, INVALID_UTF_CHAR); - OP2U(SLJIT_SUB | SLJIT_SET_LESS, TMP2, 0, SLJIT_IMM, 0xe000 - 0xd800); - CMOV(SLJIT_LESS, TMP1, SLJIT_IMM, INVALID_UTF_CHAR); - } - } -#endif /* PCRE2_CODE_UNIT_WIDTH == [8|16|32] */ -#endif /* SUPPORT_UNICODE */ -} - -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8 - -static BOOL is_char7_bitset(const sljit_u8 *bitset, BOOL nclass) -{ -/* Tells whether the character codes below 128 are enough -to determine a match. */ -const sljit_u8 value = nclass ? 0xff : 0; -const sljit_u8 *end = bitset + 32; - -bitset += 16; -do - { - if (*bitset++ != value) - return FALSE; - } -while (bitset < end); -return TRUE; -} - -static void read_char7_type(compiler_common *common, jump_list **backtracks, BOOL negated) -{ -/* Reads the precise character type of a character into TMP1, if the character -is less than 128. Otherwise it returns with zero. Does not check STR_END. The -full_read argument tells whether characters above max are accepted or not. */ -DEFINE_COMPILER; -struct sljit_jump *jump; - -SLJIT_ASSERT(common->utf); - -OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), 0); -OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - -/* All values > 127 are zero in ctypes. */ -OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP2), common->ctypes); - -if (negated) - { - jump = CMP(SLJIT_LESS, TMP2, 0, SLJIT_IMM, 0x80); - - if (common->invalid_utf) - { - add_jump(compiler, &common->utfreadchar_invalid, JUMP(SLJIT_FAST_CALL)); - add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, INVALID_UTF_CHAR)); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0); - } - else - { - OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP2), (sljit_sw)PRIV(utf8_table4) - 0xc0); - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0); - } - JUMPHERE(jump); - } -} - -#endif /* SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8 */ - -static void read_char8_type(compiler_common *common, jump_list **backtracks, BOOL negated) -{ -/* Reads the character type into TMP1, updates STR_PTR. Does not check STR_END. */ -DEFINE_COMPILER; -#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8 -struct sljit_jump *jump; -#endif -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8 -struct sljit_jump *jump2; -#endif - -SLJIT_UNUSED_ARG(backtracks); -SLJIT_UNUSED_ARG(negated); - -OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), 0); -OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8 -if (common->utf) - { - /* The result of this read may be unused, but saves an "else" part. */ - OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP2), common->ctypes); - jump = CMP(SLJIT_LESS, TMP2, 0, SLJIT_IMM, 0x80); - - if (!negated) - { - if (common->invalid_utf) - add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0)); - - OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xc2); - if (common->invalid_utf) - add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0xe0 - 0xc2)); - - OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 6); - OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, TMP1, 0); - OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x80); - if (common->invalid_utf) - add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0x40)); - - OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0); - jump2 = CMP(SLJIT_GREATER, TMP2, 0, SLJIT_IMM, 255); - OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP2), common->ctypes); - JUMPHERE(jump2); - } - else if (common->invalid_utf) - { - add_jump(compiler, &common->utfreadchar_invalid, JUMP(SLJIT_FAST_CALL)); - OP1(SLJIT_MOV, TMP2, 0, TMP1, 0); - add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, INVALID_UTF_CHAR)); - - OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0); - jump2 = CMP(SLJIT_GREATER, TMP2, 0, SLJIT_IMM, 255); - OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP2), common->ctypes); - JUMPHERE(jump2); - } - else - add_jump(compiler, &common->utfreadtype8, JUMP(SLJIT_FAST_CALL)); - - JUMPHERE(jump); - return; - } -#endif /* SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8 */ - -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 32 -if (common->invalid_utf && negated) - add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0x110000)); -#endif /* SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 32 */ - -#if PCRE2_CODE_UNIT_WIDTH != 8 -/* The ctypes array contains only 256 values. */ -OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0); -jump = CMP(SLJIT_GREATER, TMP2, 0, SLJIT_IMM, 255); -#endif /* PCRE2_CODE_UNIT_WIDTH != 8 */ -OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP2), common->ctypes); -#if PCRE2_CODE_UNIT_WIDTH != 8 -JUMPHERE(jump); -#endif /* PCRE2_CODE_UNIT_WIDTH != 8 */ - -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 16 -if (common->utf && negated) - { - /* Skip low surrogate if necessary. */ - if (!common->invalid_utf) - { - OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xd800); - - if (sljit_has_cpu_feature(SLJIT_HAS_CMOV) && !HAS_VIRTUAL_REGISTERS) - { - OP2(SLJIT_ADD, RETURN_ADDR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - OP2U(SLJIT_SUB | SLJIT_SET_LESS, TMP2, 0, SLJIT_IMM, 0x400); - CMOV(SLJIT_LESS, STR_PTR, RETURN_ADDR, 0); - } - else - { - jump = CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0x400); - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - JUMPHERE(jump); - } - return; - } - - OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xd800); - jump = CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0xe000 - 0xd800); - add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0x400)); - add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0)); - - OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xdc00); - add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0x400)); - - JUMPHERE(jump); - return; - } -#endif /* SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 16 */ -} - -static void move_back(compiler_common *common, jump_list **backtracks, BOOL must_be_valid) -{ -/* Goes one character back. Affects STR_PTR and TMP1. If must_be_valid is TRUE, -TMP2 is not used. Otherwise TMP2 must contain the start of the subject buffer, -and it is destroyed. Does not modify STR_PTR for invalid character sequences. */ -DEFINE_COMPILER; - -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 -struct sljit_jump *jump; -#endif - -#ifdef SUPPORT_UNICODE -#if PCRE2_CODE_UNIT_WIDTH == 8 -struct sljit_label *label; - -if (common->utf) - { - if (!must_be_valid && common->invalid_utf) - { - OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), -IN_UCHARS(1)); - OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - jump = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0x80); - add_jump(compiler, &common->utfmoveback_invalid, JUMP(SLJIT_FAST_CALL)); - if (backtracks != NULL) - add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0)); - JUMPHERE(jump); - return; - } - - label = LABEL(); - OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), -IN_UCHARS(1)); - OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xc0); - CMPTO(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0x80, label); - return; - } -#elif PCRE2_CODE_UNIT_WIDTH == 16 -if (common->utf) - { - OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), -IN_UCHARS(1)); - OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - - if (!must_be_valid && common->invalid_utf) - { - OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xd800); - jump = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0xe000 - 0xd800); - add_jump(compiler, &common->utfmoveback_invalid, JUMP(SLJIT_FAST_CALL)); - if (backtracks != NULL) - add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0)); - JUMPHERE(jump); - return; - } - - /* Skip low surrogate if necessary. */ - OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xfc00); - OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, 0xdc00); - OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_EQUAL); - OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, UCHAR_SHIFT); - OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP1, 0); - return; - } -#elif PCRE2_CODE_UNIT_WIDTH == 32 -if (common->invalid_utf && !must_be_valid) - { - OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), -IN_UCHARS(1)); - if (backtracks != NULL) - { - add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0x110000)); - OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - return; - } - - OP2U(SLJIT_SUB | SLJIT_SET_LESS, TMP1, 0, SLJIT_IMM, 0x110000); - OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_LESS); - OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, UCHAR_SHIFT); - OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP1, 0); - return; - } -#endif /* PCRE2_CODE_UNIT_WIDTH == [8|16|32] */ -#endif /* SUPPORT_UNICODE */ - -SLJIT_UNUSED_ARG(backtracks); -SLJIT_UNUSED_ARG(must_be_valid); - -OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); -} - -static void check_newlinechar(compiler_common *common, int nltype, jump_list **backtracks, BOOL jumpifmatch) -{ -/* Character comes in TMP1. Checks if it is a newline. TMP2 may be destroyed. */ -DEFINE_COMPILER; -struct sljit_jump *jump; - -if (nltype == NLTYPE_ANY) - { - add_jump(compiler, &common->anynewline, JUMP(SLJIT_FAST_CALL)); - sljit_set_current_flags(compiler, SLJIT_SET_Z); - add_jump(compiler, backtracks, JUMP(jumpifmatch ? SLJIT_NOT_ZERO : SLJIT_ZERO)); - } -else if (nltype == NLTYPE_ANYCRLF) - { - if (jumpifmatch) - { - add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_CR)); - add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_NL)); - } - else - { - jump = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_CR); - add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_NL)); - JUMPHERE(jump); - } - } -else - { - SLJIT_ASSERT(nltype == NLTYPE_FIXED && common->newline < 256); - add_jump(compiler, backtracks, CMP(jumpifmatch ? SLJIT_EQUAL : SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, common->newline)); - } -} - -#ifdef SUPPORT_UNICODE - -#if PCRE2_CODE_UNIT_WIDTH == 8 -static void do_utfreadchar(compiler_common *common) -{ -/* Fast decoding a UTF-8 character. TMP1 contains the first byte -of the character (>= 0xc0). Return char value in TMP1. */ -DEFINE_COMPILER; -struct sljit_jump *jump; - -sljit_emit_fast_enter(compiler, RETURN_ADDR, 0); -OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); -OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6); -OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f); -OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0); - -/* Searching for the first zero. */ -OP2U(SLJIT_AND | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, 0x800); -jump = JUMP(SLJIT_NOT_ZERO); -/* Two byte sequence. */ -OP2(SLJIT_XOR, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x3000); -OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); -OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0); - -JUMPHERE(jump); -OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1)); -OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6); -OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f); -OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0); - -OP2U(SLJIT_AND | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, 0x10000); -jump = JUMP(SLJIT_NOT_ZERO); -/* Three byte sequence. */ -OP2(SLJIT_XOR, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xe0000); -OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2)); -OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0); - -/* Four byte sequence. */ -JUMPHERE(jump); -OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(2)); -OP2(SLJIT_XOR, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xf0000); -OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(3)); -OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6); -OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f); -OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0); -OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0); -} - -static void do_utfreadtype8(compiler_common *common) -{ -/* Fast decoding a UTF-8 character type. TMP2 contains the first byte -of the character (>= 0xc0). Return value in TMP1. */ -DEFINE_COMPILER; -struct sljit_jump *jump; -struct sljit_jump *compare; - -sljit_emit_fast_enter(compiler, RETURN_ADDR, 0); - -OP2U(SLJIT_AND | SLJIT_SET_Z, TMP2, 0, SLJIT_IMM, 0x20); -jump = JUMP(SLJIT_NOT_ZERO); -/* Two byte sequence. */ -OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); -OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); -OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x1f); -/* The upper 5 bits are known at this point. */ -compare = CMP(SLJIT_GREATER, TMP2, 0, SLJIT_IMM, 0x3); -OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 6); -OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x3f); -OP2(SLJIT_OR, TMP2, 0, TMP2, 0, TMP1, 0); -OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP2), common->ctypes); -OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0); - -JUMPHERE(compare); -OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0); -OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0); - -/* We only have types for characters less than 256. */ -JUMPHERE(jump); -OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP2), (sljit_sw)PRIV(utf8_table4) - 0xc0); -OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0); -OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0); -OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0); -} - -static void do_utfreadchar_invalid(compiler_common *common) -{ -/* Slow decoding a UTF-8 character. TMP1 contains the first byte -of the character (>= 0xc0). Return char value in TMP1. STR_PTR is -undefined for invalid characters. */ -DEFINE_COMPILER; -sljit_s32 i; -sljit_s32 has_cmov = sljit_has_cpu_feature(SLJIT_HAS_CMOV); -struct sljit_jump *jump; -struct sljit_jump *buffer_end_close; -struct sljit_label *three_byte_entry; -struct sljit_label *exit_invalid_label; -struct sljit_jump *exit_invalid[11]; - -sljit_emit_fast_enter(compiler, RETURN_ADDR, 0); - -OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xc2); - -/* Usually more than 3 characters remained in the subject buffer. */ -OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(3)); - -/* Not a valid start of a multi-byte sequence, no more bytes read. */ -exit_invalid[0] = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0xf5 - 0xc2); - -buffer_end_close = CMP(SLJIT_GREATER, STR_PTR, 0, STR_END, 0); - -OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-3)); -OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6); -/* If TMP2 is in 0x80-0xbf range, TMP1 is also increased by (0x2 << 6). */ -OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP2, 0); -OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x80); -exit_invalid[1] = CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0x40); - -OP2U(SLJIT_AND | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, 0x800); -jump = JUMP(SLJIT_NOT_ZERO); - -OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2)); -OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0); - -JUMPHERE(jump); - -/* Three-byte sequence. */ -OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-2)); -OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6); -OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x80); -OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0); -if (has_cmov) - { - OP2U(SLJIT_SUB | SLJIT_SET_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0x40); - CMOV(SLJIT_GREATER_EQUAL, TMP1, SLJIT_IMM, 0x20000); - exit_invalid[2] = NULL; - } -else - exit_invalid[2] = CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0x40); - -OP2U(SLJIT_AND | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, 0x10000); -jump = JUMP(SLJIT_NOT_ZERO); - -three_byte_entry = LABEL(); - -OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x2d800); -if (has_cmov) - { - OP2U(SLJIT_SUB | SLJIT_SET_LESS, TMP1, 0, SLJIT_IMM, 0x800); - CMOV(SLJIT_LESS, TMP1, SLJIT_IMM, INVALID_UTF_CHAR - 0xd800); - exit_invalid[3] = NULL; - } -else - exit_invalid[3] = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0x800); -OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xd800); -OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - -if (has_cmov) - { - OP2U(SLJIT_SUB | SLJIT_SET_LESS, TMP1, 0, SLJIT_IMM, 0x800); - CMOV(SLJIT_LESS, TMP1, SLJIT_IMM, INVALID_UTF_CHAR); - exit_invalid[4] = NULL; - } -else - exit_invalid[4] = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0x800); -OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0); - -JUMPHERE(jump); - -/* Four-byte sequence. */ -OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-1)); -OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6); -OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x80); -OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0); -if (has_cmov) - { - OP2U(SLJIT_SUB | SLJIT_SET_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0x40); - CMOV(SLJIT_GREATER_EQUAL, TMP1, SLJIT_IMM, 0); - exit_invalid[5] = NULL; - } -else - exit_invalid[5] = CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0x40); - -OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xc10000); -if (has_cmov) - { - OP2U(SLJIT_SUB | SLJIT_SET_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0x100000); - CMOV(SLJIT_GREATER_EQUAL, TMP1, SLJIT_IMM, INVALID_UTF_CHAR - 0x10000); - exit_invalid[6] = NULL; - } -else - exit_invalid[6] = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0x100000); - -OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x10000); -OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0); - -JUMPHERE(buffer_end_close); -OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2)); -exit_invalid[7] = CMP(SLJIT_GREATER, STR_PTR, 0, STR_END, 0); - -/* Two-byte sequence. */ -OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-1)); -OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6); -/* If TMP2 is in 0x80-0xbf range, TMP1 is also increased by (0x2 << 6). */ -OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP2, 0); -OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x80); -exit_invalid[8] = CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0x40); - -OP2U(SLJIT_AND | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, 0x800); -jump = JUMP(SLJIT_NOT_ZERO); - -OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0); - -/* Three-byte sequence. */ -JUMPHERE(jump); -exit_invalid[9] = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); - -OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); -OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6); -OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x80); -OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0); -if (has_cmov) - { - OP2U(SLJIT_SUB | SLJIT_SET_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0x40); - CMOV(SLJIT_GREATER_EQUAL, TMP1, SLJIT_IMM, INVALID_UTF_CHAR); - exit_invalid[10] = NULL; - } -else - exit_invalid[10] = CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0x40); - -/* One will be substracted from STR_PTR later. */ -OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2)); - -/* Four byte sequences are not possible. */ -CMPTO(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0x30000, three_byte_entry); - -exit_invalid_label = LABEL(); -for (i = 0; i < 11; i++) - sljit_set_label(exit_invalid[i], exit_invalid_label); - -OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, INVALID_UTF_CHAR); -OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0); -} - -static void do_utfreadnewline_invalid(compiler_common *common) -{ -/* Slow decoding a UTF-8 character, specialized for newlines. -TMP1 contains the first byte of the character (>= 0xc0). Return -char value in TMP1. */ -DEFINE_COMPILER; -struct sljit_label *loop; -struct sljit_label *skip_start; -struct sljit_label *three_byte_exit; -struct sljit_jump *jump[5]; - -sljit_emit_fast_enter(compiler, RETURN_ADDR, 0); - -if (common->nltype != NLTYPE_ANY) - { - SLJIT_ASSERT(common->nltype != NLTYPE_FIXED || common->newline < 128); - - /* All newlines are ascii, just skip intermediate octets. */ - jump[0] = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); - loop = LABEL(); - if (sljit_emit_mem_update(compiler, MOV_UCHAR | SLJIT_MEM_SUPP | SLJIT_MEM_POST, TMP2, SLJIT_MEM1(STR_PTR), IN_UCHARS(1)) == SLJIT_SUCCESS) - sljit_emit_mem_update(compiler, MOV_UCHAR | SLJIT_MEM_POST, TMP2, SLJIT_MEM1(STR_PTR), IN_UCHARS(1)); - else - { - OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - } - - OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xc0); - CMPTO(SLJIT_EQUAL, TMP2, 0, SLJIT_IMM, 0x80, loop); - OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - - JUMPHERE(jump[0]); - - OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, INVALID_UTF_CHAR); - OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0); - return; - } - -jump[0] = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); -OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); -OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - -jump[1] = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0xc2); -jump[2] = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0xe2); - -skip_start = LABEL(); -OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xc0); -jump[3] = CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0x80); - -/* Skip intermediate octets. */ -loop = LABEL(); -jump[4] = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); -OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); -OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); -OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xc0); -CMPTO(SLJIT_EQUAL, TMP2, 0, SLJIT_IMM, 0x80, loop); - -JUMPHERE(jump[3]); -OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - -three_byte_exit = LABEL(); -JUMPHERE(jump[0]); -JUMPHERE(jump[4]); - -OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, INVALID_UTF_CHAR); -OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0); - -/* Two byte long newline: 0x85. */ -JUMPHERE(jump[1]); -CMPTO(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0x85, skip_start); - -OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0x85); -OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0); - -/* Three byte long newlines: 0x2028 and 0x2029. */ -JUMPHERE(jump[2]); -CMPTO(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0x80, skip_start); -CMPTO(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0, three_byte_exit); - -OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); -OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - -OP2(SLJIT_SUB, TMP1, 0, TMP2, 0, SLJIT_IMM, 0x80); -CMPTO(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0x40, skip_start); - -OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, 0x2000); -OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0); -OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0); -} - -static void do_utfmoveback_invalid(compiler_common *common) -{ -/* Goes one character back. */ -DEFINE_COMPILER; -sljit_s32 i; -struct sljit_jump *jump; -struct sljit_jump *buffer_start_close; -struct sljit_label *exit_ok_label; -struct sljit_label *exit_invalid_label; -struct sljit_jump *exit_invalid[7]; - -sljit_emit_fast_enter(compiler, RETURN_ADDR, 0); - -OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(3)); -exit_invalid[0] = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0xc0); - -/* Two-byte sequence. */ -buffer_start_close = CMP(SLJIT_LESS, STR_PTR, 0, TMP2, 0); - -OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(2)); - -OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xc0); -jump = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0x20); - -OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 1); -OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2)); -OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0); - -/* Three-byte sequence. */ -JUMPHERE(jump); -exit_invalid[1] = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, -0x40); - -OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1)); - -OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xe0); -jump = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0x10); - -OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 1); -OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); -OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0); - -/* Four-byte sequence. */ -JUMPHERE(jump); -OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xe0 - 0x80); -exit_invalid[2] = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0x40); - -OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); -OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xf0); -exit_invalid[3] = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0x05); - -exit_ok_label = LABEL(); -OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 1); -OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0); - -/* Two-byte sequence. */ -JUMPHERE(buffer_start_close); -OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2)); - -exit_invalid[4] = CMP(SLJIT_LESS, STR_PTR, 0, TMP2, 0); - -OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); - -OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xc0); -CMPTO(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0x20, exit_ok_label); - -/* Three-byte sequence. */ -OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); -exit_invalid[5] = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, -0x40); -exit_invalid[6] = CMP(SLJIT_LESS, STR_PTR, 0, TMP2, 0); - -OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); - -OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xe0); -CMPTO(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0x10, exit_ok_label); - -/* Four-byte sequences are not possible. */ - -exit_invalid_label = LABEL(); -sljit_set_label(exit_invalid[5], exit_invalid_label); -sljit_set_label(exit_invalid[6], exit_invalid_label); -OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0); -OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(3)); -OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0); - -JUMPHERE(exit_invalid[4]); -/* -2 + 4 = 2 */ -OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2)); - -exit_invalid_label = LABEL(); -for (i = 0; i < 4; i++) - sljit_set_label(exit_invalid[i], exit_invalid_label); -OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0); -OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(4)); -OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0); -} - -static void do_utfpeakcharback(compiler_common *common) -{ -/* Peak a character back. Does not modify STR_PTR. */ -DEFINE_COMPILER; -struct sljit_jump *jump[2]; - -sljit_emit_fast_enter(compiler, RETURN_ADDR, 0); - -OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-2)); -OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xc0); -jump[0] = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0x20); - -OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-3)); -OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xe0); -jump[1] = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0x10); - -OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-4)); -OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xe0 - 0x80); -OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xf0); -OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 6); -OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0); - -JUMPHERE(jump[1]); -OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-2)); -OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6); -OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x80); -OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0); - -JUMPHERE(jump[0]); -OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-1)); -OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6); -OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x80); -OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0); - -OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0); -} - -static void do_utfpeakcharback_invalid(compiler_common *common) -{ -/* Peak a character back. Does not modify STR_PTR. */ -DEFINE_COMPILER; -sljit_s32 i; -sljit_s32 has_cmov = sljit_has_cpu_feature(SLJIT_HAS_CMOV); -struct sljit_jump *jump[2]; -struct sljit_label *two_byte_entry; -struct sljit_label *three_byte_entry; -struct sljit_label *exit_invalid_label; -struct sljit_jump *exit_invalid[8]; - -sljit_emit_fast_enter(compiler, RETURN_ADDR, 0); - -OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, SLJIT_IMM, IN_UCHARS(3)); -exit_invalid[0] = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0xc0); -jump[0] = CMP(SLJIT_GREATER_EQUAL, TMP2, 0, STR_PTR, 0); - -/* Two-byte sequence. */ -OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-2)); -OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xc2); -jump[1] = CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0x1e); - -two_byte_entry = LABEL(); -OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 6); -/* If TMP1 is in 0x80-0xbf range, TMP1 is also increased by (0x2 << 6). */ -OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP2, 0); -OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0); - -JUMPHERE(jump[1]); -OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xc2 - 0x80); -OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x80); -exit_invalid[1] = CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0x40); -OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 6); -OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0); - -/* Three-byte sequence. */ -OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-3)); -OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xe0); -jump[1] = CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0x10); - -three_byte_entry = LABEL(); -OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 12); -OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0); - -OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xd800); -if (has_cmov) - { - OP2U(SLJIT_SUB | SLJIT_SET_LESS, TMP1, 0, SLJIT_IMM, 0x800); - CMOV(SLJIT_LESS, TMP1, SLJIT_IMM, -0xd800); - exit_invalid[2] = NULL; - } -else - exit_invalid[2] = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0x800); - -OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xd800); -if (has_cmov) - { - OP2U(SLJIT_SUB | SLJIT_SET_LESS, TMP1, 0, SLJIT_IMM, 0x800); - CMOV(SLJIT_LESS, TMP1, SLJIT_IMM, INVALID_UTF_CHAR); - exit_invalid[3] = NULL; - } -else - exit_invalid[3] = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0x800); - -OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0); - -JUMPHERE(jump[1]); -OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xe0 - 0x80); -exit_invalid[4] = CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0x40); -OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 12); -OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0); - -/* Four-byte sequence. */ -OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-4)); -OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x10000); -OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xf0); -OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 18); -/* ADD is used instead of OR because of the SUB 0x10000 above. */ -OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP2, 0); - -if (has_cmov) - { - OP2U(SLJIT_SUB | SLJIT_SET_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0x100000); - CMOV(SLJIT_GREATER_EQUAL, TMP1, SLJIT_IMM, INVALID_UTF_CHAR - 0x10000); - exit_invalid[5] = NULL; - } -else - exit_invalid[5] = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0x100000); - -OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x10000); -OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0); - -JUMPHERE(jump[0]); -OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, SLJIT_IMM, IN_UCHARS(1)); -jump[0] = CMP(SLJIT_GREATER_EQUAL, TMP2, 0, STR_PTR, 0); - -/* Two-byte sequence. */ -OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-2)); -OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xc2); -CMPTO(SLJIT_LESS, TMP2, 0, SLJIT_IMM, 0x1e, two_byte_entry); - -OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xc2 - 0x80); -OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x80); -exit_invalid[6] = CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0x40); -OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 6); -OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0); - -/* Three-byte sequence. */ -OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-3)); -OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xe0); -CMPTO(SLJIT_LESS, TMP2, 0, SLJIT_IMM, 0x10, three_byte_entry); - -OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, INVALID_UTF_CHAR); -OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0); - -JUMPHERE(jump[0]); -exit_invalid[7] = CMP(SLJIT_GREATER, TMP2, 0, STR_PTR, 0); - -/* Two-byte sequence. */ -OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-2)); -OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xc2); -CMPTO(SLJIT_LESS, TMP2, 0, SLJIT_IMM, 0x1e, two_byte_entry); - -exit_invalid_label = LABEL(); -for (i = 0; i < 8; i++) - sljit_set_label(exit_invalid[i], exit_invalid_label); - -OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, INVALID_UTF_CHAR); -OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0); -} - -#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */ - -#if PCRE2_CODE_UNIT_WIDTH == 16 - -static void do_utfreadchar_invalid(compiler_common *common) -{ -/* Slow decoding a UTF-16 character. TMP1 contains the first half -of the character (>= 0xd800). Return char value in TMP1. STR_PTR is -undefined for invalid characters. */ -DEFINE_COMPILER; -struct sljit_jump *exit_invalid[3]; - -sljit_emit_fast_enter(compiler, RETURN_ADDR, 0); - -/* TMP2 contains the high surrogate. */ -exit_invalid[0] = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0xdc00); -exit_invalid[1] = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); - -OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); -OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 10); -OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - -OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xdc00); -OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x10000); -exit_invalid[2] = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0x400); - -OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP2, 0); -OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0); - -JUMPHERE(exit_invalid[0]); -JUMPHERE(exit_invalid[1]); -JUMPHERE(exit_invalid[2]); -OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, INVALID_UTF_CHAR); -OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0); -} - -static void do_utfreadnewline_invalid(compiler_common *common) -{ -/* Slow decoding a UTF-16 character, specialized for newlines. -TMP1 contains the first half of the character (>= 0xd800). Return -char value in TMP1. */ - -DEFINE_COMPILER; -struct sljit_jump *exit_invalid[2]; - -sljit_emit_fast_enter(compiler, RETURN_ADDR, 0); - -/* TMP2 contains the high surrogate. */ -exit_invalid[0] = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); - -OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); -exit_invalid[1] = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0xdc00); - -OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xdc00); -OP2U(SLJIT_SUB | SLJIT_SET_LESS, TMP2, 0, SLJIT_IMM, 0x400); -OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS); -OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0x10000); -OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, UCHAR_SHIFT); -OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0); - -OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0); - -JUMPHERE(exit_invalid[0]); -JUMPHERE(exit_invalid[1]); -OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, INVALID_UTF_CHAR); -OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0); -} - -static void do_utfmoveback_invalid(compiler_common *common) -{ -/* Goes one character back. */ -DEFINE_COMPILER; -struct sljit_jump *exit_invalid[3]; - -sljit_emit_fast_enter(compiler, RETURN_ADDR, 0); - -exit_invalid[0] = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0x400); -exit_invalid[1] = CMP(SLJIT_GREATER_EQUAL, TMP2, 0, STR_PTR, 0); - -OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-1)); -OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xd800); -exit_invalid[2] = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0x400); - -OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); -OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 1); -OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0); - -JUMPHERE(exit_invalid[0]); -JUMPHERE(exit_invalid[1]); -JUMPHERE(exit_invalid[2]); - -OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); -OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0); -OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0); -} - -static void do_utfpeakcharback_invalid(compiler_common *common) -{ -/* Peak a character back. Does not modify STR_PTR. */ -DEFINE_COMPILER; -struct sljit_jump *jump; -struct sljit_jump *exit_invalid[3]; - -sljit_emit_fast_enter(compiler, RETURN_ADDR, 0); - -jump = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0xe000); -OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, SLJIT_IMM, IN_UCHARS(1)); -exit_invalid[0] = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0xdc00); -exit_invalid[1] = CMP(SLJIT_GREATER_EQUAL, TMP2, 0, STR_PTR, 0); - -OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-2)); -OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x10000 - 0xdc00); -OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xd800); -exit_invalid[2] = CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0x400); -OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 10); -OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP2, 0); - -JUMPHERE(jump); -OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0); - -JUMPHERE(exit_invalid[0]); -JUMPHERE(exit_invalid[1]); -JUMPHERE(exit_invalid[2]); - -OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, INVALID_UTF_CHAR); -OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0); -} - -#endif /* PCRE2_CODE_UNIT_WIDTH == 16 */ - -/* UCD_BLOCK_SIZE must be 128 (see the assert below). */ -#define UCD_BLOCK_MASK 127 -#define UCD_BLOCK_SHIFT 7 - -static void do_getucd(compiler_common *common) -{ -/* Search the UCD record for the character comes in TMP1. -Returns chartype in TMP1 and UCD offset in TMP2. */ -DEFINE_COMPILER; -#if PCRE2_CODE_UNIT_WIDTH == 32 -struct sljit_jump *jump; -#endif - -#if defined SLJIT_DEBUG && SLJIT_DEBUG -/* dummy_ucd_record */ -const ucd_record *record = GET_UCD(UNASSIGNED_UTF_CHAR); -SLJIT_ASSERT(record->script == ucp_Unknown && record->chartype == ucp_Cn && record->gbprop == ucp_gbOther); -SLJIT_ASSERT(record->caseset == 0 && record->other_case == 0); -#endif - -SLJIT_ASSERT(UCD_BLOCK_SIZE == 128 && sizeof(ucd_record) == 12); - -sljit_emit_fast_enter(compiler, RETURN_ADDR, 0); - -#if PCRE2_CODE_UNIT_WIDTH == 32 -if (!common->utf) - { - jump = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, MAX_UTF_CODE_POINT + 1); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, UNASSIGNED_UTF_CHAR); - JUMPHERE(jump); - } -#endif - -OP2(SLJIT_LSHR, TMP2, 0, TMP1, 0, SLJIT_IMM, UCD_BLOCK_SHIFT); -OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 1); -OP1(SLJIT_MOV_U16, TMP2, 0, SLJIT_MEM1(TMP2), (sljit_sw)PRIV(ucd_stage1)); -OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, UCD_BLOCK_MASK); -OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, UCD_BLOCK_SHIFT); -OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP2, 0); -OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, (sljit_sw)PRIV(ucd_stage2)); -OP1(SLJIT_MOV_U16, TMP2, 0, SLJIT_MEM2(TMP2, TMP1), 1); -OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0); -} - -static void do_getucdtype(compiler_common *common) -{ -/* Search the UCD record for the character comes in TMP1. -Returns chartype in TMP1 and UCD offset in TMP2. */ -DEFINE_COMPILER; -#if PCRE2_CODE_UNIT_WIDTH == 32 -struct sljit_jump *jump; -#endif - -#if defined SLJIT_DEBUG && SLJIT_DEBUG -/* dummy_ucd_record */ -const ucd_record *record = GET_UCD(UNASSIGNED_UTF_CHAR); -SLJIT_ASSERT(record->script == ucp_Unknown && record->chartype == ucp_Cn && record->gbprop == ucp_gbOther); -SLJIT_ASSERT(record->caseset == 0 && record->other_case == 0); -#endif - -SLJIT_ASSERT(UCD_BLOCK_SIZE == 128 && sizeof(ucd_record) == 12); - -sljit_emit_fast_enter(compiler, RETURN_ADDR, 0); - -#if PCRE2_CODE_UNIT_WIDTH == 32 -if (!common->utf) - { - jump = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, MAX_UTF_CODE_POINT + 1); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, UNASSIGNED_UTF_CHAR); - JUMPHERE(jump); - } -#endif - -OP2(SLJIT_LSHR, TMP2, 0, TMP1, 0, SLJIT_IMM, UCD_BLOCK_SHIFT); -OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 1); -OP1(SLJIT_MOV_U16, TMP2, 0, SLJIT_MEM1(TMP2), (sljit_sw)PRIV(ucd_stage1)); -OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, UCD_BLOCK_MASK); -OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, UCD_BLOCK_SHIFT); -OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP2, 0); -OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, (sljit_sw)PRIV(ucd_stage2)); -OP1(SLJIT_MOV_U16, TMP2, 0, SLJIT_MEM2(TMP2, TMP1), 1); - -/* TMP2 is multiplied by 12. Same as (TMP2 << 2) + ((TMP2 << 2) << 1). */ -OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, (sljit_sw)PRIV(ucd_records) + SLJIT_OFFSETOF(ucd_record, chartype)); -OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 2); -OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP2, 0); -OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM2(TMP1, TMP2), 1); - -OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0); -} - -#endif /* SUPPORT_UNICODE */ - -static SLJIT_INLINE struct sljit_label *mainloop_entry(compiler_common *common) -{ -DEFINE_COMPILER; -struct sljit_label *mainloop; -struct sljit_label *newlinelabel = NULL; -struct sljit_jump *start; -struct sljit_jump *end = NULL; -struct sljit_jump *end2 = NULL; -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 -struct sljit_label *loop; -struct sljit_jump *jump; -#endif /* SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 */ -jump_list *newline = NULL; -sljit_u32 overall_options = common->re->overall_options; -BOOL hascrorlf = (common->re->flags & PCRE2_HASCRORLF) != 0; -BOOL newlinecheck = FALSE; -BOOL readuchar = FALSE; - -if (!(hascrorlf || (overall_options & PCRE2_FIRSTLINE) != 0) - && (common->nltype == NLTYPE_ANY || common->nltype == NLTYPE_ANYCRLF || common->newline > 255)) - newlinecheck = TRUE; - -SLJIT_ASSERT(common->abort_label == NULL); - -if ((overall_options & PCRE2_FIRSTLINE) != 0) - { - /* Search for the end of the first line. */ - SLJIT_ASSERT(common->match_end_ptr != 0); - OP1(SLJIT_MOV, TMP3, 0, STR_PTR, 0); - - if (common->nltype == NLTYPE_FIXED && common->newline > 255) - { - mainloop = LABEL(); - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - end = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); - OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-1)); - OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); - CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff, mainloop); - CMPTO(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, common->newline & 0xff, mainloop); - JUMPHERE(end); - OP2(SLJIT_SUB, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - } - else - { - end = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); - mainloop = LABEL(); - /* Continual stores does not cause data dependency. */ - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr, STR_PTR, 0); - read_char(common, common->nlmin, common->nlmax, NULL, READ_CHAR_NEWLINE); - check_newlinechar(common, common->nltype, &newline, TRUE); - CMPTO(SLJIT_LESS, STR_PTR, 0, STR_END, 0, mainloop); - JUMPHERE(end); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr, STR_PTR, 0); - set_jumps(newline, LABEL()); - } - - OP1(SLJIT_MOV, STR_PTR, 0, TMP3, 0); - } -else if ((overall_options & PCRE2_USE_OFFSET_LIMIT) != 0) - { - /* Check whether offset limit is set and valid. */ - SLJIT_ASSERT(common->match_end_ptr != 0); - - if (HAS_VIRTUAL_REGISTERS) - { - OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, offset_limit)); - } - else - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, offset_limit)); - - OP1(SLJIT_MOV, TMP2, 0, STR_END, 0); - end = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, (sljit_sw) PCRE2_UNSET); - if (HAS_VIRTUAL_REGISTERS) - OP1(SLJIT_MOV, TMP2, 0, ARGUMENTS, 0); - else - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, begin)); - -#if PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32 - OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, UCHAR_SHIFT); -#endif /* PCRE2_CODE_UNIT_WIDTH == [16|32] */ - if (HAS_VIRTUAL_REGISTERS) - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, begin)); - - OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, TMP1, 0); - end2 = CMP(SLJIT_LESS_EQUAL, TMP2, 0, STR_END, 0); - OP1(SLJIT_MOV, TMP2, 0, STR_END, 0); - JUMPHERE(end2); - OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE2_ERROR_NOMATCH); - add_jump(compiler, &common->abort, CMP(SLJIT_LESS, TMP2, 0, STR_PTR, 0)); - JUMPHERE(end); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr, TMP2, 0); - } - -start = JUMP(SLJIT_JUMP); - -if (newlinecheck) - { - newlinelabel = LABEL(); - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - end = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); - OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0); - OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, common->newline & 0xff); - OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_EQUAL); -#if PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32 - OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, UCHAR_SHIFT); -#endif /* PCRE2_CODE_UNIT_WIDTH == [16|32] */ - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0); - end2 = JUMP(SLJIT_JUMP); - } - -mainloop = LABEL(); - -/* Increasing the STR_PTR here requires one less jump in the most common case. */ -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 -if (common->utf && !common->invalid_utf) readuchar = TRUE; -#endif /* SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 */ -if (newlinecheck) readuchar = TRUE; - -if (readuchar) - OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0); - -if (newlinecheck) - CMPTO(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff, newlinelabel); - -OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 -#if PCRE2_CODE_UNIT_WIDTH == 8 -if (common->invalid_utf) - { - /* Skip continuation code units. */ - loop = LABEL(); - jump = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); - OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0); - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x80); - CMPTO(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0x40, loop); - OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - JUMPHERE(jump); - } -else if (common->utf) - { - jump = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0xc0); - OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0); - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0); - JUMPHERE(jump); - } -#elif PCRE2_CODE_UNIT_WIDTH == 16 -if (common->invalid_utf) - { - /* Skip continuation code units. */ - loop = LABEL(); - jump = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); - OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0); - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xdc00); - CMPTO(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0x400, loop); - OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - JUMPHERE(jump); - } -else if (common->utf) - { - OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xd800); - - if (sljit_has_cpu_feature(SLJIT_HAS_CMOV)) - { - OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - OP2U(SLJIT_SUB | SLJIT_SET_LESS, TMP1, 0, SLJIT_IMM, 0x400); - CMOV(SLJIT_LESS, STR_PTR, TMP2, 0); - } - else - { - OP2U(SLJIT_SUB | SLJIT_SET_LESS, TMP1, 0, SLJIT_IMM, 0x400); - OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_LESS); - OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, UCHAR_SHIFT); - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0); - } - } -#endif /* PCRE2_CODE_UNIT_WIDTH == [8|16] */ -#endif /* SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 */ -JUMPHERE(start); - -if (newlinecheck) - { - JUMPHERE(end); - JUMPHERE(end2); - } - -return mainloop; -} - - -static SLJIT_INLINE void add_prefix_char(PCRE2_UCHAR chr, fast_forward_char_data *chars, BOOL last) -{ -sljit_u32 i, count = chars->count; - -if (count == 255) - return; - -if (count == 0) - { - chars->count = 1; - chars->chars[0] = chr; - - if (last) - chars->last_count = 1; - return; - } - -for (i = 0; i < count; i++) - if (chars->chars[i] == chr) - return; - -if (count >= MAX_DIFF_CHARS) - { - chars->count = 255; - return; - } - -chars->chars[count] = chr; -chars->count = count + 1; - -if (last) - chars->last_count++; -} - -static int scan_prefix(compiler_common *common, PCRE2_SPTR cc, fast_forward_char_data *chars, int max_chars, sljit_u32 *rec_count) -{ -/* Recursive function, which scans prefix literals. */ -BOOL last, any, class, caseless; -int len, repeat, len_save, consumed = 0; -sljit_u32 chr; /* Any unicode character. */ -sljit_u8 *bytes, *bytes_end, byte; -PCRE2_SPTR alternative, cc_save, oc; -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8 -PCRE2_UCHAR othercase[4]; -#elif defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 16 -PCRE2_UCHAR othercase[2]; -#else -PCRE2_UCHAR othercase[1]; -#endif - -repeat = 1; -while (TRUE) - { - if (*rec_count == 0) - return 0; - (*rec_count)--; - - last = TRUE; - any = FALSE; - class = FALSE; - caseless = FALSE; - - switch (*cc) - { - case OP_CHARI: - caseless = TRUE; - /* Fall through */ - case OP_CHAR: - last = FALSE; - cc++; - break; - - case OP_SOD: - case OP_SOM: - case OP_SET_SOM: - case OP_NOT_WORD_BOUNDARY: - case OP_WORD_BOUNDARY: - case OP_EODN: - case OP_EOD: - case OP_CIRC: - case OP_CIRCM: - case OP_DOLL: - case OP_DOLLM: - /* Zero width assertions. */ - cc++; - continue; - - case OP_ASSERT: - case OP_ASSERT_NOT: - case OP_ASSERTBACK: - case OP_ASSERTBACK_NOT: - case OP_ASSERT_NA: - case OP_ASSERTBACK_NA: - cc = bracketend(cc); - continue; - - case OP_PLUSI: - case OP_MINPLUSI: - case OP_POSPLUSI: - caseless = TRUE; - /* Fall through */ - case OP_PLUS: - case OP_MINPLUS: - case OP_POSPLUS: - cc++; - break; - - case OP_EXACTI: - caseless = TRUE; - /* Fall through */ - case OP_EXACT: - repeat = GET2(cc, 1); - last = FALSE; - cc += 1 + IMM2_SIZE; - break; - - case OP_QUERYI: - case OP_MINQUERYI: - case OP_POSQUERYI: - caseless = TRUE; - /* Fall through */ - case OP_QUERY: - case OP_MINQUERY: - case OP_POSQUERY: - len = 1; - cc++; -#ifdef SUPPORT_UNICODE - if (common->utf && HAS_EXTRALEN(*cc)) len += GET_EXTRALEN(*cc); -#endif - max_chars = scan_prefix(common, cc + len, chars, max_chars, rec_count); - if (max_chars == 0) - return consumed; - last = FALSE; - break; - - case OP_KET: - cc += 1 + LINK_SIZE; - continue; - - case OP_ALT: - cc += GET(cc, 1); - continue; - - case OP_ONCE: - case OP_BRA: - case OP_BRAPOS: - case OP_CBRA: - case OP_CBRAPOS: - alternative = cc + GET(cc, 1); - while (*alternative == OP_ALT) - { - max_chars = scan_prefix(common, alternative + 1 + LINK_SIZE, chars, max_chars, rec_count); - if (max_chars == 0) - return consumed; - alternative += GET(alternative, 1); - } - - if (*cc == OP_CBRA || *cc == OP_CBRAPOS) - cc += IMM2_SIZE; - cc += 1 + LINK_SIZE; - continue; - - case OP_CLASS: -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8 - if (common->utf && !is_char7_bitset((const sljit_u8 *)(cc + 1), FALSE)) - return consumed; -#endif - class = TRUE; - break; - - case OP_NCLASS: -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 - if (common->utf) return consumed; -#endif - class = TRUE; - break; - -#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8 - case OP_XCLASS: -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 - if (common->utf) return consumed; -#endif - any = TRUE; - cc += GET(cc, 1); - break; -#endif - - case OP_DIGIT: -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8 - if (common->utf && !is_char7_bitset((const sljit_u8 *)common->ctypes - cbit_length + cbit_digit, FALSE)) - return consumed; -#endif - any = TRUE; - cc++; - break; - - case OP_WHITESPACE: -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8 - if (common->utf && !is_char7_bitset((const sljit_u8 *)common->ctypes - cbit_length + cbit_space, FALSE)) - return consumed; -#endif - any = TRUE; - cc++; - break; - - case OP_WORDCHAR: -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8 - if (common->utf && !is_char7_bitset((const sljit_u8 *)common->ctypes - cbit_length + cbit_word, FALSE)) - return consumed; -#endif - any = TRUE; - cc++; - break; - - case OP_NOT: - case OP_NOTI: - cc++; - /* Fall through. */ - case OP_NOT_DIGIT: - case OP_NOT_WHITESPACE: - case OP_NOT_WORDCHAR: - case OP_ANY: - case OP_ALLANY: -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 - if (common->utf) return consumed; -#endif - any = TRUE; - cc++; - break; - -#ifdef SUPPORT_UNICODE - case OP_NOTPROP: - case OP_PROP: -#if PCRE2_CODE_UNIT_WIDTH != 32 - if (common->utf) return consumed; -#endif - any = TRUE; - cc += 1 + 2; - break; -#endif - - case OP_TYPEEXACT: - repeat = GET2(cc, 1); - cc += 1 + IMM2_SIZE; - continue; - - case OP_NOTEXACT: - case OP_NOTEXACTI: -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 - if (common->utf) return consumed; -#endif - any = TRUE; - repeat = GET2(cc, 1); - cc += 1 + IMM2_SIZE + 1; - break; - - default: - return consumed; - } - - if (any) - { - do - { - chars->count = 255; - - consumed++; - if (--max_chars == 0) - return consumed; - chars++; - } - while (--repeat > 0); - - repeat = 1; - continue; - } - - if (class) - { - bytes = (sljit_u8*) (cc + 1); - cc += 1 + 32 / sizeof(PCRE2_UCHAR); - - switch (*cc) - { - case OP_CRSTAR: - case OP_CRMINSTAR: - case OP_CRPOSSTAR: - case OP_CRQUERY: - case OP_CRMINQUERY: - case OP_CRPOSQUERY: - max_chars = scan_prefix(common, cc + 1, chars, max_chars, rec_count); - if (max_chars == 0) - return consumed; - break; - - default: - case OP_CRPLUS: - case OP_CRMINPLUS: - case OP_CRPOSPLUS: - break; - - case OP_CRRANGE: - case OP_CRMINRANGE: - case OP_CRPOSRANGE: - repeat = GET2(cc, 1); - if (repeat <= 0) - return consumed; - break; - } - - do - { - if (bytes[31] & 0x80) - chars->count = 255; - else if (chars->count != 255) - { - bytes_end = bytes + 32; - chr = 0; - do - { - byte = *bytes++; - SLJIT_ASSERT((chr & 0x7) == 0); - if (byte == 0) - chr += 8; - else - { - do - { - if ((byte & 0x1) != 0) - add_prefix_char(chr, chars, TRUE); - byte >>= 1; - chr++; - } - while (byte != 0); - chr = (chr + 7) & ~7; - } - } - while (chars->count != 255 && bytes < bytes_end); - bytes = bytes_end - 32; - } - - consumed++; - if (--max_chars == 0) - return consumed; - chars++; - } - while (--repeat > 0); - - switch (*cc) - { - case OP_CRSTAR: - case OP_CRMINSTAR: - case OP_CRPOSSTAR: - return consumed; - - case OP_CRQUERY: - case OP_CRMINQUERY: - case OP_CRPOSQUERY: - cc++; - break; - - case OP_CRRANGE: - case OP_CRMINRANGE: - case OP_CRPOSRANGE: - if (GET2(cc, 1) != GET2(cc, 1 + IMM2_SIZE)) - return consumed; - cc += 1 + 2 * IMM2_SIZE; - break; - } - - repeat = 1; - continue; - } - - len = 1; -#ifdef SUPPORT_UNICODE - if (common->utf && HAS_EXTRALEN(*cc)) len += GET_EXTRALEN(*cc); -#endif - - if (caseless && char_has_othercase(common, cc)) - { -#ifdef SUPPORT_UNICODE - if (common->utf) - { - GETCHAR(chr, cc); - if ((int)PRIV(ord2utf)(char_othercase(common, chr), othercase) != len) - return consumed; - } - else -#endif - { - chr = *cc; -#ifdef SUPPORT_UNICODE - if (common->ucp && chr > 127) - othercase[0] = UCD_OTHERCASE(chr); - else -#endif - othercase[0] = TABLE_GET(chr, common->fcc, chr); - } - } - else - { - caseless = FALSE; - othercase[0] = 0; /* Stops compiler warning - PH */ - } - - len_save = len; - cc_save = cc; - while (TRUE) - { - oc = othercase; - do - { - len--; - consumed++; - - chr = *cc; - add_prefix_char(*cc, chars, len == 0); - - if (caseless) - add_prefix_char(*oc, chars, len == 0); - - if (--max_chars == 0) - return consumed; - chars++; - cc++; - oc++; - } - while (len > 0); - - if (--repeat == 0) - break; - - len = len_save; - cc = cc_save; - } - - repeat = 1; - if (last) - return consumed; - } -} - -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 -static void jumpto_if_not_utf_char_start(struct sljit_compiler *compiler, sljit_s32 reg, struct sljit_label *label) -{ -#if PCRE2_CODE_UNIT_WIDTH == 8 -OP2(SLJIT_AND, reg, 0, reg, 0, SLJIT_IMM, 0xc0); -CMPTO(SLJIT_EQUAL, reg, 0, SLJIT_IMM, 0x80, label); -#elif PCRE2_CODE_UNIT_WIDTH == 16 -OP2(SLJIT_AND, reg, 0, reg, 0, SLJIT_IMM, 0xfc00); -CMPTO(SLJIT_EQUAL, reg, 0, SLJIT_IMM, 0xdc00, label); -#else -#error "Unknown code width" -#endif -} -#endif - -#include "pcre2_jit_simd_inc.h" - -#ifdef JIT_HAS_FAST_FORWARD_CHAR_PAIR_SIMD - -static BOOL check_fast_forward_char_pair_simd(compiler_common *common, fast_forward_char_data *chars, int max) -{ - sljit_s32 i, j, max_i = 0, max_j = 0; - sljit_u32 max_pri = 0; - PCRE2_UCHAR a1, a2, a_pri, b1, b2, b_pri; - - for (i = max - 1; i >= 1; i--) - { - if (chars[i].last_count > 2) - { - a1 = chars[i].chars[0]; - a2 = chars[i].chars[1]; - a_pri = chars[i].last_count; - - j = i - max_fast_forward_char_pair_offset(); - if (j < 0) - j = 0; - - while (j < i) - { - b_pri = chars[j].last_count; - if (b_pri > 2 && (sljit_u32)a_pri + (sljit_u32)b_pri >= max_pri) - { - b1 = chars[j].chars[0]; - b2 = chars[j].chars[1]; - - if (a1 != b1 && a1 != b2 && a2 != b1 && a2 != b2) - { - max_pri = a_pri + b_pri; - max_i = i; - max_j = j; - } - } - j++; - } - } - } - -if (max_pri == 0) - return FALSE; - -fast_forward_char_pair_simd(common, max_i, chars[max_i].chars[0], chars[max_i].chars[1], max_j, chars[max_j].chars[0], chars[max_j].chars[1]); -return TRUE; -} - -#endif /* JIT_HAS_FAST_FORWARD_CHAR_PAIR_SIMD */ - -static void fast_forward_first_char2(compiler_common *common, PCRE2_UCHAR char1, PCRE2_UCHAR char2, sljit_s32 offset) -{ -DEFINE_COMPILER; -struct sljit_label *start; -struct sljit_jump *match; -struct sljit_jump *partial_quit; -PCRE2_UCHAR mask; -BOOL has_match_end = (common->match_end_ptr != 0); - -SLJIT_ASSERT(common->mode == PCRE2_JIT_COMPLETE || offset == 0); - -if (has_match_end) - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr); - -if (offset > 0) - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(offset)); - -if (has_match_end) - { - OP1(SLJIT_MOV, TMP3, 0, STR_END, 0); - - OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(offset + 1)); - OP2U(SLJIT_SUB | SLJIT_SET_GREATER, STR_END, 0, TMP1, 0); - CMOV(SLJIT_GREATER, STR_END, TMP1, 0); - } - -#ifdef JIT_HAS_FAST_FORWARD_CHAR_SIMD - -if (JIT_HAS_FAST_FORWARD_CHAR_SIMD) - { - fast_forward_char_simd(common, char1, char2, offset); - - if (offset > 0) - OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(offset)); - - if (has_match_end) - OP1(SLJIT_MOV, STR_END, 0, TMP3, 0); - return; - } - -#endif - -start = LABEL(); - -partial_quit = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); -if (common->mode == PCRE2_JIT_COMPLETE) - add_jump(compiler, &common->failed_match, partial_quit); - -OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0); -OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - -if (char1 == char2) - CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, char1, start); -else - { - mask = char1 ^ char2; - if (is_powerof2(mask)) - { - OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, mask); - CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, char1 | mask, start); - } - else - { - match = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, char1); - CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, char2, start); - JUMPHERE(match); - } - } - -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 -if (common->utf && offset > 0) - { - OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-(offset + 1))); - jumpto_if_not_utf_char_start(compiler, TMP1, start); - } -#endif - -OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(offset + 1)); - -if (common->mode != PCRE2_JIT_COMPLETE) - JUMPHERE(partial_quit); - -if (has_match_end) - OP1(SLJIT_MOV, STR_END, 0, TMP3, 0); -} - -static SLJIT_INLINE BOOL fast_forward_first_n_chars(compiler_common *common) -{ -DEFINE_COMPILER; -struct sljit_label *start; -struct sljit_jump *match; -fast_forward_char_data chars[MAX_N_CHARS]; -sljit_s32 offset; -PCRE2_UCHAR mask; -PCRE2_UCHAR *char_set, *char_set_end; -int i, max, from; -int range_right = -1, range_len; -sljit_u8 *update_table = NULL; -BOOL in_range; -sljit_u32 rec_count; - -for (i = 0; i < MAX_N_CHARS; i++) - { - chars[i].count = 0; - chars[i].last_count = 0; - } - -rec_count = 10000; -max = scan_prefix(common, common->start, chars, MAX_N_CHARS, &rec_count); - -if (max < 1) - return FALSE; - -/* Convert last_count to priority. */ -for (i = 0; i < max; i++) - { - SLJIT_ASSERT(chars[i].count > 0 && chars[i].last_count <= chars[i].count); - - if (chars[i].count == 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) - { - 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 - chars[i].last_count = (chars[i].count == 255) ? 0 : 1; - } - -#ifdef JIT_HAS_FAST_FORWARD_CHAR_PAIR_SIMD -if (JIT_HAS_FAST_FORWARD_CHAR_PAIR_SIMD && check_fast_forward_char_pair_simd(common, chars, max)) - return TRUE; -#endif - -in_range = FALSE; -/* Prevent compiler "uninitialized" warning */ -from = 0; -range_len = 4 /* minimum length */ - 1; -for (i = 0; i <= max; i++) - { - if (in_range && (i - from) > range_len && (chars[i - 1].count < 255)) - { - range_len = i - from; - range_right = i - 1; - } - - if (i < max && chars[i].count < 255) - { - SLJIT_ASSERT(chars[i].count > 0); - if (!in_range) - { - in_range = TRUE; - from = i; - } - } - else - in_range = FALSE; - } - -if (range_right >= 0) - { - update_table = (sljit_u8 *)allocate_read_only_data(common, 256); - if (update_table == NULL) - return TRUE; - memset(update_table, IN_UCHARS(range_len), 256); - - for (i = 0; i < range_len; i++) - { - SLJIT_ASSERT(chars[range_right - i].count > 0 && chars[range_right - i].count < 255); - - char_set = chars[range_right - i].chars; - char_set_end = char_set + chars[range_right - i].count; - do - { - if (update_table[(*char_set) & 0xff] > IN_UCHARS(i)) - update_table[(*char_set) & 0xff] = IN_UCHARS(i); - char_set++; - } - while (char_set < char_set_end); - } - } - -offset = -1; -/* Scan forward. */ -for (i = 0; i < max; i++) - { - if (range_right == i) - continue; - - if (offset == -1) - { - if (chars[i].last_count >= 2) - offset = i; - } - else if (chars[offset].last_count < chars[i].last_count) - offset = i; - } - -SLJIT_ASSERT(offset == -1 || (chars[offset].count >= 1 && chars[offset].count <= 2)); - -if (range_right < 0) - { - if (offset < 0) - return FALSE; - /* Works regardless the value is 1 or 2. */ - fast_forward_first_char2(common, chars[offset].chars[0], chars[offset].chars[1], offset); - return TRUE; - } - -SLJIT_ASSERT(range_right != offset); - -if (common->match_end_ptr != 0) - { - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr); - OP1(SLJIT_MOV, TMP3, 0, STR_END, 0); - OP2(SLJIT_SUB | SLJIT_SET_LESS, STR_END, 0, STR_END, 0, SLJIT_IMM, IN_UCHARS(max)); - add_jump(compiler, &common->failed_match, JUMP(SLJIT_LESS)); - OP2U(SLJIT_SUB | SLJIT_SET_GREATER, STR_END, 0, TMP1, 0); - CMOV(SLJIT_GREATER, STR_END, TMP1, 0); - } -else - { - OP2(SLJIT_SUB | SLJIT_SET_LESS, STR_END, 0, STR_END, 0, SLJIT_IMM, IN_UCHARS(max)); - add_jump(compiler, &common->failed_match, JUMP(SLJIT_LESS)); - } - -SLJIT_ASSERT(range_right >= 0); - -if (!HAS_VIRTUAL_REGISTERS) - OP1(SLJIT_MOV, RETURN_ADDR, 0, SLJIT_IMM, (sljit_sw)update_table); - -start = LABEL(); -add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER, STR_PTR, 0, STR_END, 0)); - -#if PCRE2_CODE_UNIT_WIDTH == 8 || (defined SLJIT_LITTLE_ENDIAN && SLJIT_LITTLE_ENDIAN) -OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(range_right)); -#else -OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(range_right + 1) - 1); -#endif - -if (!HAS_VIRTUAL_REGISTERS) - OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM2(RETURN_ADDR, TMP1), 0); -else - OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)update_table); - -OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0); -CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, 0, start); - -if (offset >= 0) - { - OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(offset)); - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - - if (chars[offset].count == 1) - CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, chars[offset].chars[0], start); - else - { - mask = chars[offset].chars[0] ^ chars[offset].chars[1]; - if (is_powerof2(mask)) - { - OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, mask); - CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, chars[offset].chars[0] | mask, start); - } - else - { - match = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, chars[offset].chars[0]); - CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, chars[offset].chars[1], start); - JUMPHERE(match); - } - } - } - -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 -if (common->utf && offset != 0) - { - if (offset < 0) - { - OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0); - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - } - else - OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-1)); - - jumpto_if_not_utf_char_start(compiler, TMP1, start); - - if (offset < 0) - OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - } -#endif - -if (offset >= 0) - OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - -if (common->match_end_ptr != 0) - OP1(SLJIT_MOV, STR_END, 0, TMP3, 0); -else - OP2(SLJIT_ADD, STR_END, 0, STR_END, 0, SLJIT_IMM, IN_UCHARS(max)); -return TRUE; -} - -static SLJIT_INLINE void fast_forward_first_char(compiler_common *common) -{ -PCRE2_UCHAR first_char = (PCRE2_UCHAR)(common->re->first_codeunit); -PCRE2_UCHAR oc; - -oc = first_char; -if ((common->re->flags & PCRE2_FIRSTCASELESS) != 0) - { - oc = TABLE_GET(first_char, common->fcc, first_char); -#if defined SUPPORT_UNICODE - if (first_char > 127 && (common->utf || common->ucp)) - oc = UCD_OTHERCASE(first_char); -#endif - } - -fast_forward_first_char2(common, first_char, oc, 0); -} - -static SLJIT_INLINE void fast_forward_newline(compiler_common *common) -{ -DEFINE_COMPILER; -struct sljit_label *loop; -struct sljit_jump *lastchar = NULL; -struct sljit_jump *firstchar; -struct sljit_jump *quit = NULL; -struct sljit_jump *foundcr = NULL; -struct sljit_jump *notfoundnl; -jump_list *newline = NULL; - -if (common->match_end_ptr != 0) - { - OP1(SLJIT_MOV, TMP3, 0, STR_END, 0); - OP1(SLJIT_MOV, STR_END, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr); - } - -if (common->nltype == NLTYPE_FIXED && common->newline > 255) - { -#ifdef JIT_HAS_FAST_FORWARD_CHAR_PAIR_SIMD - if (JIT_HAS_FAST_FORWARD_CHAR_PAIR_SIMD && common->mode == PCRE2_JIT_COMPLETE) - { - if (HAS_VIRTUAL_REGISTERS) - { - OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0); - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, str)); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, begin)); - } - else - { - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, str)); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, begin)); - } - firstchar = CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, TMP2, 0); - - OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - OP2U(SLJIT_SUB | SLJIT_SET_Z, STR_PTR, 0, TMP1, 0); - OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_NOT_EQUAL); -#if PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32 - OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, UCHAR_SHIFT); -#endif - OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP1, 0); - - fast_forward_char_pair_simd(common, 1, common->newline & 0xff, common->newline & 0xff, 0, (common->newline >> 8) & 0xff, (common->newline >> 8) & 0xff); - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2)); - } - else -#endif /* JIT_HAS_FAST_FORWARD_CHAR_PAIR_SIMD */ - { - lastchar = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); - if (HAS_VIRTUAL_REGISTERS) - { - OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0); - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, str)); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, begin)); - } - else - { - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, str)); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, begin)); - } - firstchar = CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, TMP2, 0); - - OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(2)); - OP2U(SLJIT_SUB | SLJIT_SET_GREATER_EQUAL, STR_PTR, 0, TMP1, 0); - OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_GREATER_EQUAL); -#if PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32 - OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, UCHAR_SHIFT); -#endif - OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0); - - loop = LABEL(); - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - quit = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); - OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-2)); - OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-1)); - CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff, loop); - CMPTO(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, common->newline & 0xff, loop); - - JUMPHERE(quit); - JUMPHERE(lastchar); - } - - JUMPHERE(firstchar); - - if (common->match_end_ptr != 0) - OP1(SLJIT_MOV, STR_END, 0, TMP3, 0); - return; - } - -if (HAS_VIRTUAL_REGISTERS) - { - OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0); - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, str)); - } -else - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, str)); - -/* Example: match /^/ to \r\n from offset 1. */ -firstchar = CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, TMP2, 0); - -if (common->nltype == NLTYPE_ANY) - move_back(common, NULL, FALSE); -else - OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - -loop = LABEL(); -common->ff_newline_shortcut = loop; - -#ifdef JIT_HAS_FAST_FORWARD_CHAR_SIMD -if (JIT_HAS_FAST_FORWARD_CHAR_SIMD && (common->nltype == NLTYPE_FIXED || common->nltype == NLTYPE_ANYCRLF)) - { - if (common->nltype == NLTYPE_ANYCRLF) - { - fast_forward_char_simd(common, CHAR_CR, CHAR_LF, 0); - if (common->mode != PCRE2_JIT_COMPLETE) - lastchar = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); - - OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0); - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - quit = CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_CR); - } - else - { - fast_forward_char_simd(common, common->newline, common->newline, 0); - - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - if (common->mode != PCRE2_JIT_COMPLETE) - { - OP2U(SLJIT_SUB | SLJIT_SET_GREATER, STR_PTR, 0, STR_END, 0); - CMOV(SLJIT_GREATER, STR_PTR, STR_END, 0); - } - } - } -else -#endif /* JIT_HAS_FAST_FORWARD_CHAR_SIMD */ - { - read_char(common, common->nlmin, common->nlmax, NULL, READ_CHAR_NEWLINE); - lastchar = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); - if (common->nltype == NLTYPE_ANY || common->nltype == NLTYPE_ANYCRLF) - foundcr = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_CR); - check_newlinechar(common, common->nltype, &newline, FALSE); - set_jumps(newline, loop); - } - -if (common->nltype == NLTYPE_ANY || common->nltype == NLTYPE_ANYCRLF) - { - if (quit == NULL) - { - quit = JUMP(SLJIT_JUMP); - JUMPHERE(foundcr); - } - - notfoundnl = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); - OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0); - OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, CHAR_NL); - OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_EQUAL); -#if PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32 - OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, UCHAR_SHIFT); -#endif - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0); - JUMPHERE(notfoundnl); - JUMPHERE(quit); - } - -if (lastchar) - JUMPHERE(lastchar); -JUMPHERE(firstchar); - -if (common->match_end_ptr != 0) - OP1(SLJIT_MOV, STR_END, 0, TMP3, 0); -} - -static BOOL optimize_class(compiler_common *common, const sljit_u8 *bits, BOOL nclass, BOOL invert, jump_list **backtracks); - -static SLJIT_INLINE void fast_forward_start_bits(compiler_common *common) -{ -DEFINE_COMPILER; -const sljit_u8 *start_bits = common->re->start_bitmap; -struct sljit_label *start; -struct sljit_jump *partial_quit; -#if PCRE2_CODE_UNIT_WIDTH != 8 -struct sljit_jump *found = NULL; -#endif -jump_list *matches = NULL; - -if (common->match_end_ptr != 0) - { - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr); - OP1(SLJIT_MOV, RETURN_ADDR, 0, STR_END, 0); - OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(1)); - OP2U(SLJIT_SUB | SLJIT_SET_GREATER, STR_END, 0, TMP1, 0); - CMOV(SLJIT_GREATER, STR_END, TMP1, 0); - } - -start = LABEL(); - -partial_quit = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); -if (common->mode == PCRE2_JIT_COMPLETE) - add_jump(compiler, &common->failed_match, partial_quit); - -OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0); -OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - -if (!optimize_class(common, start_bits, (start_bits[31] & 0x80) != 0, FALSE, &matches)) - { -#if PCRE2_CODE_UNIT_WIDTH != 8 - if ((start_bits[31] & 0x80) != 0) - found = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 255); - else - CMPTO(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 255, start); -#elif defined SUPPORT_UNICODE - if (common->utf && is_char7_bitset(start_bits, FALSE)) - CMPTO(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, 127, start); -#endif - OP2(SLJIT_AND, TMP2, 0, TMP1, 0, SLJIT_IMM, 0x7); - OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, SLJIT_IMM, 3); - OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)start_bits); - if (!HAS_VIRTUAL_REGISTERS) - { - OP2(SLJIT_SHL, TMP3, 0, SLJIT_IMM, 1, TMP2, 0); - OP2U(SLJIT_AND | SLJIT_SET_Z, TMP1, 0, TMP3, 0); - } - else - { - OP2(SLJIT_SHL, TMP2, 0, SLJIT_IMM, 1, TMP2, 0); - OP2U(SLJIT_AND | SLJIT_SET_Z, TMP1, 0, TMP2, 0); - } - JUMPTO(SLJIT_ZERO, start); - } -else - set_jumps(matches, start); - -#if PCRE2_CODE_UNIT_WIDTH != 8 -if (found != NULL) - JUMPHERE(found); -#endif - -OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - -if (common->mode != PCRE2_JIT_COMPLETE) - JUMPHERE(partial_quit); - -if (common->match_end_ptr != 0) - OP1(SLJIT_MOV, STR_END, 0, RETURN_ADDR, 0); -} - -static SLJIT_INLINE jump_list *search_requested_char(compiler_common *common, PCRE2_UCHAR req_char, BOOL caseless, BOOL has_firstchar) -{ -DEFINE_COMPILER; -struct sljit_label *loop; -struct sljit_jump *toolong; -struct sljit_jump *already_found; -struct sljit_jump *found; -struct sljit_jump *found_oc = NULL; -jump_list *not_found = NULL; -sljit_u32 oc, bit; - -SLJIT_ASSERT(common->req_char_ptr != 0); -OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(REQ_CU_MAX) * 100); -OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->req_char_ptr); -toolong = CMP(SLJIT_LESS, TMP2, 0, STR_END, 0); -already_found = CMP(SLJIT_LESS, STR_PTR, 0, TMP1, 0); - -if (has_firstchar) - OP2(SLJIT_ADD, TMP1, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); -else - OP1(SLJIT_MOV, TMP1, 0, STR_PTR, 0); - -oc = req_char; -if (caseless) - { - oc = TABLE_GET(req_char, common->fcc, req_char); -#if defined SUPPORT_UNICODE - if (req_char > 127 && (common->utf || common->ucp)) - oc = UCD_OTHERCASE(req_char); -#endif - } - -#ifdef JIT_HAS_FAST_REQUESTED_CHAR_SIMD -if (JIT_HAS_FAST_REQUESTED_CHAR_SIMD) - { - not_found = fast_requested_char_simd(common, req_char, oc); - } -else -#endif - { - loop = LABEL(); - add_jump(compiler, ¬_found, CMP(SLJIT_GREATER_EQUAL, TMP1, 0, STR_END, 0)); - - OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(TMP1), 0); - - if (req_char == oc) - found = CMP(SLJIT_EQUAL, TMP2, 0, SLJIT_IMM, req_char); - else - { - bit = req_char ^ oc; - if (is_powerof2(bit)) - { - OP2(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_IMM, bit); - found = CMP(SLJIT_EQUAL, TMP2, 0, SLJIT_IMM, req_char | bit); - } - else - { - found = CMP(SLJIT_EQUAL, TMP2, 0, SLJIT_IMM, req_char); - found_oc = CMP(SLJIT_EQUAL, TMP2, 0, SLJIT_IMM, oc); - } - } - OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(1)); - JUMPTO(SLJIT_JUMP, loop); - - JUMPHERE(found); - if (found_oc) - JUMPHERE(found_oc); - } - -OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->req_char_ptr, TMP1, 0); - -JUMPHERE(already_found); -JUMPHERE(toolong); -return not_found; -} - -static void do_revertframes(compiler_common *common) -{ -DEFINE_COMPILER; -struct sljit_jump *jump; -struct sljit_label *mainloop; - -sljit_emit_fast_enter(compiler, RETURN_ADDR, 0); -GET_LOCAL_BASE(TMP1, 0, 0); - -/* Drop frames until we reach STACK_TOP. */ -mainloop = LABEL(); -OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), -SSIZE_OF(sw)); -jump = CMP(SLJIT_SIG_LESS_EQUAL, TMP2, 0, SLJIT_IMM, 0); - -OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, TMP1, 0); -if (HAS_VIRTUAL_REGISTERS) - { - OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), 0, SLJIT_MEM1(STACK_TOP), -(2 * SSIZE_OF(sw))); - OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), sizeof(sljit_sw), SLJIT_MEM1(STACK_TOP), -(3 * SSIZE_OF(sw))); - OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, 3 * SSIZE_OF(sw)); - } -else - { - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), -(2 * SSIZE_OF(sw))); - OP1(SLJIT_MOV, TMP3, 0, SLJIT_MEM1(STACK_TOP), -(3 * SSIZE_OF(sw))); - OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, 3 * SSIZE_OF(sw)); - OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), 0, TMP1, 0); - GET_LOCAL_BASE(TMP1, 0, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), sizeof(sljit_sw), TMP3, 0); - } -JUMPTO(SLJIT_JUMP, mainloop); - -JUMPHERE(jump); -jump = CMP(SLJIT_NOT_ZERO /* SIG_LESS */, TMP2, 0, SLJIT_IMM, 0); -/* End of reverting values. */ -OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0); - -JUMPHERE(jump); -OP2(SLJIT_SUB, TMP2, 0, SLJIT_IMM, 0, TMP2, 0); -OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, TMP1, 0); -if (HAS_VIRTUAL_REGISTERS) - { - OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), 0, SLJIT_MEM1(STACK_TOP), -(2 * SSIZE_OF(sw))); - OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, 2 * SSIZE_OF(sw)); - } -else - { - OP1(SLJIT_MOV, TMP3, 0, SLJIT_MEM1(STACK_TOP), -(2 * SSIZE_OF(sw))); - OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, 2 * SSIZE_OF(sw)); - OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), 0, TMP3, 0); - } -JUMPTO(SLJIT_JUMP, mainloop); -} - -static void check_wordboundary(compiler_common *common) -{ -DEFINE_COMPILER; -struct sljit_jump *skipread; -jump_list *skipread_list = NULL; -#ifdef SUPPORT_UNICODE -struct sljit_label *valid_utf; -jump_list *invalid_utf1 = NULL; -#endif /* SUPPORT_UNICODE */ -jump_list *invalid_utf2 = NULL; -#if PCRE2_CODE_UNIT_WIDTH != 8 || defined SUPPORT_UNICODE -struct sljit_jump *jump; -#endif /* PCRE2_CODE_UNIT_WIDTH != 8 || SUPPORT_UNICODE */ - -SLJIT_COMPILE_ASSERT(ctype_word == 0x10, ctype_word_must_be_16); - -sljit_emit_fast_enter(compiler, SLJIT_MEM1(SLJIT_SP), LOCALS0); -/* Get type of the previous char, and put it to TMP3. */ -OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0); -OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, begin)); -OP1(SLJIT_MOV, TMP3, 0, SLJIT_IMM, 0); -skipread = CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, TMP2, 0); - -#ifdef SUPPORT_UNICODE -if (common->invalid_utf) - { - peek_char_back(common, READ_CHAR_MAX, &invalid_utf1); - - if (common->mode != PCRE2_JIT_COMPLETE) - { - OP1(SLJIT_MOV, RETURN_ADDR, 0, TMP1, 0); - OP1(SLJIT_MOV, TMP2, 0, STR_PTR, 0); - move_back(common, NULL, TRUE); - check_start_used_ptr(common); - OP1(SLJIT_MOV, TMP1, 0, RETURN_ADDR, 0); - OP1(SLJIT_MOV, STR_PTR, 0, TMP2, 0); - } - } -else -#endif /* SUPPORT_UNICODE */ - { - if (common->mode == PCRE2_JIT_COMPLETE) - peek_char_back(common, READ_CHAR_MAX, NULL); - else - { - move_back(common, NULL, TRUE); - check_start_used_ptr(common); - read_char(common, 0, READ_CHAR_MAX, NULL, READ_CHAR_UPDATE_STR_PTR); - } - } - -/* Testing char type. */ -#ifdef SUPPORT_UNICODE -if (common->ucp) - { - OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, 1); - jump = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_UNDERSCORE); - add_jump(compiler, &common->getucdtype, JUMP(SLJIT_FAST_CALL)); - OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ucp_Ll); - OP2U(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, TMP1, 0, SLJIT_IMM, ucp_Lu - ucp_Ll); - OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL); - OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ucp_Nd - ucp_Ll); - OP2U(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, TMP1, 0, SLJIT_IMM, ucp_No - ucp_Nd); - OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_LESS_EQUAL); - JUMPHERE(jump); - OP1(SLJIT_MOV, TMP3, 0, TMP2, 0); - } -else -#endif /* SUPPORT_UNICODE */ - { -#if PCRE2_CODE_UNIT_WIDTH != 8 - jump = CMP(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, 255); -#elif defined SUPPORT_UNICODE - /* Here TMP3 has already been zeroed. */ - jump = NULL; - if (common->utf) - jump = CMP(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, 255); -#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */ - OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), common->ctypes); - OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, SLJIT_IMM, 4 /* ctype_word */); - OP2(SLJIT_AND, TMP3, 0, TMP1, 0, SLJIT_IMM, 1); -#if PCRE2_CODE_UNIT_WIDTH != 8 - JUMPHERE(jump); -#elif defined SUPPORT_UNICODE - if (jump != NULL) - JUMPHERE(jump); -#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */ - } -JUMPHERE(skipread); - -OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, 0); -check_str_end(common, &skipread_list); -peek_char(common, READ_CHAR_MAX, SLJIT_MEM1(SLJIT_SP), LOCALS1, &invalid_utf2); - -/* Testing char type. This is a code duplication. */ -#ifdef SUPPORT_UNICODE - -valid_utf = LABEL(); - -if (common->ucp) - { - OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, 1); - jump = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_UNDERSCORE); - add_jump(compiler, &common->getucdtype, JUMP(SLJIT_FAST_CALL)); - OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ucp_Ll); - OP2U(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, TMP1, 0, SLJIT_IMM, ucp_Lu - ucp_Ll); - OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL); - OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ucp_Nd - ucp_Ll); - OP2U(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, TMP1, 0, SLJIT_IMM, ucp_No - ucp_Nd); - OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_LESS_EQUAL); - JUMPHERE(jump); - } -else -#endif /* SUPPORT_UNICODE */ - { -#if PCRE2_CODE_UNIT_WIDTH != 8 - /* TMP2 may be destroyed by peek_char. */ - OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, 0); - jump = CMP(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, 255); -#elif defined SUPPORT_UNICODE - OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, 0); - jump = NULL; - if (common->utf) - jump = CMP(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, 255); -#endif - OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP1), common->ctypes); - OP2(SLJIT_LSHR, TMP2, 0, TMP2, 0, SLJIT_IMM, 4 /* ctype_word */); - OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 1); -#if PCRE2_CODE_UNIT_WIDTH != 8 - JUMPHERE(jump); -#elif defined SUPPORT_UNICODE - if (jump != NULL) - JUMPHERE(jump); -#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */ - } -set_jumps(skipread_list, LABEL()); - -OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0); -OP2(SLJIT_XOR | SLJIT_SET_Z, TMP2, 0, TMP2, 0, TMP3, 0); -OP_SRC(SLJIT_FAST_RETURN, TMP1, 0); - -#ifdef SUPPORT_UNICODE -if (common->invalid_utf) - { - set_jumps(invalid_utf1, LABEL()); - - peek_char(common, READ_CHAR_MAX, SLJIT_MEM1(SLJIT_SP), LOCALS1, NULL); - CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, INVALID_UTF_CHAR, valid_utf); - - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0); - OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, -1); - OP_SRC(SLJIT_FAST_RETURN, TMP1, 0); - - set_jumps(invalid_utf2, LABEL()); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0); - OP1(SLJIT_MOV, TMP2, 0, TMP3, 0); - OP_SRC(SLJIT_FAST_RETURN, TMP1, 0); - } -#endif /* SUPPORT_UNICODE */ -} - -static BOOL optimize_class_ranges(compiler_common *common, const sljit_u8 *bits, BOOL nclass, BOOL invert, jump_list **backtracks) -{ -/* May destroy TMP1. */ -DEFINE_COMPILER; -int ranges[MAX_CLASS_RANGE_SIZE]; -sljit_u8 bit, cbit, all; -int i, byte, length = 0; - -bit = bits[0] & 0x1; -/* All bits will be zero or one (since bit is zero or one). */ -all = -bit; - -for (i = 0; i < 256; ) - { - byte = i >> 3; - if ((i & 0x7) == 0 && bits[byte] == all) - i += 8; - else - { - cbit = (bits[byte] >> (i & 0x7)) & 0x1; - if (cbit != bit) - { - if (length >= MAX_CLASS_RANGE_SIZE) - return FALSE; - ranges[length] = i; - length++; - bit = cbit; - all = -cbit; - } - i++; - } - } - -if (((bit == 0) && nclass) || ((bit == 1) && !nclass)) - { - if (length >= MAX_CLASS_RANGE_SIZE) - return FALSE; - ranges[length] = 256; - length++; - } - -if (length < 0 || length > 4) - return FALSE; - -bit = bits[0] & 0x1; -if (invert) bit ^= 0x1; - -/* No character is accepted. */ -if (length == 0 && bit == 0) - add_jump(compiler, backtracks, JUMP(SLJIT_JUMP)); - -switch(length) - { - case 0: - /* When bit != 0, all characters are accepted. */ - return TRUE; - - case 1: - add_jump(compiler, backtracks, CMP(bit == 0 ? SLJIT_LESS : SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, ranges[0])); - return TRUE; - - case 2: - if (ranges[0] + 1 != ranges[1]) - { - OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ranges[0]); - add_jump(compiler, backtracks, CMP(bit != 0 ? SLJIT_LESS : SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, ranges[1] - ranges[0])); - } - else - add_jump(compiler, backtracks, CMP(bit != 0 ? SLJIT_EQUAL : SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, ranges[0])); - return TRUE; - - case 3: - if (bit != 0) - { - add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, ranges[2])); - if (ranges[0] + 1 != ranges[1]) - { - OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ranges[0]); - add_jump(compiler, backtracks, CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, ranges[1] - ranges[0])); - } - else - add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, ranges[0])); - return TRUE; - } - - add_jump(compiler, backtracks, CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, ranges[0])); - if (ranges[1] + 1 != ranges[2]) - { - OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ranges[1]); - add_jump(compiler, backtracks, CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, ranges[2] - ranges[1])); - } - else - add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, ranges[1])); - return TRUE; - - case 4: - if ((ranges[1] - ranges[0]) == (ranges[3] - ranges[2]) - && (ranges[0] | (ranges[2] - ranges[0])) == ranges[2] - && (ranges[1] & (ranges[2] - ranges[0])) == 0 - && is_powerof2(ranges[2] - ranges[0])) - { - SLJIT_ASSERT((ranges[0] & (ranges[2] - ranges[0])) == 0 && (ranges[2] & ranges[3] & (ranges[2] - ranges[0])) != 0); - OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, ranges[2] - ranges[0]); - if (ranges[2] + 1 != ranges[3]) - { - OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ranges[2]); - add_jump(compiler, backtracks, CMP(bit != 0 ? SLJIT_LESS : SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, ranges[3] - ranges[2])); - } - else - add_jump(compiler, backtracks, CMP(bit != 0 ? SLJIT_EQUAL : SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, ranges[2])); - return TRUE; - } - - if (bit != 0) - { - i = 0; - if (ranges[0] + 1 != ranges[1]) - { - OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ranges[0]); - add_jump(compiler, backtracks, CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, ranges[1] - ranges[0])); - i = ranges[0]; - } - else - add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, ranges[0])); - - if (ranges[2] + 1 != ranges[3]) - { - OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ranges[2] - i); - add_jump(compiler, backtracks, CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, ranges[3] - ranges[2])); - } - else - add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, ranges[2] - i)); - return TRUE; - } - - OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ranges[0]); - add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, ranges[3] - ranges[0])); - if (ranges[1] + 1 != ranges[2]) - { - OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ranges[1] - ranges[0]); - add_jump(compiler, backtracks, CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, ranges[2] - ranges[1])); - } - else - add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, ranges[1] - ranges[0])); - return TRUE; - - default: - SLJIT_UNREACHABLE(); - return FALSE; - } -} - -static BOOL optimize_class_chars(compiler_common *common, const sljit_u8 *bits, BOOL nclass, BOOL invert, jump_list **backtracks) -{ -/* May destroy TMP1. */ -DEFINE_COMPILER; -uint16_t char_list[MAX_CLASS_CHARS_SIZE]; -uint8_t byte; -sljit_s32 type; -int i, j, k, len, c; - -if (!sljit_has_cpu_feature(SLJIT_HAS_CMOV)) - return FALSE; - -len = 0; - -for (i = 0; i < 32; i++) - { - byte = bits[i]; - - if (nclass) - byte = ~byte; - - j = 0; - while (byte != 0) - { - if (byte & 0x1) - { - c = i * 8 + j; - - k = len; - - if ((c & 0x20) != 0) - { - for (k = 0; k < len; k++) - if (char_list[k] == c - 0x20) - { - char_list[k] |= 0x120; - break; - } - } - - if (k == len) - { - if (len >= MAX_CLASS_CHARS_SIZE) - return FALSE; - - char_list[len++] = (uint16_t) c; - } - } - - byte >>= 1; - j++; - } - } - -if (len == 0) return FALSE; /* Should never occur, but stops analyzers complaining. */ - -i = 0; -j = 0; - -if (char_list[0] == 0) - { - i++; - OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, 0); - OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_ZERO); - } -else - OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, 0); - -while (i < len) - { - if ((char_list[i] & 0x100) != 0) - j++; - else - { - OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, char_list[i]); - CMOV(SLJIT_ZERO, TMP2, TMP1, 0); - } - i++; - } - -if (j != 0) - { - OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x20); - - for (i = 0; i < len; i++) - if ((char_list[i] & 0x100) != 0) - { - j--; - OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, char_list[i] & 0xff); - CMOV(SLJIT_ZERO, TMP2, TMP1, 0); - } - } - -if (invert) - nclass = !nclass; - -type = nclass ? SLJIT_NOT_EQUAL : SLJIT_EQUAL; -add_jump(compiler, backtracks, CMP(type, TMP2, 0, SLJIT_IMM, 0)); -return TRUE; -} - -static BOOL optimize_class(compiler_common *common, const sljit_u8 *bits, BOOL nclass, BOOL invert, jump_list **backtracks) -{ -/* May destroy TMP1. */ -if (optimize_class_ranges(common, bits, nclass, invert, backtracks)) - return TRUE; -return optimize_class_chars(common, bits, nclass, invert, backtracks); -} - -static void check_anynewline(compiler_common *common) -{ -/* Check whether TMP1 contains a newline character. TMP2 destroyed. */ -DEFINE_COMPILER; - -sljit_emit_fast_enter(compiler, RETURN_ADDR, 0); - -OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x0a); -OP2U(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, TMP1, 0, SLJIT_IMM, 0x0d - 0x0a); -OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL); -OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, 0x85 - 0x0a); -#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32 -#if PCRE2_CODE_UNIT_WIDTH == 8 -if (common->utf) - { -#endif - OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); - OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x1); - OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, 0x2029 - 0x0a); -#if PCRE2_CODE_UNIT_WIDTH == 8 - } -#endif -#endif /* SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH == [16|32] */ -OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_EQUAL); -OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0); -} - -static void check_hspace(compiler_common *common) -{ -/* Check whether TMP1 contains a newline character. TMP2 destroyed. */ -DEFINE_COMPILER; - -sljit_emit_fast_enter(compiler, RETURN_ADDR, 0); - -OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, 0x09); -OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_EQUAL); -OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, 0x20); -OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); -OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, 0xa0); -#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32 -#if PCRE2_CODE_UNIT_WIDTH == 8 -if (common->utf) - { -#endif - OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); - OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, 0x1680); - OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); - OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, 0x180e); - OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); - OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x2000); - OP2U(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, TMP1, 0, SLJIT_IMM, 0x200A - 0x2000); - OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_LESS_EQUAL); - OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, 0x202f - 0x2000); - OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); - OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, 0x205f - 0x2000); - OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); - OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, 0x3000 - 0x2000); -#if PCRE2_CODE_UNIT_WIDTH == 8 - } -#endif -#endif /* SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH == [16|32] */ -OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_EQUAL); - -OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0); -} - -static void check_vspace(compiler_common *common) -{ -/* Check whether TMP1 contains a newline character. TMP2 destroyed. */ -DEFINE_COMPILER; - -sljit_emit_fast_enter(compiler, RETURN_ADDR, 0); - -OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x0a); -OP2U(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, TMP1, 0, SLJIT_IMM, 0x0d - 0x0a); -OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL); -OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, 0x85 - 0x0a); -#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32 -#if PCRE2_CODE_UNIT_WIDTH == 8 -if (common->utf) - { -#endif - OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); - OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x1); - OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, 0x2029 - 0x0a); -#if PCRE2_CODE_UNIT_WIDTH == 8 - } -#endif -#endif /* SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH == [16|32] */ -OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_EQUAL); - -OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0); -} - -static void do_casefulcmp(compiler_common *common) -{ -DEFINE_COMPILER; -struct sljit_jump *jump; -struct sljit_label *label; -int char1_reg; -int char2_reg; - -if (HAS_VIRTUAL_REGISTERS) - { - char1_reg = STR_END; - char2_reg = STACK_TOP; - } -else - { - char1_reg = TMP3; - char2_reg = RETURN_ADDR; - } - -sljit_emit_fast_enter(compiler, SLJIT_MEM1(SLJIT_SP), LOCALS0); -OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0); - -if (char1_reg == STR_END) - { - OP1(SLJIT_MOV, TMP3, 0, char1_reg, 0); - OP1(SLJIT_MOV, RETURN_ADDR, 0, char2_reg, 0); - } - -if (sljit_emit_mem_update(compiler, MOV_UCHAR | SLJIT_MEM_SUPP | SLJIT_MEM_POST, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1)) == SLJIT_SUCCESS) - { - label = LABEL(); - sljit_emit_mem_update(compiler, MOV_UCHAR | SLJIT_MEM_POST, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1)); - sljit_emit_mem_update(compiler, MOV_UCHAR | SLJIT_MEM_POST, char2_reg, SLJIT_MEM1(STR_PTR), IN_UCHARS(1)); - jump = CMP(SLJIT_NOT_EQUAL, char1_reg, 0, char2_reg, 0); - OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, TMP2, 0, SLJIT_IMM, IN_UCHARS(1)); - JUMPTO(SLJIT_NOT_ZERO, label); - - JUMPHERE(jump); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0); - } -else if (sljit_emit_mem_update(compiler, MOV_UCHAR | SLJIT_MEM_SUPP | SLJIT_MEM_PRE, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1)) == SLJIT_SUCCESS) - { - OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(1)); - OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - - label = LABEL(); - sljit_emit_mem_update(compiler, MOV_UCHAR | SLJIT_MEM_PRE, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1)); - sljit_emit_mem_update(compiler, MOV_UCHAR | SLJIT_MEM_PRE, char2_reg, SLJIT_MEM1(STR_PTR), IN_UCHARS(1)); - jump = CMP(SLJIT_NOT_EQUAL, char1_reg, 0, char2_reg, 0); - OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, TMP2, 0, SLJIT_IMM, IN_UCHARS(1)); - JUMPTO(SLJIT_NOT_ZERO, label); - - JUMPHERE(jump); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0); - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - } -else - { - label = LABEL(); - OP1(MOV_UCHAR, char1_reg, 0, SLJIT_MEM1(TMP1), 0); - OP1(MOV_UCHAR, char2_reg, 0, SLJIT_MEM1(STR_PTR), 0); - OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(1)); - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - jump = CMP(SLJIT_NOT_EQUAL, char1_reg, 0, char2_reg, 0); - OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, TMP2, 0, SLJIT_IMM, IN_UCHARS(1)); - JUMPTO(SLJIT_NOT_ZERO, label); - - JUMPHERE(jump); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0); - } - -if (char1_reg == STR_END) - { - OP1(SLJIT_MOV, char1_reg, 0, TMP3, 0); - OP1(SLJIT_MOV, char2_reg, 0, RETURN_ADDR, 0); - } - -OP_SRC(SLJIT_FAST_RETURN, TMP1, 0); -} - -static void do_caselesscmp(compiler_common *common) -{ -DEFINE_COMPILER; -struct sljit_jump *jump; -struct sljit_label *label; -int char1_reg = STR_END; -int char2_reg; -int lcc_table; -int opt_type = 0; - -if (HAS_VIRTUAL_REGISTERS) - { - char2_reg = STACK_TOP; - lcc_table = STACK_LIMIT; - } -else - { - char2_reg = RETURN_ADDR; - lcc_table = TMP3; - } - -if (sljit_emit_mem_update(compiler, MOV_UCHAR | SLJIT_MEM_SUPP | SLJIT_MEM_POST, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1)) == SLJIT_SUCCESS) - opt_type = 1; -else if (sljit_emit_mem_update(compiler, MOV_UCHAR | SLJIT_MEM_SUPP | SLJIT_MEM_PRE, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1)) == SLJIT_SUCCESS) - opt_type = 2; - -sljit_emit_fast_enter(compiler, SLJIT_MEM1(SLJIT_SP), LOCALS0); -OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0); - -OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS1, char1_reg, 0); - -if (char2_reg == STACK_TOP) - { - OP1(SLJIT_MOV, TMP3, 0, char2_reg, 0); - OP1(SLJIT_MOV, RETURN_ADDR, 0, lcc_table, 0); - } - -OP1(SLJIT_MOV, lcc_table, 0, SLJIT_IMM, common->lcc); - -if (opt_type == 1) - { - label = LABEL(); - sljit_emit_mem_update(compiler, MOV_UCHAR | SLJIT_MEM_POST, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1)); - sljit_emit_mem_update(compiler, MOV_UCHAR | SLJIT_MEM_POST, char2_reg, SLJIT_MEM1(STR_PTR), IN_UCHARS(1)); - } -else if (opt_type == 2) - { - OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(1)); - OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - - label = LABEL(); - sljit_emit_mem_update(compiler, MOV_UCHAR | SLJIT_MEM_PRE, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1)); - sljit_emit_mem_update(compiler, MOV_UCHAR | SLJIT_MEM_PRE, char2_reg, SLJIT_MEM1(STR_PTR), IN_UCHARS(1)); - } -else - { - label = LABEL(); - OP1(MOV_UCHAR, char1_reg, 0, SLJIT_MEM1(TMP1), 0); - OP1(MOV_UCHAR, char2_reg, 0, SLJIT_MEM1(STR_PTR), 0); - OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(1)); - } - -#if PCRE2_CODE_UNIT_WIDTH != 8 -jump = CMP(SLJIT_GREATER, char1_reg, 0, SLJIT_IMM, 255); -#endif -OP1(SLJIT_MOV_U8, char1_reg, 0, SLJIT_MEM2(lcc_table, char1_reg), 0); -#if PCRE2_CODE_UNIT_WIDTH != 8 -JUMPHERE(jump); -jump = CMP(SLJIT_GREATER, char2_reg, 0, SLJIT_IMM, 255); -#endif -OP1(SLJIT_MOV_U8, char2_reg, 0, SLJIT_MEM2(lcc_table, char2_reg), 0); -#if PCRE2_CODE_UNIT_WIDTH != 8 -JUMPHERE(jump); -#endif - -if (opt_type == 0) - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - -jump = CMP(SLJIT_NOT_EQUAL, char1_reg, 0, char2_reg, 0); -OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, TMP2, 0, SLJIT_IMM, IN_UCHARS(1)); -JUMPTO(SLJIT_NOT_ZERO, label); - -JUMPHERE(jump); -OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0); - -if (opt_type == 2) - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - -if (char2_reg == STACK_TOP) - { - OP1(SLJIT_MOV, char2_reg, 0, TMP3, 0); - OP1(SLJIT_MOV, lcc_table, 0, RETURN_ADDR, 0); - } - -OP1(SLJIT_MOV, char1_reg, 0, SLJIT_MEM1(SLJIT_SP), LOCALS1); -OP_SRC(SLJIT_FAST_RETURN, TMP1, 0); -} - -static PCRE2_SPTR byte_sequence_compare(compiler_common *common, BOOL caseless, PCRE2_SPTR cc, - compare_context *context, jump_list **backtracks) -{ -DEFINE_COMPILER; -unsigned int othercasebit = 0; -PCRE2_SPTR othercasechar = NULL; -#ifdef SUPPORT_UNICODE -int utflength; -#endif - -if (caseless && char_has_othercase(common, cc)) - { - othercasebit = char_get_othercase_bit(common, cc); - SLJIT_ASSERT(othercasebit); - /* Extracting bit difference info. */ -#if PCRE2_CODE_UNIT_WIDTH == 8 - othercasechar = cc + (othercasebit >> 8); - othercasebit &= 0xff; -#elif PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32 - /* Note that this code only handles characters in the BMP. If there - ever are characters outside the BMP whose othercase differs in only one - bit from itself (there currently are none), this code will need to be - revised for PCRE2_CODE_UNIT_WIDTH == 32. */ - othercasechar = cc + (othercasebit >> 9); - if ((othercasebit & 0x100) != 0) - othercasebit = (othercasebit & 0xff) << 8; - else - othercasebit &= 0xff; -#endif /* PCRE2_CODE_UNIT_WIDTH == [8|16|32] */ - } - -if (context->sourcereg == -1) - { -#if PCRE2_CODE_UNIT_WIDTH == 8 -#if defined SLJIT_UNALIGNED && SLJIT_UNALIGNED - if (context->length >= 4) - OP1(SLJIT_MOV_S32, TMP1, 0, SLJIT_MEM1(STR_PTR), -context->length); - else if (context->length >= 2) - OP1(SLJIT_MOV_U16, TMP1, 0, SLJIT_MEM1(STR_PTR), -context->length); - else -#endif - OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), -context->length); -#elif PCRE2_CODE_UNIT_WIDTH == 16 -#if defined SLJIT_UNALIGNED && SLJIT_UNALIGNED - if (context->length >= 4) - OP1(SLJIT_MOV_S32, TMP1, 0, SLJIT_MEM1(STR_PTR), -context->length); - else -#endif - OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), -context->length); -#elif PCRE2_CODE_UNIT_WIDTH == 32 - OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), -context->length); -#endif /* PCRE2_CODE_UNIT_WIDTH == [8|16|32] */ - context->sourcereg = TMP2; - } - -#ifdef SUPPORT_UNICODE -utflength = 1; -if (common->utf && HAS_EXTRALEN(*cc)) - utflength += GET_EXTRALEN(*cc); - -do - { -#endif - - context->length -= IN_UCHARS(1); -#if (defined SLJIT_UNALIGNED && SLJIT_UNALIGNED) && (PCRE2_CODE_UNIT_WIDTH == 8 || PCRE2_CODE_UNIT_WIDTH == 16) - - /* Unaligned read is supported. */ - if (othercasebit != 0 && othercasechar == cc) - { - context->c.asuchars[context->ucharptr] = *cc | othercasebit; - context->oc.asuchars[context->ucharptr] = othercasebit; - } - else - { - context->c.asuchars[context->ucharptr] = *cc; - context->oc.asuchars[context->ucharptr] = 0; - } - context->ucharptr++; - -#if PCRE2_CODE_UNIT_WIDTH == 8 - if (context->ucharptr >= 4 || context->length == 0 || (context->ucharptr == 2 && context->length == 1)) -#else - if (context->ucharptr >= 2 || context->length == 0) -#endif - { - if (context->length >= 4) - OP1(SLJIT_MOV_S32, context->sourcereg, 0, SLJIT_MEM1(STR_PTR), -context->length); - else if (context->length >= 2) - OP1(SLJIT_MOV_U16, context->sourcereg, 0, SLJIT_MEM1(STR_PTR), -context->length); -#if PCRE2_CODE_UNIT_WIDTH == 8 - else if (context->length >= 1) - OP1(SLJIT_MOV_U8, context->sourcereg, 0, SLJIT_MEM1(STR_PTR), -context->length); -#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */ - context->sourcereg = context->sourcereg == TMP1 ? TMP2 : TMP1; - - switch(context->ucharptr) - { - case 4 / sizeof(PCRE2_UCHAR): - if (context->oc.asint != 0) - OP2(SLJIT_OR, context->sourcereg, 0, context->sourcereg, 0, SLJIT_IMM, context->oc.asint); - add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, context->sourcereg, 0, SLJIT_IMM, context->c.asint | context->oc.asint)); - break; - - case 2 / sizeof(PCRE2_UCHAR): - if (context->oc.asushort != 0) - OP2(SLJIT_OR, context->sourcereg, 0, context->sourcereg, 0, SLJIT_IMM, context->oc.asushort); - add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, context->sourcereg, 0, SLJIT_IMM, context->c.asushort | context->oc.asushort)); - break; - -#if PCRE2_CODE_UNIT_WIDTH == 8 - case 1: - if (context->oc.asbyte != 0) - OP2(SLJIT_OR, context->sourcereg, 0, context->sourcereg, 0, SLJIT_IMM, context->oc.asbyte); - add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, context->sourcereg, 0, SLJIT_IMM, context->c.asbyte | context->oc.asbyte)); - break; -#endif - - default: - SLJIT_UNREACHABLE(); - break; - } - context->ucharptr = 0; - } - -#else - - /* Unaligned read is unsupported or in 32 bit mode. */ - if (context->length >= 1) - OP1(MOV_UCHAR, context->sourcereg, 0, SLJIT_MEM1(STR_PTR), -context->length); - - context->sourcereg = context->sourcereg == TMP1 ? TMP2 : TMP1; - - if (othercasebit != 0 && othercasechar == cc) - { - OP2(SLJIT_OR, context->sourcereg, 0, context->sourcereg, 0, SLJIT_IMM, othercasebit); - add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, context->sourcereg, 0, SLJIT_IMM, *cc | othercasebit)); - } - else - add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, context->sourcereg, 0, SLJIT_IMM, *cc)); - -#endif - - cc++; -#ifdef SUPPORT_UNICODE - utflength--; - } -while (utflength > 0); -#endif - -return cc; -} - -#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8 - -#define SET_TYPE_OFFSET(value) \ - if ((value) != typeoffset) \ - { \ - if ((value) < typeoffset) \ - OP2(SLJIT_ADD, typereg, 0, typereg, 0, SLJIT_IMM, typeoffset - (value)); \ - else \ - OP2(SLJIT_SUB, typereg, 0, typereg, 0, SLJIT_IMM, (value) - typeoffset); \ - } \ - typeoffset = (value); - -#define SET_CHAR_OFFSET(value) \ - if ((value) != charoffset) \ - { \ - if ((value) < charoffset) \ - OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(charoffset - (value))); \ - else \ - OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)((value) - charoffset)); \ - } \ - charoffset = (value); - -static PCRE2_SPTR compile_char1_matchingpath(compiler_common *common, PCRE2_UCHAR type, PCRE2_SPTR cc, jump_list **backtracks, BOOL check_str_ptr); - -#ifdef SUPPORT_UNICODE -#define XCLASS_SAVE_CHAR 0x001 -#define XCLASS_CHAR_SAVED 0x002 -#define XCLASS_HAS_TYPE 0x004 -#define XCLASS_HAS_SCRIPT 0x008 -#define XCLASS_HAS_SCRIPT_EXTENSION 0x010 -#define XCLASS_HAS_BOOL 0x020 -#define XCLASS_HAS_BIDICL 0x040 -#define XCLASS_NEEDS_UCD (XCLASS_HAS_TYPE | XCLASS_HAS_SCRIPT | XCLASS_HAS_SCRIPT_EXTENSION | XCLASS_HAS_BOOL | XCLASS_HAS_BIDICL) -#define XCLASS_SCRIPT_EXTENSION_NOTPROP 0x080 -#define XCLASS_SCRIPT_EXTENSION_RESTORE_RETURN_ADDR 0x100 -#define XCLASS_SCRIPT_EXTENSION_RESTORE_LOCALS0 0x200 - -#endif /* SUPPORT_UNICODE */ - -static void compile_xclass_matchingpath(compiler_common *common, PCRE2_SPTR cc, jump_list **backtracks) -{ -DEFINE_COMPILER; -jump_list *found = NULL; -jump_list **list = (cc[0] & XCL_NOT) == 0 ? &found : backtracks; -sljit_uw c, charoffset, max = 256, min = READ_CHAR_MAX; -struct sljit_jump *jump = NULL; -PCRE2_SPTR ccbegin; -int compares, invertcmp, numberofcmps; -#if defined SUPPORT_UNICODE && (PCRE2_CODE_UNIT_WIDTH == 8 || PCRE2_CODE_UNIT_WIDTH == 16) -BOOL utf = common->utf; -#endif /* SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == [8|16] */ - -#ifdef SUPPORT_UNICODE -sljit_u32 unicode_status = 0; -int typereg = TMP1; -const sljit_u32 *other_cases; -sljit_uw typeoffset; -#endif /* SUPPORT_UNICODE */ - -/* Scanning the necessary info. */ -cc++; -ccbegin = cc; -compares = 0; - -if (cc[-1] & XCL_MAP) - { - min = 0; - cc += 32 / sizeof(PCRE2_UCHAR); - } - -while (*cc != XCL_END) - { - compares++; - if (*cc == XCL_SINGLE) - { - cc ++; - GETCHARINCTEST(c, cc); - if (c > max) max = c; - if (c < min) min = c; -#ifdef SUPPORT_UNICODE - unicode_status |= XCLASS_SAVE_CHAR; -#endif /* SUPPORT_UNICODE */ - } - else if (*cc == XCL_RANGE) - { - cc ++; - GETCHARINCTEST(c, cc); - if (c < min) min = c; - GETCHARINCTEST(c, cc); - if (c > max) max = c; -#ifdef SUPPORT_UNICODE - unicode_status |= XCLASS_SAVE_CHAR; -#endif /* SUPPORT_UNICODE */ - } -#ifdef SUPPORT_UNICODE - else - { - SLJIT_ASSERT(*cc == XCL_PROP || *cc == XCL_NOTPROP); - cc++; - if (*cc == PT_CLIST && cc[-1] == XCL_PROP) - { - other_cases = PRIV(ucd_caseless_sets) + cc[1]; - while (*other_cases != NOTACHAR) - { - if (*other_cases > max) max = *other_cases; - if (*other_cases < min) min = *other_cases; - other_cases++; - } - } - else - { - max = READ_CHAR_MAX; - min = 0; - } - - switch(*cc) - { - case PT_ANY: - /* Any either accepts everything or ignored. */ - if (cc[-1] == XCL_PROP) - { - compile_char1_matchingpath(common, OP_ALLANY, cc, backtracks, FALSE); - if (list == backtracks) - add_jump(compiler, backtracks, JUMP(SLJIT_JUMP)); - return; - } - break; - - case PT_LAMP: - case PT_GC: - case PT_PC: - case PT_ALNUM: - unicode_status |= XCLASS_HAS_TYPE; - break; - - case PT_SCX: - unicode_status |= XCLASS_HAS_SCRIPT_EXTENSION; - if (cc[-1] == XCL_NOTPROP) - { - unicode_status |= XCLASS_SCRIPT_EXTENSION_NOTPROP; - break; - } - compares++; - /* Fall through */ - - case PT_SC: - unicode_status |= XCLASS_HAS_SCRIPT; - break; - - case PT_SPACE: - case PT_PXSPACE: - case PT_WORD: - case PT_PXGRAPH: - case PT_PXPRINT: - case PT_PXPUNCT: - unicode_status |= XCLASS_SAVE_CHAR | XCLASS_HAS_TYPE; - break; - - case PT_CLIST: - case PT_UCNC: - unicode_status |= XCLASS_SAVE_CHAR; - break; - - case PT_BOOL: - unicode_status |= XCLASS_HAS_BOOL; - break; - - case PT_BIDICL: - unicode_status |= XCLASS_HAS_BIDICL; - break; - - default: - SLJIT_UNREACHABLE(); - break; - } - cc += 2; - } -#endif /* SUPPORT_UNICODE */ - } -SLJIT_ASSERT(compares > 0); - -/* We are not necessary in utf mode even in 8 bit mode. */ -cc = ccbegin; -if ((cc[-1] & XCL_NOT) != 0) - read_char(common, min, max, backtracks, READ_CHAR_UPDATE_STR_PTR); -else - { -#ifdef SUPPORT_UNICODE - read_char(common, min, max, (unicode_status & XCLASS_NEEDS_UCD) ? backtracks : NULL, 0); -#else /* !SUPPORT_UNICODE */ - read_char(common, min, max, NULL, 0); -#endif /* SUPPORT_UNICODE */ - } - -if ((cc[-1] & XCL_HASPROP) == 0) - { - if ((cc[-1] & XCL_MAP) != 0) - { - jump = CMP(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, 255); - if (!optimize_class(common, (const sljit_u8 *)cc, (((const sljit_u8 *)cc)[31] & 0x80) != 0, TRUE, &found)) - { - OP2(SLJIT_AND, TMP2, 0, TMP1, 0, SLJIT_IMM, 0x7); - OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, SLJIT_IMM, 3); - OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)cc); - OP2(SLJIT_SHL, TMP2, 0, SLJIT_IMM, 1, TMP2, 0); - OP2U(SLJIT_AND | SLJIT_SET_Z, TMP1, 0, TMP2, 0); - add_jump(compiler, &found, JUMP(SLJIT_NOT_ZERO)); - } - - add_jump(compiler, backtracks, JUMP(SLJIT_JUMP)); - JUMPHERE(jump); - - cc += 32 / sizeof(PCRE2_UCHAR); - } - else - { - OP2(SLJIT_SUB, TMP2, 0, TMP1, 0, SLJIT_IMM, min); - add_jump(compiler, (cc[-1] & XCL_NOT) == 0 ? backtracks : &found, CMP(SLJIT_GREATER, TMP2, 0, SLJIT_IMM, max - min)); - } - } -else if ((cc[-1] & XCL_MAP) != 0) - { - OP1(SLJIT_MOV, RETURN_ADDR, 0, TMP1, 0); -#ifdef SUPPORT_UNICODE - unicode_status |= XCLASS_CHAR_SAVED; -#endif /* SUPPORT_UNICODE */ - if (!optimize_class(common, (const sljit_u8 *)cc, FALSE, TRUE, list)) - { -#if PCRE2_CODE_UNIT_WIDTH == 8 - jump = NULL; - if (common->utf) -#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */ - jump = CMP(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, 255); - - OP2(SLJIT_AND, TMP2, 0, TMP1, 0, SLJIT_IMM, 0x7); - OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, SLJIT_IMM, 3); - OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)cc); - OP2(SLJIT_SHL, TMP2, 0, SLJIT_IMM, 1, TMP2, 0); - OP2U(SLJIT_AND | SLJIT_SET_Z, TMP1, 0, TMP2, 0); - add_jump(compiler, list, JUMP(SLJIT_NOT_ZERO)); - -#if PCRE2_CODE_UNIT_WIDTH == 8 - if (common->utf) -#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */ - JUMPHERE(jump); - } - - OP1(SLJIT_MOV, TMP1, 0, RETURN_ADDR, 0); - cc += 32 / sizeof(PCRE2_UCHAR); - } - -#ifdef SUPPORT_UNICODE -if (unicode_status & XCLASS_NEEDS_UCD) - { - if ((unicode_status & (XCLASS_SAVE_CHAR | XCLASS_CHAR_SAVED)) == XCLASS_SAVE_CHAR) - OP1(SLJIT_MOV, RETURN_ADDR, 0, TMP1, 0); - -#if PCRE2_CODE_UNIT_WIDTH == 32 - if (!common->utf) - { - jump = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, MAX_UTF_CODE_POINT + 1); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, UNASSIGNED_UTF_CHAR); - JUMPHERE(jump); - } -#endif /* PCRE2_CODE_UNIT_WIDTH == 32 */ - - OP2(SLJIT_LSHR, TMP2, 0, TMP1, 0, SLJIT_IMM, UCD_BLOCK_SHIFT); - OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 1); - OP1(SLJIT_MOV_U16, TMP2, 0, SLJIT_MEM1(TMP2), (sljit_sw)PRIV(ucd_stage1)); - OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, UCD_BLOCK_MASK); - OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, UCD_BLOCK_SHIFT); - OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP2, 0); - OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, (sljit_sw)PRIV(ucd_stage2)); - OP1(SLJIT_MOV_U16, TMP2, 0, SLJIT_MEM2(TMP2, TMP1), 1); - OP2(SLJIT_SHL, TMP1, 0, TMP2, 0, SLJIT_IMM, 3); - OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 2); - OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, TMP1, 0); - - ccbegin = cc; - - if (unicode_status & XCLASS_HAS_BIDICL) - { - OP1(SLJIT_MOV_U16, TMP1, 0, SLJIT_MEM1(TMP2), (sljit_sw)PRIV(ucd_records) + SLJIT_OFFSETOF(ucd_record, scriptx_bidiclass)); - OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, SLJIT_IMM, UCD_BIDICLASS_SHIFT); - - while (*cc != XCL_END) - { - if (*cc == XCL_SINGLE) - { - cc ++; - GETCHARINCTEST(c, cc); - } - else if (*cc == XCL_RANGE) - { - cc ++; - GETCHARINCTEST(c, cc); - GETCHARINCTEST(c, cc); - } - else - { - SLJIT_ASSERT(*cc == XCL_PROP || *cc == XCL_NOTPROP); - cc++; - if (*cc == PT_BIDICL) - { - compares--; - invertcmp = (compares == 0 && list != backtracks); - if (cc[-1] == XCL_NOTPROP) - invertcmp ^= 0x1; - jump = CMP(SLJIT_EQUAL ^ invertcmp, TMP1, 0, SLJIT_IMM, (int)cc[1]); - add_jump(compiler, compares > 0 ? list : backtracks, jump); - } - cc += 2; - } - } - - cc = ccbegin; - } - - if (unicode_status & XCLASS_HAS_BOOL) - { - OP1(SLJIT_MOV_U16, TMP1, 0, SLJIT_MEM1(TMP2), (sljit_sw)PRIV(ucd_records) + SLJIT_OFFSETOF(ucd_record, bprops)); - OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, UCD_BPROPS_MASK); - OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 2); - - while (*cc != XCL_END) - { - if (*cc == XCL_SINGLE) - { - cc ++; - GETCHARINCTEST(c, cc); - } - else if (*cc == XCL_RANGE) - { - cc ++; - GETCHARINCTEST(c, cc); - GETCHARINCTEST(c, cc); - } - else - { - SLJIT_ASSERT(*cc == XCL_PROP || *cc == XCL_NOTPROP); - cc++; - if (*cc == PT_BOOL) - { - compares--; - invertcmp = (compares == 0 && list != backtracks); - 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)); - add_jump(compiler, compares > 0 ? list : backtracks, JUMP(SLJIT_NOT_ZERO ^ invertcmp)); - } - cc += 2; - } - } - - cc = ccbegin; - } - - if (unicode_status & XCLASS_HAS_SCRIPT) - { - OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP2), (sljit_sw)PRIV(ucd_records) + SLJIT_OFFSETOF(ucd_record, script)); - - while (*cc != XCL_END) - { - if (*cc == XCL_SINGLE) - { - cc ++; - GETCHARINCTEST(c, cc); - } - else if (*cc == XCL_RANGE) - { - cc ++; - GETCHARINCTEST(c, cc); - GETCHARINCTEST(c, cc); - } - else - { - SLJIT_ASSERT(*cc == XCL_PROP || *cc == XCL_NOTPROP); - cc++; - switch (*cc) - { - case PT_SCX: - if (cc[-1] == XCL_NOTPROP) - break; - /* Fall through */ - - case PT_SC: - compares--; - invertcmp = (compares == 0 && list != backtracks); - if (cc[-1] == XCL_NOTPROP) - invertcmp ^= 0x1; - - add_jump(compiler, compares > 0 ? list : backtracks, CMP(SLJIT_EQUAL ^ invertcmp, TMP1, 0, SLJIT_IMM, (int)cc[1])); - } - cc += 2; - } - } - - cc = ccbegin; - } - - if (unicode_status & XCLASS_HAS_SCRIPT_EXTENSION) - { - OP1(SLJIT_MOV_U16, TMP1, 0, SLJIT_MEM1(TMP2), (sljit_sw)PRIV(ucd_records) + SLJIT_OFFSETOF(ucd_record, scriptx_bidiclass)); - OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, UCD_SCRIPTX_MASK); - OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 2); - - if (unicode_status & XCLASS_SCRIPT_EXTENSION_NOTPROP) - { - if (unicode_status & XCLASS_HAS_TYPE) - { - if (unicode_status & XCLASS_SAVE_CHAR) - { - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS0, TMP2, 0); - unicode_status |= XCLASS_SCRIPT_EXTENSION_RESTORE_LOCALS0; - } - else - { - OP1(SLJIT_MOV, RETURN_ADDR, 0, TMP2, 0); - unicode_status |= XCLASS_SCRIPT_EXTENSION_RESTORE_RETURN_ADDR; - } - } - OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP2), (sljit_sw)PRIV(ucd_records) + SLJIT_OFFSETOF(ucd_record, script)); - } - - while (*cc != XCL_END) - { - if (*cc == XCL_SINGLE) - { - cc ++; - GETCHARINCTEST(c, cc); - } - else if (*cc == XCL_RANGE) - { - cc ++; - GETCHARINCTEST(c, cc); - GETCHARINCTEST(c, cc); - } - else - { - SLJIT_ASSERT(*cc == XCL_PROP || *cc == XCL_NOTPROP); - cc++; - if (*cc == PT_SCX) - { - compares--; - invertcmp = (compares == 0 && list != backtracks); - - jump = NULL; - if (cc[-1] == XCL_NOTPROP) - { - jump = CMP(SLJIT_EQUAL, TMP2, 0, SLJIT_IMM, (int)cc[1]); - if (invertcmp) - { - add_jump(compiler, backtracks, jump); - jump = NULL; - } - 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)); - add_jump(compiler, compares > 0 ? list : backtracks, JUMP(SLJIT_NOT_ZERO ^ invertcmp)); - - if (jump != NULL) - JUMPHERE(jump); - } - cc += 2; - } - } - - if (unicode_status & XCLASS_SCRIPT_EXTENSION_RESTORE_LOCALS0) - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0); - else if (unicode_status & XCLASS_SCRIPT_EXTENSION_RESTORE_RETURN_ADDR) - OP1(SLJIT_MOV, TMP2, 0, RETURN_ADDR, 0); - cc = ccbegin; - } - - if (unicode_status & XCLASS_SAVE_CHAR) - OP1(SLJIT_MOV, TMP1, 0, RETURN_ADDR, 0); - - if (unicode_status & XCLASS_HAS_TYPE) - { - if (unicode_status & XCLASS_SAVE_CHAR) - typereg = RETURN_ADDR; - - OP1(SLJIT_MOV_U8, typereg, 0, SLJIT_MEM1(TMP2), (sljit_sw)PRIV(ucd_records) + SLJIT_OFFSETOF(ucd_record, chartype)); - } - } -#endif /* SUPPORT_UNICODE */ - -/* Generating code. */ -charoffset = 0; -numberofcmps = 0; -#ifdef SUPPORT_UNICODE -typeoffset = 0; -#endif /* SUPPORT_UNICODE */ - -while (*cc != XCL_END) - { - compares--; - invertcmp = (compares == 0 && list != backtracks); - jump = NULL; - - if (*cc == XCL_SINGLE) - { - cc ++; - GETCHARINCTEST(c, cc); - - if (numberofcmps < 3 && (*cc == XCL_SINGLE || *cc == XCL_RANGE)) - { - OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, (sljit_sw)(c - charoffset)); - OP_FLAGS(numberofcmps == 0 ? SLJIT_MOV : SLJIT_OR, TMP2, 0, SLJIT_EQUAL); - numberofcmps++; - } - else if (numberofcmps > 0) - { - OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, (sljit_sw)(c - charoffset)); - OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_EQUAL); - jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp); - numberofcmps = 0; - } - else - { - jump = CMP(SLJIT_EQUAL ^ invertcmp, TMP1, 0, SLJIT_IMM, (sljit_sw)(c - charoffset)); - numberofcmps = 0; - } - } - else if (*cc == XCL_RANGE) - { - cc ++; - GETCHARINCTEST(c, cc); - SET_CHAR_OFFSET(c); - GETCHARINCTEST(c, cc); - - if (numberofcmps < 3 && (*cc == XCL_SINGLE || *cc == XCL_RANGE)) - { - OP2U(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, TMP1, 0, SLJIT_IMM, (sljit_sw)(c - charoffset)); - OP_FLAGS(numberofcmps == 0 ? SLJIT_MOV : SLJIT_OR, TMP2, 0, SLJIT_LESS_EQUAL); - numberofcmps++; - } - else if (numberofcmps > 0) - { - OP2U(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, TMP1, 0, SLJIT_IMM, (sljit_sw)(c - charoffset)); - OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_LESS_EQUAL); - jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp); - numberofcmps = 0; - } - else - { - jump = CMP(SLJIT_LESS_EQUAL ^ invertcmp, TMP1, 0, SLJIT_IMM, (sljit_sw)(c - charoffset)); - numberofcmps = 0; - } - } -#ifdef SUPPORT_UNICODE - else - { - SLJIT_ASSERT(*cc == XCL_PROP || *cc == XCL_NOTPROP); - if (*cc == XCL_NOTPROP) - invertcmp ^= 0x1; - cc++; - switch(*cc) - { - case PT_ANY: - if (!invertcmp) - jump = JUMP(SLJIT_JUMP); - break; - - case PT_LAMP: - OP2U(SLJIT_SUB | SLJIT_SET_Z, typereg, 0, SLJIT_IMM, ucp_Lu - typeoffset); - OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_EQUAL); - OP2U(SLJIT_SUB | SLJIT_SET_Z, typereg, 0, SLJIT_IMM, ucp_Ll - typeoffset); - OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); - OP2U(SLJIT_SUB | SLJIT_SET_Z, typereg, 0, SLJIT_IMM, ucp_Lt - typeoffset); - OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_EQUAL); - jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp); - break; - - case PT_GC: - c = PRIV(ucp_typerange)[(int)cc[1] * 2]; - SET_TYPE_OFFSET(c); - jump = CMP(SLJIT_LESS_EQUAL ^ invertcmp, typereg, 0, SLJIT_IMM, PRIV(ucp_typerange)[(int)cc[1] * 2 + 1] - c); - break; - - case PT_PC: - jump = CMP(SLJIT_EQUAL ^ invertcmp, typereg, 0, SLJIT_IMM, (int)cc[1] - typeoffset); - break; - - case PT_SC: - case PT_SCX: - case PT_BOOL: - case PT_BIDICL: - compares++; - /* Do nothing. */ - break; - - case PT_SPACE: - case PT_PXSPACE: - SET_CHAR_OFFSET(9); - OP2U(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, TMP1, 0, SLJIT_IMM, 0xd - 0x9); - OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL); - - OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, 0x85 - 0x9); - OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); - - OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, 0x180e - 0x9); - OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); - - SET_TYPE_OFFSET(ucp_Zl); - OP2U(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, typereg, 0, SLJIT_IMM, ucp_Zs - ucp_Zl); - OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_LESS_EQUAL); - jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp); - break; - - case PT_WORD: - OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, (sljit_sw)(CHAR_UNDERSCORE - charoffset)); - OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_EQUAL); - /* Fall through. */ - - case PT_ALNUM: - SET_TYPE_OFFSET(ucp_Ll); - OP2U(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, typereg, 0, SLJIT_IMM, ucp_Lu - ucp_Ll); - OP_FLAGS((*cc == PT_ALNUM) ? SLJIT_MOV : SLJIT_OR, TMP2, 0, SLJIT_LESS_EQUAL); - SET_TYPE_OFFSET(ucp_Nd); - OP2U(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, typereg, 0, SLJIT_IMM, ucp_No - ucp_Nd); - OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_LESS_EQUAL); - jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp); - break; - - case PT_CLIST: - other_cases = PRIV(ucd_caseless_sets) + cc[1]; - - /* At least three characters are required. - Otherwise this case would be handled by the normal code path. */ - SLJIT_ASSERT(other_cases[0] != NOTACHAR && other_cases[1] != NOTACHAR && other_cases[2] != NOTACHAR); - SLJIT_ASSERT(other_cases[0] < other_cases[1] && other_cases[1] < other_cases[2]); - - /* Optimizing character pairs, if their difference is power of 2. */ - if (is_powerof2(other_cases[1] ^ other_cases[0])) - { - if (charoffset == 0) - OP2(SLJIT_OR, TMP2, 0, TMP1, 0, SLJIT_IMM, other_cases[1] ^ other_cases[0]); - else - { - OP2(SLJIT_ADD, TMP2, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)charoffset); - OP2(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_IMM, other_cases[1] ^ other_cases[0]); - } - OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, SLJIT_IMM, other_cases[1]); - OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_EQUAL); - other_cases += 2; - } - else if (is_powerof2(other_cases[2] ^ other_cases[1])) - { - if (charoffset == 0) - OP2(SLJIT_OR, TMP2, 0, TMP1, 0, SLJIT_IMM, other_cases[2] ^ other_cases[1]); - else - { - OP2(SLJIT_ADD, TMP2, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)charoffset); - OP2(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_IMM, other_cases[1] ^ other_cases[0]); - } - OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, SLJIT_IMM, other_cases[2]); - OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_EQUAL); - - OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, (sljit_sw)(other_cases[0] - charoffset)); - OP_FLAGS(SLJIT_OR | ((other_cases[3] == NOTACHAR) ? SLJIT_SET_Z : 0), TMP2, 0, SLJIT_EQUAL); - - other_cases += 3; - } - else - { - OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, (sljit_sw)(*other_cases++ - charoffset)); - OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_EQUAL); - } - - while (*other_cases != NOTACHAR) - { - OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, (sljit_sw)(*other_cases++ - charoffset)); - OP_FLAGS(SLJIT_OR | ((*other_cases == NOTACHAR) ? SLJIT_SET_Z : 0), TMP2, 0, SLJIT_EQUAL); - } - jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp); - break; - - case PT_UCNC: - OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, (sljit_sw)(CHAR_DOLLAR_SIGN - charoffset)); - OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_EQUAL); - OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, (sljit_sw)(CHAR_COMMERCIAL_AT - charoffset)); - OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); - OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, (sljit_sw)(CHAR_GRAVE_ACCENT - charoffset)); - OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); - - SET_CHAR_OFFSET(0xa0); - OP2U(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, TMP1, 0, SLJIT_IMM, (sljit_sw)(0xd7ff - charoffset)); - OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_LESS_EQUAL); - SET_CHAR_OFFSET(0); - OP2U(SLJIT_SUB | SLJIT_SET_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0xe000 - 0); - OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_GREATER_EQUAL); - jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp); - break; - - case PT_PXGRAPH: - /* C and Z groups are the farthest two groups. */ - SET_TYPE_OFFSET(ucp_Ll); - OP2U(SLJIT_SUB | SLJIT_SET_GREATER, typereg, 0, SLJIT_IMM, ucp_So - ucp_Ll); - OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_GREATER); - - jump = CMP(SLJIT_NOT_EQUAL, typereg, 0, SLJIT_IMM, ucp_Cf - ucp_Ll); - - /* In case of ucp_Cf, we overwrite the result. */ - SET_CHAR_OFFSET(0x2066); - OP2U(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, TMP1, 0, SLJIT_IMM, 0x2069 - 0x2066); - OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL); - - OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, 0x061c - 0x2066); - OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); - - OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, 0x180e - 0x2066); - OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); - - JUMPHERE(jump); - jump = CMP(SLJIT_ZERO ^ invertcmp, TMP2, 0, SLJIT_IMM, 0); - break; - - case PT_PXPRINT: - /* C and Z groups are the farthest two groups. */ - SET_TYPE_OFFSET(ucp_Ll); - OP2U(SLJIT_SUB | SLJIT_SET_GREATER, typereg, 0, SLJIT_IMM, ucp_So - ucp_Ll); - OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_GREATER); - - OP2U(SLJIT_SUB | SLJIT_SET_Z, typereg, 0, SLJIT_IMM, ucp_Zs - ucp_Ll); - OP_FLAGS(SLJIT_AND, TMP2, 0, SLJIT_NOT_EQUAL); - - jump = CMP(SLJIT_NOT_EQUAL, typereg, 0, SLJIT_IMM, ucp_Cf - ucp_Ll); - - /* In case of ucp_Cf, we overwrite the result. */ - SET_CHAR_OFFSET(0x2066); - OP2U(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, TMP1, 0, SLJIT_IMM, 0x2069 - 0x2066); - OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL); - - OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, 0x061c - 0x2066); - OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); - - JUMPHERE(jump); - jump = CMP(SLJIT_ZERO ^ invertcmp, TMP2, 0, SLJIT_IMM, 0); - break; - - case PT_PXPUNCT: - SET_TYPE_OFFSET(ucp_Sc); - OP2U(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, typereg, 0, SLJIT_IMM, ucp_So - ucp_Sc); - OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL); - - SET_CHAR_OFFSET(0); - OP2U(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, TMP1, 0, SLJIT_IMM, 0x7f); - OP_FLAGS(SLJIT_AND, TMP2, 0, SLJIT_LESS_EQUAL); - - SET_TYPE_OFFSET(ucp_Pc); - OP2U(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, typereg, 0, SLJIT_IMM, ucp_Ps - ucp_Pc); - OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_LESS_EQUAL); - jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp); - break; - - default: - SLJIT_UNREACHABLE(); - break; - } - cc += 2; - } -#endif /* SUPPORT_UNICODE */ - - if (jump != NULL) - add_jump(compiler, compares > 0 ? list : backtracks, jump); - } - -if (found != NULL) - set_jumps(found, LABEL()); -} - -#undef SET_TYPE_OFFSET -#undef SET_CHAR_OFFSET - -#endif - -static PCRE2_SPTR compile_simple_assertion_matchingpath(compiler_common *common, PCRE2_UCHAR type, PCRE2_SPTR cc, jump_list **backtracks) -{ -DEFINE_COMPILER; -int length; -struct sljit_jump *jump[4]; -#ifdef SUPPORT_UNICODE -struct sljit_label *label; -#endif /* SUPPORT_UNICODE */ - -switch(type) - { - case OP_SOD: - if (HAS_VIRTUAL_REGISTERS) - { - OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, begin)); - } - else - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, begin)); - add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, TMP1, 0)); - return cc; - - case OP_SOM: - if (HAS_VIRTUAL_REGISTERS) - { - OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, str)); - } - else - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, str)); - add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, TMP1, 0)); - return cc; - - case OP_NOT_WORD_BOUNDARY: - case OP_WORD_BOUNDARY: - add_jump(compiler, &common->wordboundary, JUMP(SLJIT_FAST_CALL)); -#ifdef SUPPORT_UNICODE - if (common->invalid_utf) - { - add_jump(compiler, backtracks, CMP((type == OP_NOT_WORD_BOUNDARY) ? SLJIT_NOT_EQUAL : SLJIT_SIG_LESS_EQUAL, TMP2, 0, SLJIT_IMM, 0)); - return cc; - } -#endif /* SUPPORT_UNICODE */ - sljit_set_current_flags(compiler, SLJIT_SET_Z); - add_jump(compiler, backtracks, JUMP(type == OP_NOT_WORD_BOUNDARY ? SLJIT_NOT_ZERO : SLJIT_ZERO)); - return cc; - - case OP_EODN: - /* Requires rather complex checks. */ - jump[0] = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); - if (common->nltype == NLTYPE_FIXED && common->newline > 255) - { - OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2)); - OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); - if (common->mode == PCRE2_JIT_COMPLETE) - add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, STR_END, 0)); - else - { - jump[1] = CMP(SLJIT_EQUAL, TMP2, 0, STR_END, 0); - OP2U(SLJIT_SUB | SLJIT_SET_LESS, TMP2, 0, STR_END, 0); - OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS); - OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff); - OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_NOT_EQUAL); - add_jump(compiler, backtracks, JUMP(SLJIT_NOT_EQUAL)); - check_partial(common, TRUE); - add_jump(compiler, backtracks, JUMP(SLJIT_JUMP)); - JUMPHERE(jump[1]); - } - OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1)); - add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff)); - add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, common->newline & 0xff)); - } - else if (common->nltype == NLTYPE_FIXED) - { - OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); - add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, STR_END, 0)); - add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, common->newline)); - } - else - { - OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); - jump[1] = CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_CR); - OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2)); - OP2U(SLJIT_SUB | SLJIT_SET_Z | SLJIT_SET_GREATER, TMP2, 0, STR_END, 0); - jump[2] = JUMP(SLJIT_GREATER); - add_jump(compiler, backtracks, JUMP(SLJIT_NOT_EQUAL) /* LESS */); - /* Equal. */ - OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1)); - jump[3] = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_NL); - add_jump(compiler, backtracks, JUMP(SLJIT_JUMP)); - - JUMPHERE(jump[1]); - if (common->nltype == NLTYPE_ANYCRLF) - { - OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - add_jump(compiler, backtracks, CMP(SLJIT_LESS, TMP2, 0, STR_END, 0)); - add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_NL)); - } - else - { - OP1(SLJIT_MOV, TMP3, 0, STR_PTR, 0); - read_char(common, common->nlmin, common->nlmax, backtracks, READ_CHAR_UPDATE_STR_PTR); - add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, STR_END, 0)); - add_jump(compiler, &common->anynewline, JUMP(SLJIT_FAST_CALL)); - sljit_set_current_flags(compiler, SLJIT_SET_Z); - add_jump(compiler, backtracks, JUMP(SLJIT_ZERO)); - OP1(SLJIT_MOV, STR_PTR, 0, TMP3, 0); - } - JUMPHERE(jump[2]); - JUMPHERE(jump[3]); - } - JUMPHERE(jump[0]); - if (common->mode != PCRE2_JIT_COMPLETE) - check_partial(common, TRUE); - return cc; - - case OP_EOD: - add_jump(compiler, backtracks, CMP(SLJIT_LESS, STR_PTR, 0, STR_END, 0)); - if (common->mode != PCRE2_JIT_COMPLETE) - check_partial(common, TRUE); - return cc; - - case OP_DOLL: - if (HAS_VIRTUAL_REGISTERS) - { - OP1(SLJIT_MOV, TMP2, 0, ARGUMENTS, 0); - OP2U(SLJIT_AND32 | SLJIT_SET_Z, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, options), SLJIT_IMM, PCRE2_NOTEOL); - } - else - OP2U(SLJIT_AND32 | SLJIT_SET_Z, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, options), SLJIT_IMM, PCRE2_NOTEOL); - add_jump(compiler, backtracks, JUMP(SLJIT_NOT_ZERO)); - - if (!common->endonly) - compile_simple_assertion_matchingpath(common, OP_EODN, cc, backtracks); - else - { - add_jump(compiler, backtracks, CMP(SLJIT_LESS, STR_PTR, 0, STR_END, 0)); - check_partial(common, FALSE); - } - return cc; - - case OP_DOLLM: - jump[1] = CMP(SLJIT_LESS, STR_PTR, 0, STR_END, 0); - if (HAS_VIRTUAL_REGISTERS) - { - OP1(SLJIT_MOV, TMP2, 0, ARGUMENTS, 0); - OP2U(SLJIT_AND32 | SLJIT_SET_Z, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, options), SLJIT_IMM, PCRE2_NOTEOL); - } - else - OP2U(SLJIT_AND32 | SLJIT_SET_Z, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, options), SLJIT_IMM, PCRE2_NOTEOL); - add_jump(compiler, backtracks, JUMP(SLJIT_NOT_ZERO)); - check_partial(common, FALSE); - jump[0] = JUMP(SLJIT_JUMP); - JUMPHERE(jump[1]); - - if (common->nltype == NLTYPE_FIXED && common->newline > 255) - { - OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2)); - OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); - if (common->mode == PCRE2_JIT_COMPLETE) - add_jump(compiler, backtracks, CMP(SLJIT_GREATER, TMP2, 0, STR_END, 0)); - else - { - jump[1] = CMP(SLJIT_LESS_EQUAL, TMP2, 0, STR_END, 0); - /* STR_PTR = STR_END - IN_UCHARS(1) */ - add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff)); - check_partial(common, TRUE); - add_jump(compiler, backtracks, JUMP(SLJIT_JUMP)); - JUMPHERE(jump[1]); - } - - OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1)); - add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff)); - add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, common->newline & 0xff)); - } - else - { - peek_char(common, common->nlmax, TMP3, 0, NULL); - check_newlinechar(common, common->nltype, backtracks, FALSE); - } - JUMPHERE(jump[0]); - return cc; - - case OP_CIRC: - if (HAS_VIRTUAL_REGISTERS) - { - OP1(SLJIT_MOV, TMP2, 0, ARGUMENTS, 0); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, begin)); - add_jump(compiler, backtracks, CMP(SLJIT_GREATER, STR_PTR, 0, TMP1, 0)); - OP2U(SLJIT_AND32 | SLJIT_SET_Z, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, options), SLJIT_IMM, PCRE2_NOTBOL); - add_jump(compiler, backtracks, JUMP(SLJIT_NOT_ZERO)); - } - else - { - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, begin)); - add_jump(compiler, backtracks, CMP(SLJIT_GREATER, STR_PTR, 0, TMP1, 0)); - OP2U(SLJIT_AND32 | SLJIT_SET_Z, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, options), SLJIT_IMM, PCRE2_NOTBOL); - add_jump(compiler, backtracks, JUMP(SLJIT_NOT_ZERO)); - } - return cc; - - case OP_CIRCM: - /* TMP2 might be used by peek_char_back. */ - if (HAS_VIRTUAL_REGISTERS) - { - OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0); - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, begin)); - jump[1] = CMP(SLJIT_GREATER, STR_PTR, 0, TMP2, 0); - OP2U(SLJIT_AND32 | SLJIT_SET_Z, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, options), SLJIT_IMM, PCRE2_NOTBOL); - } - else - { - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, begin)); - jump[1] = CMP(SLJIT_GREATER, STR_PTR, 0, TMP2, 0); - OP2U(SLJIT_AND32 | SLJIT_SET_Z, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, options), SLJIT_IMM, PCRE2_NOTBOL); - } - add_jump(compiler, backtracks, JUMP(SLJIT_NOT_ZERO)); - jump[0] = JUMP(SLJIT_JUMP); - JUMPHERE(jump[1]); - - if (!common->alt_circumflex) - add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0)); - - if (common->nltype == NLTYPE_FIXED && common->newline > 255) - { - OP2(SLJIT_SUB, TMP1, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2)); - add_jump(compiler, backtracks, CMP(SLJIT_LESS, TMP1, 0, TMP2, 0)); - OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-2)); - OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-1)); - add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff)); - add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, common->newline & 0xff)); - } - else - { - peek_char_back(common, common->nlmax, backtracks); - check_newlinechar(common, common->nltype, backtracks, FALSE); - } - JUMPHERE(jump[0]); - return cc; - - case OP_REVERSE: - length = GET(cc, 0); - if (length == 0) - return cc + LINK_SIZE; - if (HAS_VIRTUAL_REGISTERS) - { - OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0); - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, begin)); - } - else - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, begin)); -#ifdef SUPPORT_UNICODE - if (common->utf) - { - OP1(SLJIT_MOV, TMP3, 0, SLJIT_IMM, length); - label = LABEL(); - add_jump(compiler, backtracks, CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, TMP2, 0)); - move_back(common, backtracks, FALSE); - OP2(SLJIT_SUB | SLJIT_SET_Z, TMP3, 0, TMP3, 0, SLJIT_IMM, 1); - JUMPTO(SLJIT_NOT_ZERO, label); - } - else -#endif - { - OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(length)); - add_jump(compiler, backtracks, CMP(SLJIT_LESS, STR_PTR, 0, TMP2, 0)); - } - check_start_used_ptr(common); - return cc + LINK_SIZE; - } -SLJIT_UNREACHABLE(); -return cc; -} - -#ifdef SUPPORT_UNICODE - -#if PCRE2_CODE_UNIT_WIDTH != 32 - -static PCRE2_SPTR SLJIT_FUNC do_extuni_utf(jit_arguments *args, PCRE2_SPTR cc) -{ -PCRE2_SPTR start_subject = args->begin; -PCRE2_SPTR end_subject = args->end; -int lgb, rgb, ricount; -PCRE2_SPTR prevcc, endcc, bptr; -BOOL first = TRUE; -uint32_t c; - -prevcc = cc; -endcc = NULL; -do - { - GETCHARINC(c, cc); - rgb = UCD_GRAPHBREAK(c); - - if (first) - { - lgb = rgb; - endcc = cc; - first = FALSE; - continue; - } - - if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0) - break; - - /* Not breaking between Regional Indicators is allowed only if there - are an even number of preceding RIs. */ - - if (lgb == ucp_gbRegional_Indicator && rgb == ucp_gbRegional_Indicator) - { - ricount = 0; - bptr = prevcc; - - /* bptr is pointing to the left-hand character */ - while (bptr > start_subject) - { - bptr--; - BACKCHAR(bptr); - GETCHAR(c, bptr); - - if (UCD_GRAPHBREAK(c) != ucp_gbRegional_Indicator) - break; - - ricount++; - } - - 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. */ - - if ((rgb != ucp_gbExtend && rgb != ucp_gbZWJ) || - lgb != ucp_gbExtended_Pictographic) - lgb = rgb; - - prevcc = endcc; - endcc = cc; - } -while (cc < end_subject); - -return endcc; -} - -#endif /* PCRE2_CODE_UNIT_WIDTH != 32 */ - -static PCRE2_SPTR SLJIT_FUNC do_extuni_utf_invalid(jit_arguments *args, PCRE2_SPTR cc) -{ -PCRE2_SPTR start_subject = args->begin; -PCRE2_SPTR end_subject = args->end; -int lgb, rgb, ricount; -PCRE2_SPTR prevcc, endcc, bptr; -BOOL first = TRUE; -uint32_t c; - -prevcc = cc; -endcc = NULL; -do - { - GETCHARINC_INVALID(c, cc, end_subject, break); - rgb = UCD_GRAPHBREAK(c); - - if (first) - { - lgb = rgb; - endcc = cc; - first = FALSE; - continue; - } - - if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0) - break; - - /* Not breaking between Regional Indicators is allowed only if there - are an even number of preceding RIs. */ - - if (lgb == ucp_gbRegional_Indicator && rgb == ucp_gbRegional_Indicator) - { - ricount = 0; - bptr = prevcc; - - /* bptr is pointing to the left-hand character */ - while (bptr > start_subject) - { - GETCHARBACK_INVALID(c, bptr, start_subject, break); - - if (UCD_GRAPHBREAK(c) != ucp_gbRegional_Indicator) - break; - - ricount++; - } - - 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. */ - - if ((rgb != ucp_gbExtend && rgb != ucp_gbZWJ) || - lgb != ucp_gbExtended_Pictographic) - lgb = rgb; - - prevcc = endcc; - endcc = cc; - } -while (cc < end_subject); - -return endcc; -} - -static PCRE2_SPTR SLJIT_FUNC do_extuni_no_utf(jit_arguments *args, PCRE2_SPTR cc) -{ -PCRE2_SPTR start_subject = args->begin; -PCRE2_SPTR end_subject = args->end; -int lgb, rgb, ricount; -PCRE2_SPTR bptr; -uint32_t c; - -/* Patch by PH */ -/* GETCHARINC(c, cc); */ -c = *cc++; - -#if PCRE2_CODE_UNIT_WIDTH == 32 -if (c >= 0x110000) - return NULL; -#endif /* PCRE2_CODE_UNIT_WIDTH == 32 */ -lgb = UCD_GRAPHBREAK(c); - -while (cc < end_subject) - { - c = *cc; -#if PCRE2_CODE_UNIT_WIDTH == 32 - if (c >= 0x110000) - break; -#endif /* PCRE2_CODE_UNIT_WIDTH == 32 */ - rgb = UCD_GRAPHBREAK(c); - - if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0) - break; - - /* Not breaking between Regional Indicators is allowed only if there - are an even number of preceding RIs. */ - - if (lgb == ucp_gbRegional_Indicator && rgb == ucp_gbRegional_Indicator) - { - ricount = 0; - bptr = cc - 1; - - /* bptr is pointing to the left-hand character */ - while (bptr > start_subject) - { - bptr--; - c = *bptr; -#if PCRE2_CODE_UNIT_WIDTH == 32 - if (c >= 0x110000) - break; -#endif /* PCRE2_CODE_UNIT_WIDTH == 32 */ - - if (UCD_GRAPHBREAK(c) != ucp_gbRegional_Indicator) break; - - ricount++; - } - - 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. */ - - if ((rgb != ucp_gbExtend && rgb != ucp_gbZWJ) || - lgb != ucp_gbExtended_Pictographic) - lgb = rgb; - - cc++; - } - -return cc; -} - -#endif /* SUPPORT_UNICODE */ - -static PCRE2_SPTR compile_char1_matchingpath(compiler_common *common, PCRE2_UCHAR type, PCRE2_SPTR cc, jump_list **backtracks, BOOL check_str_ptr) -{ -DEFINE_COMPILER; -int length; -unsigned int c, oc, bit; -compare_context context; -struct sljit_jump *jump[3]; -jump_list *end_list; -#ifdef SUPPORT_UNICODE -PCRE2_UCHAR propdata[5]; -#endif /* SUPPORT_UNICODE */ - -switch(type) - { - case OP_NOT_DIGIT: - case OP_DIGIT: - /* Digits are usually 0-9, so it is worth to optimize them. */ - if (check_str_ptr) - detect_partial_match(common, backtracks); -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8 - if (common->utf && is_char7_bitset((const sljit_u8*)common->ctypes - cbit_length + cbit_digit, FALSE)) - read_char7_type(common, backtracks, type == OP_NOT_DIGIT); - else -#endif - read_char8_type(common, backtracks, type == OP_NOT_DIGIT); - /* Flip the starting bit in the negative case. */ - OP2U(SLJIT_AND | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, ctype_digit); - add_jump(compiler, backtracks, JUMP(type == OP_DIGIT ? SLJIT_ZERO : SLJIT_NOT_ZERO)); - return cc; - - case OP_NOT_WHITESPACE: - case OP_WHITESPACE: - if (check_str_ptr) - detect_partial_match(common, backtracks); -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8 - if (common->utf && is_char7_bitset((const sljit_u8*)common->ctypes - cbit_length + cbit_space, FALSE)) - read_char7_type(common, backtracks, type == OP_NOT_WHITESPACE); - else -#endif - read_char8_type(common, backtracks, type == OP_NOT_WHITESPACE); - OP2U(SLJIT_AND | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, ctype_space); - add_jump(compiler, backtracks, JUMP(type == OP_WHITESPACE ? SLJIT_ZERO : SLJIT_NOT_ZERO)); - return cc; - - case OP_NOT_WORDCHAR: - case OP_WORDCHAR: - if (check_str_ptr) - detect_partial_match(common, backtracks); -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8 - if (common->utf && is_char7_bitset((const sljit_u8*)common->ctypes - cbit_length + cbit_word, FALSE)) - read_char7_type(common, backtracks, type == OP_NOT_WORDCHAR); - else -#endif - read_char8_type(common, backtracks, type == OP_NOT_WORDCHAR); - OP2U(SLJIT_AND | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, ctype_word); - add_jump(compiler, backtracks, JUMP(type == OP_WORDCHAR ? SLJIT_ZERO : SLJIT_NOT_ZERO)); - return cc; - - case OP_ANY: - if (check_str_ptr) - detect_partial_match(common, backtracks); - read_char(common, common->nlmin, common->nlmax, backtracks, READ_CHAR_UPDATE_STR_PTR); - if (common->nltype == NLTYPE_FIXED && common->newline > 255) - { - jump[0] = CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff); - end_list = NULL; - if (common->mode != PCRE2_JIT_PARTIAL_HARD) - add_jump(compiler, &end_list, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0)); - else - check_str_end(common, &end_list); - - OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0); - add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, common->newline & 0xff)); - set_jumps(end_list, LABEL()); - JUMPHERE(jump[0]); - } - else - check_newlinechar(common, common->nltype, backtracks, TRUE); - return cc; - - case OP_ALLANY: - if (check_str_ptr) - detect_partial_match(common, backtracks); -#ifdef SUPPORT_UNICODE - if (common->utf) - { - if (common->invalid_utf) - { - read_char(common, 0, READ_CHAR_MAX, backtracks, READ_CHAR_UPDATE_STR_PTR); - return cc; - } - -#if PCRE2_CODE_UNIT_WIDTH == 8 || PCRE2_CODE_UNIT_WIDTH == 16 - OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0); - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); -#if PCRE2_CODE_UNIT_WIDTH == 8 - jump[0] = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0xc0); - OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0); - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0); -#elif PCRE2_CODE_UNIT_WIDTH == 16 - jump[0] = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0xd800); - OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xfc00); - OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, 0xd800); - OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_EQUAL); - OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 1); - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0); -#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */ - JUMPHERE(jump[0]); - return cc; -#endif /* PCRE2_CODE_UNIT_WIDTH == [8|16] */ - } -#endif /* SUPPORT_UNICODE */ - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - return cc; - - case OP_ANYBYTE: - if (check_str_ptr) - detect_partial_match(common, backtracks); - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - return cc; - -#ifdef SUPPORT_UNICODE - case OP_NOTPROP: - case OP_PROP: - propdata[0] = XCL_HASPROP; - propdata[1] = type == OP_NOTPROP ? XCL_NOTPROP : XCL_PROP; - propdata[2] = cc[0]; - propdata[3] = cc[1]; - propdata[4] = XCL_END; - if (check_str_ptr) - detect_partial_match(common, backtracks); - compile_xclass_matchingpath(common, propdata, backtracks); - return cc + 2; -#endif - - case OP_ANYNL: - if (check_str_ptr) - detect_partial_match(common, backtracks); - read_char(common, common->bsr_nlmin, common->bsr_nlmax, NULL, 0); - jump[0] = CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_CR); - /* We don't need to handle soft partial matching case. */ - end_list = NULL; - if (common->mode != PCRE2_JIT_PARTIAL_HARD) - add_jump(compiler, &end_list, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0)); - else - check_str_end(common, &end_list); - OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0); - jump[1] = CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_NL); - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - jump[2] = JUMP(SLJIT_JUMP); - JUMPHERE(jump[0]); - check_newlinechar(common, common->bsr_nltype, backtracks, FALSE); - set_jumps(end_list, LABEL()); - JUMPHERE(jump[1]); - JUMPHERE(jump[2]); - return cc; - - case OP_NOT_HSPACE: - case OP_HSPACE: - if (check_str_ptr) - detect_partial_match(common, backtracks); - - if (type == OP_NOT_HSPACE) - read_char(common, 0x9, 0x3000, backtracks, READ_CHAR_UPDATE_STR_PTR); - else - read_char(common, 0x9, 0x3000, NULL, 0); - - add_jump(compiler, &common->hspace, JUMP(SLJIT_FAST_CALL)); - sljit_set_current_flags(compiler, SLJIT_SET_Z); - add_jump(compiler, backtracks, JUMP(type == OP_NOT_HSPACE ? SLJIT_NOT_ZERO : SLJIT_ZERO)); - return cc; - - case OP_NOT_VSPACE: - case OP_VSPACE: - if (check_str_ptr) - detect_partial_match(common, backtracks); - - if (type == OP_NOT_VSPACE) - read_char(common, 0xa, 0x2029, backtracks, READ_CHAR_UPDATE_STR_PTR); - else - read_char(common, 0xa, 0x2029, NULL, 0); - - add_jump(compiler, &common->vspace, JUMP(SLJIT_FAST_CALL)); - sljit_set_current_flags(compiler, SLJIT_SET_Z); - add_jump(compiler, backtracks, JUMP(type == OP_NOT_VSPACE ? SLJIT_NOT_ZERO : SLJIT_ZERO)); - return cc; - -#ifdef SUPPORT_UNICODE - case OP_EXTUNI: - if (check_str_ptr) - detect_partial_match(common, backtracks); - - SLJIT_ASSERT(TMP1 == SLJIT_R0 && STR_PTR == SLJIT_R1); - OP1(SLJIT_MOV, SLJIT_R0, 0, ARGUMENTS, 0); - -#if PCRE2_CODE_UNIT_WIDTH != 32 - sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_ARGS2(W, W, W), SLJIT_IMM, - common->utf ? (common->invalid_utf ? SLJIT_FUNC_ADDR(do_extuni_utf_invalid) : SLJIT_FUNC_ADDR(do_extuni_utf)) : SLJIT_FUNC_ADDR(do_extuni_no_utf)); - if (common->invalid_utf) - add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0)); -#else - sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_ARGS2(W, W, W), SLJIT_IMM, - common->invalid_utf ? SLJIT_FUNC_ADDR(do_extuni_utf_invalid) : SLJIT_FUNC_ADDR(do_extuni_no_utf)); - if (!common->utf || common->invalid_utf) - add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0)); -#endif - - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_RETURN_REG, 0); - - if (common->mode == PCRE2_JIT_PARTIAL_HARD) - { - jump[0] = CMP(SLJIT_LESS, SLJIT_RETURN_REG, 0, STR_END, 0); - /* Since we successfully read a char above, partial matching must occure. */ - check_partial(common, TRUE); - JUMPHERE(jump[0]); - } - return cc; -#endif - - case OP_CHAR: - case OP_CHARI: - length = 1; -#ifdef SUPPORT_UNICODE - if (common->utf && HAS_EXTRALEN(*cc)) length += GET_EXTRALEN(*cc); -#endif - - if (check_str_ptr && common->mode != PCRE2_JIT_COMPLETE) - detect_partial_match(common, backtracks); - - if (type == OP_CHAR || !char_has_othercase(common, cc) || char_get_othercase_bit(common, cc) != 0) - { - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(length)); - if (length > 1 || (check_str_ptr && common->mode == PCRE2_JIT_COMPLETE)) - add_jump(compiler, backtracks, CMP(SLJIT_GREATER, STR_PTR, 0, STR_END, 0)); - - context.length = IN_UCHARS(length); - context.sourcereg = -1; -#if defined SLJIT_UNALIGNED && SLJIT_UNALIGNED - context.ucharptr = 0; -#endif - return byte_sequence_compare(common, type == OP_CHARI, cc, &context, backtracks); - } - -#ifdef SUPPORT_UNICODE - if (common->utf) - { - GETCHAR(c, cc); - } - else -#endif - c = *cc; - - SLJIT_ASSERT(type == OP_CHARI && char_has_othercase(common, cc)); - - if (check_str_ptr && common->mode == PCRE2_JIT_COMPLETE) - add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0)); - - oc = char_othercase(common, c); - read_char(common, c < oc ? c : oc, c > oc ? c : oc, NULL, 0); - - SLJIT_ASSERT(!is_powerof2(c ^ oc)); - - if (sljit_has_cpu_feature(SLJIT_HAS_CMOV)) - { - OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, oc); - CMOV(SLJIT_EQUAL, TMP1, SLJIT_IMM, c); - add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, c)); - } - else - { - jump[0] = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, c); - add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, oc)); - JUMPHERE(jump[0]); - } - return cc + length; - - case OP_NOT: - case OP_NOTI: - if (check_str_ptr) - detect_partial_match(common, backtracks); - - length = 1; -#ifdef SUPPORT_UNICODE - if (common->utf) - { -#if PCRE2_CODE_UNIT_WIDTH == 8 - c = *cc; - if (c < 128 && !common->invalid_utf) - { - OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(STR_PTR), 0); - if (type == OP_NOT || !char_has_othercase(common, cc)) - add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, c)); - else - { - /* Since UTF8 code page is fixed, we know that c is in [a-z] or [A-Z] range. */ - OP2(SLJIT_OR, TMP2, 0, TMP1, 0, SLJIT_IMM, 0x20); - add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP2, 0, SLJIT_IMM, c | 0x20)); - } - /* Skip the variable-length character. */ - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - jump[0] = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0xc0); - OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0); - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0); - JUMPHERE(jump[0]); - return cc + 1; - } - else -#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */ - { - GETCHARLEN(c, cc, length); - } - } - else -#endif /* SUPPORT_UNICODE */ - c = *cc; - - if (type == OP_NOT || !char_has_othercase(common, cc)) - { - read_char(common, c, c, backtracks, READ_CHAR_UPDATE_STR_PTR); - add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, c)); - } - else - { - oc = char_othercase(common, c); - read_char(common, c < oc ? c : oc, c > oc ? c : oc, backtracks, READ_CHAR_UPDATE_STR_PTR); - bit = c ^ oc; - if (is_powerof2(bit)) - { - OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, bit); - add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, c | bit)); - } - else - { - add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, c)); - add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, oc)); - } - } - return cc + length; - - case OP_CLASS: - case OP_NCLASS: - if (check_str_ptr) - detect_partial_match(common, backtracks); - -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8 - bit = (common->utf && is_char7_bitset((const sljit_u8 *)cc, type == OP_NCLASS)) ? 127 : 255; - if (type == OP_NCLASS) - read_char(common, 0, bit, backtracks, READ_CHAR_UPDATE_STR_PTR); - else - read_char(common, 0, bit, NULL, 0); -#else - if (type == OP_NCLASS) - read_char(common, 0, 255, backtracks, READ_CHAR_UPDATE_STR_PTR); - else - read_char(common, 0, 255, NULL, 0); -#endif - - if (optimize_class(common, (const sljit_u8 *)cc, type == OP_NCLASS, FALSE, backtracks)) - return cc + 32 / sizeof(PCRE2_UCHAR); - -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8 - jump[0] = NULL; - if (common->utf) - { - jump[0] = CMP(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, bit); - if (type == OP_CLASS) - { - add_jump(compiler, backtracks, jump[0]); - jump[0] = NULL; - } - } -#elif PCRE2_CODE_UNIT_WIDTH != 8 - jump[0] = CMP(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, 255); - if (type == OP_CLASS) - { - add_jump(compiler, backtracks, jump[0]); - jump[0] = NULL; - } -#endif /* SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8 */ - - OP2(SLJIT_AND, TMP2, 0, TMP1, 0, SLJIT_IMM, 0x7); - OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, SLJIT_IMM, 3); - OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)cc); - OP2(SLJIT_SHL, TMP2, 0, SLJIT_IMM, 1, TMP2, 0); - OP2U(SLJIT_AND | SLJIT_SET_Z, TMP1, 0, TMP2, 0); - add_jump(compiler, backtracks, JUMP(SLJIT_ZERO)); - -#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8 - if (jump[0] != NULL) - JUMPHERE(jump[0]); -#endif - return cc + 32 / sizeof(PCRE2_UCHAR); - -#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32 - case OP_XCLASS: - if (check_str_ptr) - detect_partial_match(common, backtracks); - compile_xclass_matchingpath(common, cc + LINK_SIZE, backtracks); - return cc + GET(cc, 0) - 1; -#endif - } -SLJIT_UNREACHABLE(); -return cc; -} - -static SLJIT_INLINE PCRE2_SPTR compile_charn_matchingpath(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend, jump_list **backtracks) -{ -/* This function consumes at least one input character. */ -/* To decrease the number of length checks, we try to concatenate the fixed length character sequences. */ -DEFINE_COMPILER; -PCRE2_SPTR ccbegin = cc; -compare_context context; -int size; - -context.length = 0; -do - { - if (cc >= ccend) - break; - - if (*cc == OP_CHAR) - { - size = 1; -#ifdef SUPPORT_UNICODE - if (common->utf && HAS_EXTRALEN(cc[1])) - size += GET_EXTRALEN(cc[1]); -#endif - } - else if (*cc == OP_CHARI) - { - size = 1; -#ifdef SUPPORT_UNICODE - if (common->utf) - { - if (char_has_othercase(common, cc + 1) && char_get_othercase_bit(common, cc + 1) == 0) - size = 0; - else if (HAS_EXTRALEN(cc[1])) - size += GET_EXTRALEN(cc[1]); - } - else -#endif - if (char_has_othercase(common, cc + 1) && char_get_othercase_bit(common, cc + 1) == 0) - size = 0; - } - else - size = 0; - - cc += 1 + size; - context.length += IN_UCHARS(size); - } -while (size > 0 && context.length <= 128); - -cc = ccbegin; -if (context.length > 0) - { - /* We have a fixed-length byte sequence. */ - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, context.length); - add_jump(compiler, backtracks, CMP(SLJIT_GREATER, STR_PTR, 0, STR_END, 0)); - - context.sourcereg = -1; -#if defined SLJIT_UNALIGNED && SLJIT_UNALIGNED - context.ucharptr = 0; -#endif - do cc = byte_sequence_compare(common, *cc == OP_CHARI, cc + 1, &context, backtracks); while (context.length > 0); - return cc; - } - -/* A non-fixed length character will be checked if length == 0. */ -return compile_char1_matchingpath(common, *cc, cc + 1, backtracks, TRUE); -} - -/* Forward definitions. */ -static void compile_matchingpath(compiler_common *, PCRE2_SPTR, PCRE2_SPTR, backtrack_common *); -static void compile_backtrackingpath(compiler_common *, struct backtrack_common *); - -#define PUSH_BACKTRACK(size, ccstart, error) \ - do \ - { \ - backtrack = sljit_alloc_memory(compiler, (size)); \ - if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) \ - return error; \ - memset(backtrack, 0, size); \ - backtrack->prev = parent->top; \ - backtrack->cc = (ccstart); \ - parent->top = backtrack; \ - } \ - while (0) - -#define PUSH_BACKTRACK_NOVALUE(size, ccstart) \ - do \ - { \ - backtrack = sljit_alloc_memory(compiler, (size)); \ - if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) \ - return; \ - memset(backtrack, 0, size); \ - backtrack->prev = parent->top; \ - backtrack->cc = (ccstart); \ - parent->top = backtrack; \ - } \ - while (0) - -#define BACKTRACK_AS(type) ((type *)backtrack) - -static void compile_dnref_search(compiler_common *common, PCRE2_SPTR cc, jump_list **backtracks) -{ -/* The OVECTOR offset goes to TMP2. */ -DEFINE_COMPILER; -int count = GET2(cc, 1 + IMM2_SIZE); -PCRE2_SPTR slot = common->name_table + GET2(cc, 1) * common->name_entry_size; -unsigned int offset; -jump_list *found = NULL; - -SLJIT_ASSERT(*cc == OP_DNREF || *cc == OP_DNREFI); - -OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(1)); - -count--; -while (count-- > 0) - { - offset = GET2(slot, 0) << 1; - GET_LOCAL_BASE(TMP2, 0, OVECTOR(offset)); - add_jump(compiler, &found, CMP(SLJIT_NOT_EQUAL, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset), TMP1, 0)); - slot += common->name_entry_size; - } - -offset = GET2(slot, 0) << 1; -GET_LOCAL_BASE(TMP2, 0, OVECTOR(offset)); -if (backtracks != NULL && !common->unset_backref) - add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset), TMP1, 0)); - -set_jumps(found, LABEL()); -} - -static void compile_ref_matchingpath(compiler_common *common, PCRE2_SPTR cc, jump_list **backtracks, BOOL withchecks, BOOL emptyfail) -{ -DEFINE_COMPILER; -BOOL ref = (*cc == OP_REF || *cc == OP_REFI); -int offset = 0; -struct sljit_jump *jump = NULL; -struct sljit_jump *partial; -struct sljit_jump *nopartial; -#if defined SUPPORT_UNICODE -struct sljit_label *loop; -struct sljit_label *caseless_loop; -jump_list *no_match = NULL; -int source_reg = COUNT_MATCH; -int source_end_reg = ARGUMENTS; -int char1_reg = STACK_LIMIT; -#endif /* SUPPORT_UNICODE */ - -if (ref) - { - offset = GET2(cc, 1) << 1; - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset)); - /* OVECTOR(1) contains the "string begin - 1" constant. */ - if (withchecks && !common->unset_backref) - add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(1))); - } -else - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), 0); - -#if defined SUPPORT_UNICODE -if (common->utf && *cc == OP_REFI) - { - SLJIT_ASSERT(common->iref_ptr != 0); - - if (ref) - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1)); - else - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP2), sizeof(sljit_sw)); - - if (withchecks && emptyfail) - add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, TMP2, 0)); - - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->iref_ptr, source_reg, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->iref_ptr + sizeof(sljit_sw), source_end_reg, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->iref_ptr + sizeof(sljit_sw) * 2, char1_reg, 0); - - OP1(SLJIT_MOV, source_reg, 0, TMP1, 0); - OP1(SLJIT_MOV, source_end_reg, 0, TMP2, 0); - - loop = LABEL(); - jump = CMP(SLJIT_GREATER_EQUAL, source_reg, 0, source_end_reg, 0); - partial = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); - - /* Read original character. It must be a valid UTF character. */ - OP1(SLJIT_MOV, TMP3, 0, STR_PTR, 0); - OP1(SLJIT_MOV, STR_PTR, 0, source_reg, 0); - - read_char(common, 0, READ_CHAR_MAX, NULL, READ_CHAR_UPDATE_STR_PTR | READ_CHAR_VALID_UTF); - - OP1(SLJIT_MOV, source_reg, 0, STR_PTR, 0); - OP1(SLJIT_MOV, STR_PTR, 0, TMP3, 0); - OP1(SLJIT_MOV, char1_reg, 0, TMP1, 0); - - /* Read second character. */ - read_char(common, 0, READ_CHAR_MAX, &no_match, READ_CHAR_UPDATE_STR_PTR); - - CMPTO(SLJIT_EQUAL, TMP1, 0, char1_reg, 0, loop); - - OP1(SLJIT_MOV, TMP3, 0, TMP1, 0); - - add_jump(compiler, &common->getucd, JUMP(SLJIT_FAST_CALL)); - - OP2(SLJIT_SHL, TMP1, 0, TMP2, 0, SLJIT_IMM, 2); - OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 3); - OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, TMP1, 0); - - OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, SLJIT_IMM, (sljit_sw)PRIV(ucd_records)); - - OP1(SLJIT_MOV_S32, TMP1, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(ucd_record, other_case)); - OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(ucd_record, caseset)); - OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP3, 0); - CMPTO(SLJIT_EQUAL, TMP1, 0, char1_reg, 0, loop); - - add_jump(compiler, &no_match, CMP(SLJIT_EQUAL, TMP2, 0, SLJIT_IMM, 0)); - OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 2); - OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, SLJIT_IMM, (sljit_sw)PRIV(ucd_caseless_sets)); - - caseless_loop = LABEL(); - OP1(SLJIT_MOV_U32, TMP1, 0, SLJIT_MEM1(TMP2), 0); - OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, SLJIT_IMM, sizeof(uint32_t)); - OP2U(SLJIT_SUB | SLJIT_SET_Z | SLJIT_SET_LESS, TMP1, 0, char1_reg, 0); - JUMPTO(SLJIT_EQUAL, loop); - JUMPTO(SLJIT_LESS, caseless_loop); - - set_jumps(no_match, LABEL()); - if (common->mode == PCRE2_JIT_COMPLETE) - JUMPHERE(partial); - - OP1(SLJIT_MOV, source_reg, 0, SLJIT_MEM1(SLJIT_SP), common->iref_ptr); - OP1(SLJIT_MOV, source_end_reg, 0, SLJIT_MEM1(SLJIT_SP), common->iref_ptr + sizeof(sljit_sw)); - OP1(SLJIT_MOV, char1_reg, 0, SLJIT_MEM1(SLJIT_SP), common->iref_ptr + sizeof(sljit_sw) * 2); - add_jump(compiler, backtracks, JUMP(SLJIT_JUMP)); - - if (common->mode != PCRE2_JIT_COMPLETE) - { - JUMPHERE(partial); - OP1(SLJIT_MOV, source_reg, 0, SLJIT_MEM1(SLJIT_SP), common->iref_ptr); - OP1(SLJIT_MOV, source_end_reg, 0, SLJIT_MEM1(SLJIT_SP), common->iref_ptr + sizeof(sljit_sw)); - OP1(SLJIT_MOV, char1_reg, 0, SLJIT_MEM1(SLJIT_SP), common->iref_ptr + sizeof(sljit_sw) * 2); - - check_partial(common, FALSE); - add_jump(compiler, backtracks, JUMP(SLJIT_JUMP)); - } - - JUMPHERE(jump); - OP1(SLJIT_MOV, source_reg, 0, SLJIT_MEM1(SLJIT_SP), common->iref_ptr); - OP1(SLJIT_MOV, source_end_reg, 0, SLJIT_MEM1(SLJIT_SP), common->iref_ptr + sizeof(sljit_sw)); - OP1(SLJIT_MOV, char1_reg, 0, SLJIT_MEM1(SLJIT_SP), common->iref_ptr + sizeof(sljit_sw) * 2); - return; - } -else -#endif /* SUPPORT_UNICODE */ - { - if (ref) - OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), TMP1, 0); - else - OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, SLJIT_MEM1(TMP2), sizeof(sljit_sw), TMP1, 0); - - if (withchecks) - jump = JUMP(SLJIT_ZERO); - - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0); - partial = CMP(SLJIT_GREATER, STR_PTR, 0, STR_END, 0); - if (common->mode == PCRE2_JIT_COMPLETE) - add_jump(compiler, backtracks, partial); - - add_jump(compiler, *cc == OP_REF ? &common->casefulcmp : &common->caselesscmp, JUMP(SLJIT_FAST_CALL)); - add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0)); - - if (common->mode != PCRE2_JIT_COMPLETE) - { - nopartial = JUMP(SLJIT_JUMP); - JUMPHERE(partial); - /* TMP2 -= STR_END - STR_PTR */ - OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, STR_PTR, 0); - OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, STR_END, 0); - partial = CMP(SLJIT_EQUAL, TMP2, 0, SLJIT_IMM, 0); - OP1(SLJIT_MOV, STR_PTR, 0, STR_END, 0); - add_jump(compiler, *cc == OP_REF ? &common->casefulcmp : &common->caselesscmp, JUMP(SLJIT_FAST_CALL)); - add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0)); - JUMPHERE(partial); - check_partial(common, FALSE); - add_jump(compiler, backtracks, JUMP(SLJIT_JUMP)); - JUMPHERE(nopartial); - } - } - -if (jump != NULL) - { - if (emptyfail) - add_jump(compiler, backtracks, jump); - else - JUMPHERE(jump); - } -} - -static SLJIT_INLINE PCRE2_SPTR compile_ref_iterator_matchingpath(compiler_common *common, PCRE2_SPTR cc, backtrack_common *parent) -{ -DEFINE_COMPILER; -BOOL ref = (*cc == OP_REF || *cc == OP_REFI); -backtrack_common *backtrack; -PCRE2_UCHAR type; -int offset = 0; -struct sljit_label *label; -struct sljit_jump *zerolength; -struct sljit_jump *jump = NULL; -PCRE2_SPTR ccbegin = cc; -int min = 0, max = 0; -BOOL minimize; - -PUSH_BACKTRACK(sizeof(ref_iterator_backtrack), cc, NULL); - -if (ref) - offset = GET2(cc, 1) << 1; -else - cc += IMM2_SIZE; -type = cc[1 + IMM2_SIZE]; - -SLJIT_COMPILE_ASSERT((OP_CRSTAR & 0x1) == 0, crstar_opcode_must_be_even); -minimize = (type & 0x1) != 0; -switch(type) - { - case OP_CRSTAR: - case OP_CRMINSTAR: - min = 0; - max = 0; - cc += 1 + IMM2_SIZE + 1; - break; - case OP_CRPLUS: - case OP_CRMINPLUS: - min = 1; - max = 0; - cc += 1 + IMM2_SIZE + 1; - break; - case OP_CRQUERY: - case OP_CRMINQUERY: - min = 0; - max = 1; - cc += 1 + IMM2_SIZE + 1; - break; - case OP_CRRANGE: - case OP_CRMINRANGE: - min = GET2(cc, 1 + IMM2_SIZE + 1); - max = GET2(cc, 1 + IMM2_SIZE + 1 + IMM2_SIZE); - cc += 1 + IMM2_SIZE + 1 + 2 * IMM2_SIZE; - break; - default: - SLJIT_UNREACHABLE(); - break; - } - -if (!minimize) - { - if (min == 0) - { - allocate_stack(common, 2); - if (ref) - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset)); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, 0); - /* Temporary release of STR_PTR. */ - OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw)); - /* Handles both invalid and empty cases. Since the minimum repeat, - is zero the invalid case is basically the same as an empty case. */ - if (ref) - zerolength = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1)); - else - { - compile_dnref_search(common, ccbegin, NULL); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), 0); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE1, TMP2, 0); - zerolength = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(TMP2), sizeof(sljit_sw)); - } - /* Restore if not zero length. */ - OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw)); - } - else - { - allocate_stack(common, 1); - if (ref) - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset)); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); - if (ref) - { - add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(1))); - zerolength = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1)); - } - else - { - compile_dnref_search(common, ccbegin, &backtrack->topbacktracks); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), 0); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE1, TMP2, 0); - zerolength = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(TMP2), sizeof(sljit_sw)); - } - } - - if (min > 1 || max > 1) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE0, SLJIT_IMM, 0); - - label = LABEL(); - if (!ref) - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), POSSESSIVE1); - compile_ref_matchingpath(common, ccbegin, &backtrack->topbacktracks, FALSE, FALSE); - - if (min > 1 || max > 1) - { - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), POSSESSIVE0); - OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 1); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE0, TMP1, 0); - if (min > 1) - CMPTO(SLJIT_LESS, TMP1, 0, SLJIT_IMM, min, label); - if (max > 1) - { - jump = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, max); - allocate_stack(common, 1); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); - JUMPTO(SLJIT_JUMP, label); - JUMPHERE(jump); - } - } - - if (max == 0) - { - /* Includes min > 1 case as well. */ - allocate_stack(common, 1); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); - JUMPTO(SLJIT_JUMP, label); - } - - JUMPHERE(zerolength); - BACKTRACK_AS(ref_iterator_backtrack)->matchingpath = LABEL(); - - count_match(common); - return cc; - } - -allocate_stack(common, ref ? 2 : 3); -if (ref) - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset)); -OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); -if (type != OP_CRMINSTAR) - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, 0); - -if (min == 0) - { - /* Handles both invalid and empty cases. Since the minimum repeat, - is zero the invalid case is basically the same as an empty case. */ - if (ref) - zerolength = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1)); - else - { - compile_dnref_search(common, ccbegin, NULL); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), 0); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(2), TMP2, 0); - zerolength = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(TMP2), sizeof(sljit_sw)); - } - /* Length is non-zero, we can match real repeats. */ - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); - jump = JUMP(SLJIT_JUMP); - } -else - { - if (ref) - { - add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(1))); - zerolength = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1)); - } - else - { - compile_dnref_search(common, ccbegin, &backtrack->topbacktracks); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), 0); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(2), TMP2, 0); - zerolength = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(TMP2), sizeof(sljit_sw)); - } - } - -BACKTRACK_AS(ref_iterator_backtrack)->matchingpath = LABEL(); -if (max > 0) - add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_GREATER_EQUAL, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, max)); - -if (!ref) - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(2)); -compile_ref_matchingpath(common, ccbegin, &backtrack->topbacktracks, TRUE, TRUE); -OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); - -if (min > 1) - { - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(1)); - OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 1); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP1, 0); - CMPTO(SLJIT_LESS, TMP1, 0, SLJIT_IMM, min, BACKTRACK_AS(ref_iterator_backtrack)->matchingpath); - } -else if (max > 0) - OP2(SLJIT_ADD, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, 1); - -if (jump != NULL) - JUMPHERE(jump); -JUMPHERE(zerolength); - -count_match(common); -return cc; -} - -static SLJIT_INLINE PCRE2_SPTR compile_recurse_matchingpath(compiler_common *common, PCRE2_SPTR cc, backtrack_common *parent) -{ -DEFINE_COMPILER; -backtrack_common *backtrack; -recurse_entry *entry = common->entries; -recurse_entry *prev = NULL; -sljit_sw start = GET(cc, 1); -PCRE2_SPTR start_cc; -BOOL needs_control_head; - -PUSH_BACKTRACK(sizeof(recurse_backtrack), cc, NULL); - -/* Inlining simple patterns. */ -if (get_framesize(common, common->start + start, NULL, TRUE, &needs_control_head) == no_stack) - { - start_cc = common->start + start; - compile_matchingpath(common, next_opcode(common, start_cc), bracketend(start_cc) - (1 + LINK_SIZE), backtrack); - BACKTRACK_AS(recurse_backtrack)->inlined_pattern = TRUE; - return cc + 1 + LINK_SIZE; - } - -while (entry != NULL) - { - if (entry->start == start) - break; - prev = entry; - entry = entry->next; - } - -if (entry == NULL) - { - entry = sljit_alloc_memory(compiler, sizeof(recurse_entry)); - if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) - return NULL; - entry->next = NULL; - entry->entry_label = NULL; - entry->backtrack_label = NULL; - entry->entry_calls = NULL; - entry->backtrack_calls = NULL; - entry->start = start; - - if (prev != NULL) - prev->next = entry; - else - common->entries = entry; - } - -BACKTRACK_AS(recurse_backtrack)->entry = entry; - -if (entry->entry_label == NULL) - add_jump(compiler, &entry->entry_calls, JUMP(SLJIT_FAST_CALL)); -else - JUMPTO(SLJIT_FAST_CALL, entry->entry_label); -/* Leave if the match is failed. */ -add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0)); -BACKTRACK_AS(recurse_backtrack)->matchingpath = LABEL(); -return cc + 1 + LINK_SIZE; -} - -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; -sljit_u32 oveccount, capture_top; - -if (arguments->callout == NULL) - return 0; - -SLJIT_COMPILE_ASSERT(sizeof (PCRE2_SIZE) <= sizeof (sljit_sw), pcre2_size_must_be_lower_than_sljit_sw_size); - -begin = arguments->begin; -ovector = (PCRE2_SIZE*)(callout_block + 1); -oveccount = callout_block->capture_top; - -SLJIT_ASSERT(oveccount >= 1); - -callout_block->version = 2; -callout_block->callout_flags = 0; - -/* Offsets in subject. */ -callout_block->subject_length = arguments->end - arguments->begin; -callout_block->start_match = jit_ovector[0] - begin; -callout_block->current_position = (PCRE2_SPTR)callout_block->offset_vector - begin; -callout_block->subject = begin; - -/* Convert and copy the JIT offset vector to the ovector array. */ -callout_block->capture_top = 1; -callout_block->offset_vector = ovector; - -ovector[0] = PCRE2_UNSET; -ovector[1] = PCRE2_UNSET; -ovector += 2; -jit_ovector += 2; -capture_top = 1; - -/* Convert pointers to sizes. */ -while (--oveccount != 0) - { - capture_top++; - - ovector[0] = (PCRE2_SIZE)(jit_ovector[0] - begin); - ovector[1] = (PCRE2_SIZE)(jit_ovector[1] - begin); - - if (ovector[0] != PCRE2_UNSET) - callout_block->capture_top = capture_top; - - ovector += 2; - jit_ovector += 2; - } - -return (arguments->callout)(callout_block, arguments->callout_data); -} - -#define CALLOUT_ARG_OFFSET(arg) \ - SLJIT_OFFSETOF(pcre2_callout_block, arg) - -static SLJIT_INLINE PCRE2_SPTR compile_callout_matchingpath(compiler_common *common, PCRE2_SPTR cc, backtrack_common *parent) -{ -DEFINE_COMPILER; -backtrack_common *backtrack; -sljit_s32 mov_opcode; -unsigned int callout_length = (*cc == OP_CALLOUT) - ? PRIV(OP_lengths)[OP_CALLOUT] : GET(cc, 1 + 2 * LINK_SIZE); -sljit_sw value1; -sljit_sw value2; -sljit_sw value3; -sljit_uw callout_arg_size = (common->re->top_bracket + 1) * 2 * SSIZE_OF(sw); - -PUSH_BACKTRACK(sizeof(backtrack_common), cc, NULL); - -callout_arg_size = (sizeof(pcre2_callout_block) + callout_arg_size + sizeof(sljit_sw) - 1) / sizeof(sljit_sw); - -allocate_stack(common, callout_arg_size); - -SLJIT_ASSERT(common->capture_last_ptr != 0); -OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr); -OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0); -value1 = (*cc == OP_CALLOUT) ? cc[1 + 2 * LINK_SIZE] : 0; -OP1(SLJIT_MOV_U32, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(callout_number), SLJIT_IMM, value1); -OP1(SLJIT_MOV_U32, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(capture_last), TMP2, 0); -OP1(SLJIT_MOV_U32, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(capture_top), SLJIT_IMM, common->re->top_bracket + 1); - -/* These pointer sized fields temporarly stores internal variables. */ -OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(offset_vector), STR_PTR, 0); - -if (common->mark_ptr != 0) - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, mark_ptr)); -mov_opcode = (sizeof(PCRE2_SIZE) == 4) ? SLJIT_MOV_U32 : SLJIT_MOV; -OP1(mov_opcode, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(pattern_position), SLJIT_IMM, GET(cc, 1)); -OP1(mov_opcode, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(next_item_length), SLJIT_IMM, GET(cc, 1 + LINK_SIZE)); - -if (*cc == OP_CALLOUT) - { - value1 = 0; - value2 = 0; - value3 = 0; - } -else - { - value1 = (sljit_sw) (cc + (1 + 4*LINK_SIZE) + 1); - value2 = (callout_length - (1 + 4*LINK_SIZE + 2)); - value3 = (sljit_sw) (GET(cc, 1 + 3*LINK_SIZE)); - } - -OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(callout_string), SLJIT_IMM, value1); -OP1(mov_opcode, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(callout_string_length), SLJIT_IMM, value2); -OP1(mov_opcode, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(callout_string_offset), SLJIT_IMM, value3); -OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(mark), (common->mark_ptr != 0) ? TMP2 : SLJIT_IMM, 0); - -SLJIT_ASSERT(TMP1 == SLJIT_R0 && STR_PTR == SLJIT_R1); - -/* Needed to save important temporary registers. */ -OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS0, STR_PTR, 0); -/* SLJIT_R0 = arguments */ -OP1(SLJIT_MOV, SLJIT_R1, 0, STACK_TOP, 0); -GET_LOCAL_BASE(SLJIT_R2, 0, OVECTOR_START); -sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_ARGS3(32, W, W, W), SLJIT_IMM, SLJIT_FUNC_ADDR(do_callout_jit)); -OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0); -free_stack(common, callout_arg_size); - -/* Check return value. */ -OP2U(SLJIT_SUB32 | SLJIT_SET_Z | SLJIT_SET_SIG_GREATER, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0); -add_jump(compiler, &backtrack->topbacktracks, JUMP(SLJIT_SIG_GREATER)); -if (common->abort_label == NULL) - add_jump(compiler, &common->abort, JUMP(SLJIT_NOT_EQUAL) /* SIG_LESS */); -else - JUMPTO(SLJIT_NOT_EQUAL /* SIG_LESS */, common->abort_label); -return cc + callout_length; -} - -#undef CALLOUT_ARG_SIZE -#undef CALLOUT_ARG_OFFSET - -static SLJIT_INLINE BOOL assert_needs_str_ptr_saving(PCRE2_SPTR cc) -{ -while (TRUE) - { - switch (*cc) - { - case OP_CALLOUT_STR: - cc += GET(cc, 1 + 2*LINK_SIZE); - break; - - case OP_NOT_WORD_BOUNDARY: - case OP_WORD_BOUNDARY: - case OP_CIRC: - case OP_CIRCM: - case OP_DOLL: - case OP_DOLLM: - case OP_CALLOUT: - case OP_ALT: - cc += PRIV(OP_lengths)[*cc]; - break; - - case OP_KET: - return FALSE; - - default: - return TRUE; - } - } -} - -static PCRE2_SPTR compile_assert_matchingpath(compiler_common *common, PCRE2_SPTR cc, assert_backtrack *backtrack, BOOL conditional) -{ -DEFINE_COMPILER; -int framesize; -int extrasize; -BOOL local_quit_available = FALSE; -BOOL needs_control_head; -int private_data_ptr; -backtrack_common altbacktrack; -PCRE2_SPTR ccbegin; -PCRE2_UCHAR opcode; -PCRE2_UCHAR bra = OP_BRA; -jump_list *tmp = NULL; -jump_list **target = (conditional) ? &backtrack->condfailed : &backtrack->common.topbacktracks; -jump_list **found; -/* Saving previous accept variables. */ -BOOL save_local_quit_available = common->local_quit_available; -BOOL save_in_positive_assertion = common->in_positive_assertion; -then_trap_backtrack *save_then_trap = common->then_trap; -struct sljit_label *save_quit_label = common->quit_label; -struct sljit_label *save_accept_label = common->accept_label; -jump_list *save_quit = common->quit; -jump_list *save_positive_assertion_quit = common->positive_assertion_quit; -jump_list *save_accept = common->accept; -struct sljit_jump *jump; -struct sljit_jump *brajump = NULL; - -/* Assert captures then. */ -common->then_trap = NULL; - -if (*cc == OP_BRAZERO || *cc == OP_BRAMINZERO) - { - SLJIT_ASSERT(!conditional); - bra = *cc; - cc++; - } -private_data_ptr = PRIVATE_DATA(cc); -SLJIT_ASSERT(private_data_ptr != 0); -framesize = get_framesize(common, cc, NULL, FALSE, &needs_control_head); -backtrack->framesize = framesize; -backtrack->private_data_ptr = private_data_ptr; -opcode = *cc; -SLJIT_ASSERT(opcode >= OP_ASSERT && opcode <= OP_ASSERTBACK_NOT); -found = (opcode == OP_ASSERT || opcode == OP_ASSERTBACK) ? &tmp : target; -ccbegin = cc; -cc += GET(cc, 1); - -if (bra == OP_BRAMINZERO) - { - /* This is a braminzero backtrack path. */ - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - free_stack(common, 1); - brajump = CMP(SLJIT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0); - } - -if (framesize < 0) - { - extrasize = 1; - if (bra == OP_BRA && !assert_needs_str_ptr_saving(ccbegin + 1 + LINK_SIZE)) - extrasize = 0; - - if (needs_control_head) - extrasize++; - - if (framesize == no_frame) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STACK_TOP, 0); - - if (extrasize > 0) - allocate_stack(common, extrasize); - - if (needs_control_head) - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr); - - if (extrasize > 0) - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); - - if (needs_control_head) - { - SLJIT_ASSERT(extrasize == 2); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_IMM, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP1, 0); - } - } -else - { - extrasize = needs_control_head ? 3 : 2; - allocate_stack(common, framesize + extrasize); - - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); - OP2(SLJIT_ADD, TMP2, 0, STACK_TOP, 0, SLJIT_IMM, (framesize + extrasize) * sizeof(sljit_sw)); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP2, 0); - if (needs_control_head) - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); - - if (needs_control_head) - { - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(2), TMP1, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP2, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_IMM, 0); - } - else - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP1, 0); - - init_frame(common, ccbegin, NULL, framesize + extrasize - 1, extrasize); - } - -memset(&altbacktrack, 0, sizeof(backtrack_common)); -if (conditional || (opcode == OP_ASSERT_NOT || opcode == OP_ASSERTBACK_NOT)) - { - /* Control verbs cannot escape from these asserts. */ - local_quit_available = TRUE; - common->local_quit_available = TRUE; - common->quit_label = NULL; - common->quit = NULL; - } - -common->in_positive_assertion = (opcode == OP_ASSERT || opcode == OP_ASSERTBACK); -common->positive_assertion_quit = NULL; - -while (1) - { - common->accept_label = NULL; - common->accept = NULL; - altbacktrack.top = NULL; - altbacktrack.topbacktracks = NULL; - - if (*ccbegin == OP_ALT && extrasize > 0) - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - - altbacktrack.cc = ccbegin; - compile_matchingpath(common, ccbegin + 1 + LINK_SIZE, cc, &altbacktrack); - if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) - { - if (local_quit_available) - { - common->local_quit_available = save_local_quit_available; - common->quit_label = save_quit_label; - common->quit = save_quit; - } - common->in_positive_assertion = save_in_positive_assertion; - common->then_trap = save_then_trap; - common->accept_label = save_accept_label; - common->positive_assertion_quit = save_positive_assertion_quit; - common->accept = save_accept; - return NULL; - } - common->accept_label = LABEL(); - if (common->accept != NULL) - set_jumps(common->accept, common->accept_label); - - /* Reset stack. */ - if (framesize < 0) - { - if (framesize == no_frame) - OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); - else if (extrasize > 0) - free_stack(common, extrasize); - - if (needs_control_head) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), STACK(-1)); - } - else - { - if ((opcode != OP_ASSERT_NOT && opcode != OP_ASSERTBACK_NOT) || conditional) - { - /* We don't need to keep the STR_PTR, only the previous private_data_ptr. */ - OP2(SLJIT_SUB, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, (framesize + 1) * sizeof(sljit_sw)); - if (needs_control_head) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), STACK(-1)); - } - else - { - OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); - if (needs_control_head) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), STACK(-framesize - 2)); - add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL)); - OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (framesize - 1) * sizeof(sljit_sw)); - } - } - - if (opcode == OP_ASSERT_NOT || opcode == OP_ASSERTBACK_NOT) - { - /* We know that STR_PTR was stored on the top of the stack. */ - if (conditional) - { - if (extrasize > 0) - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), needs_control_head ? STACK(-2) : STACK(-1)); - } - else if (bra == OP_BRAZERO) - { - if (framesize < 0) - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(-extrasize)); - else - { - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(-framesize - 1)); - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(-framesize - extrasize)); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP1, 0); - } - OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw)); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); - } - else if (framesize >= 0) - { - /* For OP_BRA and OP_BRAMINZERO. */ - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_MEM1(STACK_TOP), STACK(-framesize - 1)); - } - } - add_jump(compiler, found, JUMP(SLJIT_JUMP)); - - compile_backtrackingpath(common, altbacktrack.top); - if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) - { - if (local_quit_available) - { - common->local_quit_available = save_local_quit_available; - common->quit_label = save_quit_label; - common->quit = save_quit; - } - common->in_positive_assertion = save_in_positive_assertion; - common->then_trap = save_then_trap; - common->accept_label = save_accept_label; - common->positive_assertion_quit = save_positive_assertion_quit; - common->accept = save_accept; - return NULL; - } - set_jumps(altbacktrack.topbacktracks, LABEL()); - - if (*cc != OP_ALT) - break; - - ccbegin = cc; - cc += GET(cc, 1); - } - -if (local_quit_available) - { - SLJIT_ASSERT(common->positive_assertion_quit == NULL); - /* Makes the check less complicated below. */ - common->positive_assertion_quit = common->quit; - } - -/* None of them matched. */ -if (common->positive_assertion_quit != NULL) - { - jump = JUMP(SLJIT_JUMP); - set_jumps(common->positive_assertion_quit, LABEL()); - SLJIT_ASSERT(framesize != no_stack); - if (framesize < 0) - OP2(SLJIT_SUB, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, extrasize * sizeof(sljit_sw)); - else - { - OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); - add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL)); - OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (extrasize + 1) * sizeof(sljit_sw)); - } - JUMPHERE(jump); - } - -if (needs_control_head) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), STACK(1)); - -if (opcode == OP_ASSERT || opcode == OP_ASSERTBACK) - { - /* Assert is failed. */ - if ((conditional && extrasize > 0) || bra == OP_BRAZERO) - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - - if (framesize < 0) - { - /* The topmost item should be 0. */ - if (bra == OP_BRAZERO) - { - if (extrasize == 2) - free_stack(common, 1); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); - } - else if (extrasize > 0) - free_stack(common, extrasize); - } - else - { - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(extrasize - 1)); - /* The topmost item should be 0. */ - if (bra == OP_BRAZERO) - { - free_stack(common, framesize + extrasize - 1); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); - } - else - free_stack(common, framesize + extrasize); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP1, 0); - } - jump = JUMP(SLJIT_JUMP); - if (bra != OP_BRAZERO) - add_jump(compiler, target, jump); - - /* Assert is successful. */ - set_jumps(tmp, LABEL()); - if (framesize < 0) - { - /* We know that STR_PTR was stored on the top of the stack. */ - if (extrasize > 0) - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(-extrasize)); - - /* Keep the STR_PTR on the top of the stack. */ - if (bra == OP_BRAZERO) - { - OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw)); - if (extrasize == 2) - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); - } - else if (bra == OP_BRAMINZERO) - { - OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw)); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); - } - } - else - { - if (bra == OP_BRA) - { - /* We don't need to keep the STR_PTR, only the previous private_data_ptr. */ - OP2(SLJIT_SUB, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, (framesize + 1) * sizeof(sljit_sw)); - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(-extrasize + 1)); - } - else - { - /* We don't need to keep the STR_PTR, only the previous private_data_ptr. */ - OP2(SLJIT_SUB, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, (framesize + 2) * sizeof(sljit_sw)); - if (extrasize == 2) - { - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - if (bra == OP_BRAMINZERO) - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); - } - else - { - SLJIT_ASSERT(extrasize == 3); - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(-1)); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), bra == OP_BRAZERO ? STR_PTR : SLJIT_IMM, 0); - } - } - } - - if (bra == OP_BRAZERO) - { - backtrack->matchingpath = LABEL(); - SET_LABEL(jump, backtrack->matchingpath); - } - else if (bra == OP_BRAMINZERO) - { - JUMPTO(SLJIT_JUMP, backtrack->matchingpath); - JUMPHERE(brajump); - if (framesize >= 0) - { - OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); - add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL)); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(-2)); - OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (framesize - 1) * sizeof(sljit_sw)); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP1, 0); - } - set_jumps(backtrack->common.topbacktracks, LABEL()); - } - } -else - { - /* AssertNot is successful. */ - if (framesize < 0) - { - if (extrasize > 0) - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - - if (bra != OP_BRA) - { - if (extrasize == 2) - free_stack(common, 1); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); - } - else if (extrasize > 0) - free_stack(common, extrasize); - } - else - { - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(extrasize - 1)); - /* The topmost item should be 0. */ - if (bra != OP_BRA) - { - free_stack(common, framesize + extrasize - 1); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); - } - else - free_stack(common, framesize + extrasize); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP1, 0); - } - - if (bra == OP_BRAZERO) - backtrack->matchingpath = LABEL(); - else if (bra == OP_BRAMINZERO) - { - JUMPTO(SLJIT_JUMP, backtrack->matchingpath); - JUMPHERE(brajump); - } - - if (bra != OP_BRA) - { - SLJIT_ASSERT(found == &backtrack->common.topbacktracks); - set_jumps(backtrack->common.topbacktracks, LABEL()); - backtrack->common.topbacktracks = NULL; - } - } - -if (local_quit_available) - { - common->local_quit_available = save_local_quit_available; - common->quit_label = save_quit_label; - common->quit = save_quit; - } -common->in_positive_assertion = save_in_positive_assertion; -common->then_trap = save_then_trap; -common->accept_label = save_accept_label; -common->positive_assertion_quit = save_positive_assertion_quit; -common->accept = save_accept; -return cc + 1 + LINK_SIZE; -} - -static SLJIT_INLINE void match_once_common(compiler_common *common, PCRE2_UCHAR ket, int framesize, int private_data_ptr, BOOL has_alternatives, BOOL needs_control_head) -{ -DEFINE_COMPILER; -int stacksize; - -if (framesize < 0) - { - if (framesize == no_frame) - OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); - else - { - stacksize = needs_control_head ? 1 : 0; - if (ket != OP_KET || has_alternatives) - stacksize++; - - if (stacksize > 0) - free_stack(common, stacksize); - } - - if (needs_control_head) - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), (ket != OP_KET || has_alternatives) ? STACK(-2) : STACK(-1)); - - /* TMP2 which is set here used by OP_KETRMAX below. */ - if (ket == OP_KETRMAX) - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(-1)); - else if (ket == OP_KETRMIN) - { - /* Move the STR_PTR to the private_data_ptr. */ - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_MEM1(STACK_TOP), STACK(-1)); - } - } -else - { - stacksize = (ket != OP_KET || has_alternatives) ? 2 : 1; - OP2(SLJIT_SUB, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, (framesize + stacksize) * sizeof(sljit_sw)); - if (needs_control_head) - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(-1)); - - if (ket == OP_KETRMAX) - { - /* TMP2 which is set here used by OP_KETRMAX below. */ - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - } - } -if (needs_control_head) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, TMP1, 0); -} - -static SLJIT_INLINE int match_capture_common(compiler_common *common, int stacksize, int offset, int private_data_ptr) -{ -DEFINE_COMPILER; - -if (common->capture_last_ptr != 0) - { - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr, SLJIT_IMM, offset >> 1); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), TMP1, 0); - stacksize++; - } -if (common->optimized_cbracket[offset >> 1] == 0) - { - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset)); - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1)); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), TMP1, 0); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize + 1), TMP2, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), STR_PTR, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset), TMP1, 0); - stacksize += 2; - } -return stacksize; -} - -static PCRE2_SPTR SLJIT_FUNC do_script_run(PCRE2_SPTR ptr, PCRE2_SPTR endptr) -{ - if (PRIV(script_run)(ptr, endptr, FALSE)) - return endptr; - return NULL; -} - -#ifdef SUPPORT_UNICODE - -static PCRE2_SPTR SLJIT_FUNC do_script_run_utf(PCRE2_SPTR ptr, PCRE2_SPTR endptr) -{ - if (PRIV(script_run)(ptr, endptr, TRUE)) - return endptr; - return NULL; -} - -#endif /* SUPPORT_UNICODE */ - -static SLJIT_INLINE void match_script_run_common(compiler_common *common, int private_data_ptr, backtrack_common *parent) -{ -DEFINE_COMPILER; - -SLJIT_ASSERT(TMP1 == SLJIT_R0 && STR_PTR == SLJIT_R1); - -OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); -#ifdef SUPPORT_UNICODE -sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_ARGS2(W, W, W), SLJIT_IMM, - common->utf ? SLJIT_FUNC_ADDR(do_script_run_utf) : SLJIT_FUNC_ADDR(do_script_run)); -#else -sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_ARGS2(W, W, W), SLJIT_IMM, SLJIT_FUNC_ADDR(do_script_run)); -#endif - -OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_RETURN_REG, 0); -add_jump(compiler, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks, CMP(SLJIT_EQUAL, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0)); -} - -/* - Handling bracketed expressions is probably the most complex part. - - Stack layout naming characters: - S - Push the current STR_PTR - 0 - Push a 0 (NULL) - A - Push the current STR_PTR. Needed for restoring the STR_PTR - before the next alternative. Not pushed if there are no alternatives. - M - Any values pushed by the current alternative. Can be empty, or anything. - C - Push the previous OVECTOR(i), OVECTOR(i+1) and OVECTOR_PRIV(i) to the stack. - L - Push the previous local (pointed by localptr) to the stack - () - opional values stored on the stack - ()* - optonal, can be stored multiple times - - The following list shows the regular expression templates, their PCRE byte codes - and stack layout supported by pcre-sljit. - - (?:) OP_BRA | OP_KET A M - () OP_CBRA | OP_KET C M - (?:)+ OP_BRA | OP_KETRMAX 0 A M S ( A M S )* - OP_SBRA | OP_KETRMAX 0 L M S ( L M S )* - (?:)+? OP_BRA | OP_KETRMIN 0 A M S ( A M S )* - OP_SBRA | OP_KETRMIN 0 L M S ( L M S )* - ()+ OP_CBRA | OP_KETRMAX 0 C M S ( C M S )* - OP_SCBRA | OP_KETRMAX 0 C M S ( C M S )* - ()+? OP_CBRA | OP_KETRMIN 0 C M S ( C M S )* - OP_SCBRA | OP_KETRMIN 0 C M S ( C M S )* - (?:)? OP_BRAZERO | OP_BRA | OP_KET S ( A M 0 ) - (?:)?? OP_BRAMINZERO | OP_BRA | OP_KET S ( A M 0 ) - ()? OP_BRAZERO | OP_CBRA | OP_KET S ( C M 0 ) - ()?? OP_BRAMINZERO | OP_CBRA | OP_KET S ( C M 0 ) - (?:)* OP_BRAZERO | OP_BRA | OP_KETRMAX S 0 ( A M S )* - OP_BRAZERO | OP_SBRA | OP_KETRMAX S 0 ( L M S )* - (?:)*? OP_BRAMINZERO | OP_BRA | OP_KETRMIN S 0 ( A M S )* - OP_BRAMINZERO | OP_SBRA | OP_KETRMIN S 0 ( L M S )* - ()* OP_BRAZERO | OP_CBRA | OP_KETRMAX S 0 ( C M S )* - OP_BRAZERO | OP_SCBRA | OP_KETRMAX S 0 ( C M S )* - ()*? OP_BRAMINZERO | OP_CBRA | OP_KETRMIN S 0 ( C M S )* - OP_BRAMINZERO | OP_SCBRA | OP_KETRMIN S 0 ( C M S )* - - - Stack layout naming characters: - A - Push the alternative index (starting from 0) on the stack. - Not pushed if there is no alternatives. - M - Any values pushed by the current alternative. Can be empty, or anything. - - The next list shows the possible content of a bracket: - (|) OP_*BRA | OP_ALT ... M A - (?()|) OP_*COND | OP_ALT M A - (?>|) OP_ONCE | OP_ALT ... [stack trace] M A - Or nothing, if trace is unnecessary -*/ - -static PCRE2_SPTR compile_bracket_matchingpath(compiler_common *common, PCRE2_SPTR cc, backtrack_common *parent) -{ -DEFINE_COMPILER; -backtrack_common *backtrack; -PCRE2_UCHAR opcode; -int private_data_ptr = 0; -int offset = 0; -int i, stacksize; -int repeat_ptr = 0, repeat_length = 0; -int repeat_type = 0, repeat_count = 0; -PCRE2_SPTR ccbegin; -PCRE2_SPTR matchingpath; -PCRE2_SPTR slot; -PCRE2_UCHAR bra = OP_BRA; -PCRE2_UCHAR ket; -assert_backtrack *assert; -BOOL has_alternatives; -BOOL needs_control_head = FALSE; -struct sljit_jump *jump; -struct sljit_jump *skip; -struct sljit_label *rmax_label = NULL; -struct sljit_jump *braminzero = NULL; - -PUSH_BACKTRACK(sizeof(bracket_backtrack), cc, NULL); - -if (*cc == OP_BRAZERO || *cc == OP_BRAMINZERO) - { - bra = *cc; - cc++; - opcode = *cc; - } - -opcode = *cc; -ccbegin = cc; -matchingpath = bracketend(cc) - 1 - LINK_SIZE; -ket = *matchingpath; -if (ket == OP_KET && PRIVATE_DATA(matchingpath) != 0) - { - repeat_ptr = PRIVATE_DATA(matchingpath); - repeat_length = PRIVATE_DATA(matchingpath + 1); - repeat_type = PRIVATE_DATA(matchingpath + 2); - repeat_count = PRIVATE_DATA(matchingpath + 3); - SLJIT_ASSERT(repeat_length != 0 && repeat_type != 0 && repeat_count != 0); - if (repeat_type == OP_UPTO) - ket = OP_KETRMAX; - if (repeat_type == OP_MINUPTO) - ket = OP_KETRMIN; - } - -matchingpath = ccbegin + 1 + LINK_SIZE; -SLJIT_ASSERT(ket == OP_KET || ket == OP_KETRMAX || ket == OP_KETRMIN); -SLJIT_ASSERT(!((bra == OP_BRAZERO && ket == OP_KETRMIN) || (bra == OP_BRAMINZERO && ket == OP_KETRMAX))); -cc += GET(cc, 1); - -has_alternatives = *cc == OP_ALT; -if (SLJIT_UNLIKELY(opcode == OP_COND || opcode == OP_SCOND)) - { - SLJIT_COMPILE_ASSERT(OP_DNRREF == OP_RREF + 1 && OP_FALSE == OP_RREF + 2 && OP_TRUE == OP_RREF + 3, - compile_time_checks_must_be_grouped_together); - has_alternatives = ((*matchingpath >= OP_RREF && *matchingpath <= OP_TRUE) || *matchingpath == OP_FAIL) ? FALSE : TRUE; - } - -if (SLJIT_UNLIKELY(opcode == OP_COND) && (*cc == OP_KETRMAX || *cc == OP_KETRMIN)) - opcode = OP_SCOND; - -if (opcode == OP_CBRA || opcode == OP_SCBRA) - { - /* Capturing brackets has a pre-allocated space. */ - offset = GET2(ccbegin, 1 + LINK_SIZE); - if (common->optimized_cbracket[offset] == 0) - { - private_data_ptr = OVECTOR_PRIV(offset); - offset <<= 1; - } - else - { - offset <<= 1; - private_data_ptr = OVECTOR(offset); - } - BACKTRACK_AS(bracket_backtrack)->private_data_ptr = private_data_ptr; - matchingpath += IMM2_SIZE; - } -else if (opcode == OP_ASSERT_NA || opcode == OP_ASSERTBACK_NA || opcode == OP_ONCE || opcode == OP_SCRIPT_RUN || opcode == OP_SBRA || opcode == OP_SCOND) - { - /* Other brackets simply allocate the next entry. */ - private_data_ptr = PRIVATE_DATA(ccbegin); - SLJIT_ASSERT(private_data_ptr != 0); - BACKTRACK_AS(bracket_backtrack)->private_data_ptr = private_data_ptr; - if (opcode == OP_ONCE) - BACKTRACK_AS(bracket_backtrack)->u.framesize = get_framesize(common, ccbegin, NULL, FALSE, &needs_control_head); - } - -/* Instructions before the first alternative. */ -stacksize = 0; -if (ket == OP_KETRMAX || (ket == OP_KETRMIN && bra != OP_BRAMINZERO)) - stacksize++; -if (bra == OP_BRAZERO) - stacksize++; - -if (stacksize > 0) - allocate_stack(common, stacksize); - -stacksize = 0; -if (ket == OP_KETRMAX || (ket == OP_KETRMIN && bra != OP_BRAMINZERO)) - { - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), SLJIT_IMM, 0); - stacksize++; - } - -if (bra == OP_BRAZERO) - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), STR_PTR, 0); - -if (bra == OP_BRAMINZERO) - { - /* This is a backtrack path! (Since the try-path of OP_BRAMINZERO matches to the empty string) */ - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - if (ket != OP_KETRMIN) - { - free_stack(common, 1); - braminzero = CMP(SLJIT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0); - } - else if (opcode == OP_ONCE || opcode >= OP_SBRA) - { - jump = CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0); - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(1)); - /* Nothing stored during the first run. */ - skip = JUMP(SLJIT_JUMP); - JUMPHERE(jump); - /* Checking zero-length iteration. */ - if (opcode != OP_ONCE || BACKTRACK_AS(bracket_backtrack)->u.framesize < 0) - { - /* When we come from outside, private_data_ptr contains the previous STR_PTR. */ - braminzero = CMP(SLJIT_EQUAL, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); - } - else - { - /* Except when the whole stack frame must be saved. */ - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); - braminzero = CMP(SLJIT_EQUAL, STR_PTR, 0, SLJIT_MEM1(TMP1), STACK(-BACKTRACK_AS(bracket_backtrack)->u.framesize - 2)); - } - JUMPHERE(skip); - } - else - { - jump = CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0); - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(1)); - JUMPHERE(jump); - } - } - -if (repeat_type != 0) - { - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_IMM, repeat_count); - if (repeat_type == OP_EXACT) - rmax_label = LABEL(); - } - -if (ket == OP_KETRMIN) - BACKTRACK_AS(bracket_backtrack)->recursive_matchingpath = LABEL(); - -if (ket == OP_KETRMAX) - { - rmax_label = LABEL(); - if (has_alternatives && opcode >= OP_BRA && opcode < OP_SBRA && repeat_type == 0) - BACKTRACK_AS(bracket_backtrack)->alternative_matchingpath = rmax_label; - } - -/* Handling capturing brackets and alternatives. */ -if (opcode == OP_ONCE) - { - stacksize = 0; - if (needs_control_head) - { - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr); - stacksize++; - } - - if (BACKTRACK_AS(bracket_backtrack)->u.framesize < 0) - { - /* Neither capturing brackets nor recursions are found in the block. */ - if (ket == OP_KETRMIN) - { - stacksize += 2; - if (!needs_control_head) - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); - } - else - { - if (BACKTRACK_AS(bracket_backtrack)->u.framesize == no_frame) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STACK_TOP, 0); - if (ket == OP_KETRMAX || has_alternatives) - stacksize++; - } - - if (stacksize > 0) - allocate_stack(common, stacksize); - - stacksize = 0; - if (needs_control_head) - { - stacksize++; - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP2, 0); - } - - if (ket == OP_KETRMIN) - { - if (needs_control_head) - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), STR_PTR, 0); - if (BACKTRACK_AS(bracket_backtrack)->u.framesize == no_frame) - OP2(SLJIT_ADD, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STACK_TOP, 0, SLJIT_IMM, needs_control_head ? (2 * sizeof(sljit_sw)) : sizeof(sljit_sw)); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize + 1), TMP2, 0); - } - else if (ket == OP_KETRMAX || has_alternatives) - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), STR_PTR, 0); - } - else - { - if (ket != OP_KET || has_alternatives) - stacksize++; - - stacksize += BACKTRACK_AS(bracket_backtrack)->u.framesize + 1; - allocate_stack(common, stacksize); - - if (needs_control_head) - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP2, 0); - - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); - OP2(SLJIT_ADD, TMP2, 0, STACK_TOP, 0, SLJIT_IMM, stacksize * sizeof(sljit_sw)); - - stacksize = needs_control_head ? 1 : 0; - if (ket != OP_KET || has_alternatives) - { - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), STR_PTR, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP2, 0); - stacksize++; - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), TMP1, 0); - } - else - { - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP2, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), TMP1, 0); - } - init_frame(common, ccbegin, NULL, BACKTRACK_AS(bracket_backtrack)->u.framesize + stacksize, stacksize + 1); - } - } -else if (opcode == OP_CBRA || opcode == OP_SCBRA) - { - /* Saving the previous values. */ - if (common->optimized_cbracket[offset >> 1] != 0) - { - SLJIT_ASSERT(private_data_ptr == OVECTOR(offset)); - allocate_stack(common, 2); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr + sizeof(sljit_sw)); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STR_PTR, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP1, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP2, 0); - } - else - { - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); - allocate_stack(common, 1); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STR_PTR, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP2, 0); - } - } -else if (opcode == OP_ASSERT_NA || opcode == OP_ASSERTBACK_NA || opcode == OP_SCRIPT_RUN || opcode == OP_SBRA || opcode == OP_SCOND) - { - /* Saving the previous value. */ - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); - allocate_stack(common, 1); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STR_PTR, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP2, 0); - } -else if (has_alternatives) - { - /* Pushing the starting string pointer. */ - allocate_stack(common, 1); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); - } - -/* Generating code for the first alternative. */ -if (opcode == OP_COND || opcode == OP_SCOND) - { - if (*matchingpath == OP_CREF) - { - SLJIT_ASSERT(has_alternatives); - add_jump(compiler, &(BACKTRACK_AS(bracket_backtrack)->u.condfailed), - CMP(SLJIT_EQUAL, SLJIT_MEM1(SLJIT_SP), OVECTOR(GET2(matchingpath, 1) << 1), SLJIT_MEM1(SLJIT_SP), OVECTOR(1))); - matchingpath += 1 + IMM2_SIZE; - } - else if (*matchingpath == OP_DNCREF) - { - SLJIT_ASSERT(has_alternatives); - - i = GET2(matchingpath, 1 + IMM2_SIZE); - slot = common->name_table + GET2(matchingpath, 1) * common->name_entry_size; - OP1(SLJIT_MOV, TMP3, 0, STR_PTR, 0); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(1)); - OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(GET2(slot, 0) << 1), TMP1, 0); - slot += common->name_entry_size; - i--; - while (i-- > 0) - { - OP2(SLJIT_SUB, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(GET2(slot, 0) << 1), TMP1, 0); - OP2(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, TMP2, 0, STR_PTR, 0); - slot += common->name_entry_size; - } - OP1(SLJIT_MOV, STR_PTR, 0, TMP3, 0); - add_jump(compiler, &(BACKTRACK_AS(bracket_backtrack)->u.condfailed), JUMP(SLJIT_ZERO)); - matchingpath += 1 + 2 * IMM2_SIZE; - } - else if ((*matchingpath >= OP_RREF && *matchingpath <= OP_TRUE) || *matchingpath == OP_FAIL) - { - /* Never has other case. */ - BACKTRACK_AS(bracket_backtrack)->u.condfailed = NULL; - SLJIT_ASSERT(!has_alternatives); - - if (*matchingpath == OP_TRUE) - { - stacksize = 1; - matchingpath++; - } - else if (*matchingpath == OP_FALSE || *matchingpath == OP_FAIL) - stacksize = 0; - else if (*matchingpath == OP_RREF) - { - stacksize = GET2(matchingpath, 1); - if (common->currententry == NULL) - stacksize = 0; - else if (stacksize == RREF_ANY) - stacksize = 1; - else if (common->currententry->start == 0) - stacksize = stacksize == 0; - else - stacksize = stacksize == (int)GET2(common->start, common->currententry->start + 1 + LINK_SIZE); - - if (stacksize != 0) - matchingpath += 1 + IMM2_SIZE; - } - else - { - if (common->currententry == NULL || common->currententry->start == 0) - stacksize = 0; - else - { - stacksize = GET2(matchingpath, 1 + IMM2_SIZE); - slot = common->name_table + GET2(matchingpath, 1) * common->name_entry_size; - i = (int)GET2(common->start, common->currententry->start + 1 + LINK_SIZE); - while (stacksize > 0) - { - if ((int)GET2(slot, 0) == i) - break; - slot += common->name_entry_size; - stacksize--; - } - } - - if (stacksize != 0) - matchingpath += 1 + 2 * IMM2_SIZE; - } - - /* The stacksize == 0 is a common "else" case. */ - if (stacksize == 0) - { - if (*cc == OP_ALT) - { - matchingpath = cc + 1 + LINK_SIZE; - cc += GET(cc, 1); - } - else - matchingpath = cc; - } - } - else - { - SLJIT_ASSERT(has_alternatives && *matchingpath >= OP_ASSERT && *matchingpath <= OP_ASSERTBACK_NOT); - /* Similar code as PUSH_BACKTRACK macro. */ - assert = sljit_alloc_memory(compiler, sizeof(assert_backtrack)); - if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) - return NULL; - memset(assert, 0, sizeof(assert_backtrack)); - assert->common.cc = matchingpath; - BACKTRACK_AS(bracket_backtrack)->u.assert = assert; - matchingpath = compile_assert_matchingpath(common, matchingpath, assert, TRUE); - } - } - -compile_matchingpath(common, matchingpath, cc, backtrack); -if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) - return NULL; - -if (opcode == OP_ASSERT_NA || opcode == OP_ASSERTBACK_NA) - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); - -if (opcode == OP_ONCE) - match_once_common(common, ket, BACKTRACK_AS(bracket_backtrack)->u.framesize, private_data_ptr, has_alternatives, needs_control_head); - -if (opcode == OP_SCRIPT_RUN) - match_script_run_common(common, private_data_ptr, backtrack); - -stacksize = 0; -if (repeat_type == OP_MINUPTO) - { - /* We need to preserve the counter. TMP2 will be used below. */ - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), repeat_ptr); - stacksize++; - } -if (ket != OP_KET || bra != OP_BRA) - stacksize++; -if (offset != 0) - { - if (common->capture_last_ptr != 0) - stacksize++; - if (common->optimized_cbracket[offset >> 1] == 0) - stacksize += 2; - } -if (has_alternatives && opcode != OP_ONCE) - stacksize++; - -if (stacksize > 0) - allocate_stack(common, stacksize); - -stacksize = 0; -if (repeat_type == OP_MINUPTO) - { - /* TMP2 was set above. */ - OP2(SLJIT_SUB, SLJIT_MEM1(STACK_TOP), STACK(stacksize), TMP2, 0, SLJIT_IMM, 1); - stacksize++; - } - -if (ket != OP_KET || bra != OP_BRA) - { - if (ket != OP_KET) - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), STR_PTR, 0); - else - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), SLJIT_IMM, 0); - stacksize++; - } - -if (offset != 0) - stacksize = match_capture_common(common, stacksize, offset, private_data_ptr); - -/* Skip and count the other alternatives. */ -i = 1; -while (*cc == OP_ALT) - { - cc += GET(cc, 1); - i++; - } - -if (has_alternatives) - { - if (opcode != OP_ONCE) - { - 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)); - } - if (ket != OP_KETRMAX) - BACKTRACK_AS(bracket_backtrack)->alternative_matchingpath = LABEL(); - } - -/* Must be after the matchingpath label. */ -if (offset != 0 && common->optimized_cbracket[offset >> 1] != 0) - { - SLJIT_ASSERT(private_data_ptr == OVECTOR(offset + 0)); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), STR_PTR, 0); - } - -if (ket == OP_KETRMAX) - { - if (repeat_type != 0) - { - if (has_alternatives) - BACKTRACK_AS(bracket_backtrack)->alternative_matchingpath = LABEL(); - OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_IMM, 1); - JUMPTO(SLJIT_NOT_ZERO, rmax_label); - /* Drop STR_PTR for greedy plus quantifier. */ - if (opcode != OP_ONCE) - free_stack(common, 1); - } - else if (opcode < OP_BRA || opcode >= OP_SBRA) - { - if (has_alternatives) - BACKTRACK_AS(bracket_backtrack)->alternative_matchingpath = LABEL(); - - /* Checking zero-length iteration. */ - if (opcode != OP_ONCE) - { - /* This case includes opcodes such as OP_SCRIPT_RUN. */ - CMPTO(SLJIT_NOT_EQUAL, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STR_PTR, 0, rmax_label); - /* Drop STR_PTR for greedy plus quantifier. */ - if (bra != OP_BRAZERO) - free_stack(common, 1); - } - else - /* TMP2 must contain the starting STR_PTR. */ - CMPTO(SLJIT_NOT_EQUAL, TMP2, 0, STR_PTR, 0, rmax_label); - } - else - JUMPTO(SLJIT_JUMP, rmax_label); - BACKTRACK_AS(bracket_backtrack)->recursive_matchingpath = LABEL(); - } - -if (repeat_type == OP_EXACT) - { - count_match(common); - OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_IMM, 1); - JUMPTO(SLJIT_NOT_ZERO, rmax_label); - } -else if (repeat_type == OP_UPTO) - { - /* We need to preserve the counter. */ - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), repeat_ptr); - allocate_stack(common, 1); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP2, 0); - } - -if (bra == OP_BRAZERO) - BACKTRACK_AS(bracket_backtrack)->zero_matchingpath = LABEL(); - -if (bra == OP_BRAMINZERO) - { - /* This is a backtrack path! (From the viewpoint of OP_BRAMINZERO) */ - JUMPTO(SLJIT_JUMP, ((braminzero_backtrack *)parent)->matchingpath); - if (braminzero != NULL) - { - JUMPHERE(braminzero); - /* We need to release the end pointer to perform the - backtrack for the zero-length iteration. When - framesize is < 0, OP_ONCE will do the release itself. */ - if (opcode == OP_ONCE && BACKTRACK_AS(bracket_backtrack)->u.framesize >= 0) - { - OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); - add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL)); - OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (BACKTRACK_AS(bracket_backtrack)->u.framesize - 1) * sizeof(sljit_sw)); - } - else if (ket == OP_KETRMIN && opcode != OP_ONCE) - free_stack(common, 1); - } - /* Continue to the normal backtrack. */ - } - -if ((ket != OP_KET && bra != OP_BRAMINZERO) || bra == OP_BRAZERO) - count_match(common); - -cc += 1 + LINK_SIZE; - -if (opcode == OP_ONCE) - { - /* 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); - } -return cc + repeat_length; -} - -static PCRE2_SPTR compile_bracketpos_matchingpath(compiler_common *common, PCRE2_SPTR cc, backtrack_common *parent) -{ -DEFINE_COMPILER; -backtrack_common *backtrack; -PCRE2_UCHAR opcode; -int private_data_ptr; -int cbraprivptr = 0; -BOOL needs_control_head; -int framesize; -int stacksize; -int offset = 0; -BOOL zero = FALSE; -PCRE2_SPTR ccbegin = NULL; -int stack; /* Also contains the offset of control head. */ -struct sljit_label *loop = NULL; -struct jump_list *emptymatch = NULL; - -PUSH_BACKTRACK(sizeof(bracketpos_backtrack), cc, NULL); -if (*cc == OP_BRAPOSZERO) - { - zero = TRUE; - cc++; - } - -opcode = *cc; -private_data_ptr = PRIVATE_DATA(cc); -SLJIT_ASSERT(private_data_ptr != 0); -BACKTRACK_AS(bracketpos_backtrack)->private_data_ptr = private_data_ptr; -switch(opcode) - { - case OP_BRAPOS: - case OP_SBRAPOS: - ccbegin = cc + 1 + LINK_SIZE; - break; - - case OP_CBRAPOS: - case OP_SCBRAPOS: - offset = GET2(cc, 1 + LINK_SIZE); - /* This case cannot be optimized in the same was as - normal capturing brackets. */ - SLJIT_ASSERT(common->optimized_cbracket[offset] == 0); - cbraprivptr = OVECTOR_PRIV(offset); - offset <<= 1; - ccbegin = cc + 1 + LINK_SIZE + IMM2_SIZE; - break; - - default: - SLJIT_UNREACHABLE(); - break; - } - -framesize = get_framesize(common, cc, NULL, FALSE, &needs_control_head); -BACKTRACK_AS(bracketpos_backtrack)->framesize = framesize; -if (framesize < 0) - { - if (offset != 0) - { - stacksize = 2; - if (common->capture_last_ptr != 0) - stacksize++; - } - else - stacksize = 1; - - if (needs_control_head) - stacksize++; - if (!zero) - stacksize++; - - BACKTRACK_AS(bracketpos_backtrack)->stacksize = stacksize; - allocate_stack(common, stacksize); - if (framesize == no_frame) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STACK_TOP, 0); - - stack = 0; - if (offset != 0) - { - stack = 2; - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset)); - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1)); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP1, 0); - if (common->capture_last_ptr != 0) - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP2, 0); - if (needs_control_head) - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr); - if (common->capture_last_ptr != 0) - { - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(2), TMP1, 0); - stack = 3; - } - } - else - { - if (needs_control_head) - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); - stack = 1; - } - - if (needs_control_head) - stack++; - if (!zero) - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stack), SLJIT_IMM, 1); - if (needs_control_head) - { - stack--; - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stack), TMP2, 0); - } - } -else - { - stacksize = framesize + 1; - if (!zero) - stacksize++; - if (needs_control_head) - stacksize++; - if (offset == 0) - stacksize++; - BACKTRACK_AS(bracketpos_backtrack)->stacksize = stacksize; - - allocate_stack(common, stacksize); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); - if (needs_control_head) - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr); - OP2(SLJIT_ADD, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STACK_TOP, 0, SLJIT_IMM, stacksize * sizeof(sljit_sw)); - - stack = 0; - if (!zero) - { - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 1); - stack = 1; - } - if (needs_control_head) - { - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stack), TMP2, 0); - stack++; - } - if (offset == 0) - { - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stack), STR_PTR, 0); - stack++; - } - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stack), TMP1, 0); - init_frame(common, cc, NULL, stacksize - 1, stacksize - framesize); - stack -= 1 + (offset == 0); - } - -if (offset != 0) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), cbraprivptr, STR_PTR, 0); - -loop = LABEL(); -while (*cc != OP_KETRPOS) - { - backtrack->top = NULL; - backtrack->topbacktracks = NULL; - cc += GET(cc, 1); - - compile_matchingpath(common, ccbegin, cc, backtrack); - if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) - return NULL; - - if (framesize < 0) - { - if (framesize == no_frame) - OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); - - if (offset != 0) - { - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), cbraprivptr); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), STR_PTR, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), cbraprivptr, STR_PTR, 0); - if (common->capture_last_ptr != 0) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr, SLJIT_IMM, offset >> 1); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset), TMP1, 0); - } - else - { - if (opcode == OP_SBRAPOS) - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); - } - - /* Even if the match is empty, we need to reset the control head. */ - if (needs_control_head) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), STACK(stack)); - - if (opcode == OP_SBRAPOS || opcode == OP_SCBRAPOS) - add_jump(compiler, &emptymatch, CMP(SLJIT_EQUAL, TMP1, 0, STR_PTR, 0)); - - if (!zero) - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize - 1), SLJIT_IMM, 0); - } - else - { - if (offset != 0) - { - OP2(SLJIT_SUB, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, stacksize * sizeof(sljit_sw)); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), cbraprivptr); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), STR_PTR, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), cbraprivptr, STR_PTR, 0); - if (common->capture_last_ptr != 0) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr, SLJIT_IMM, offset >> 1); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset), TMP1, 0); - } - else - { - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); - OP2(SLJIT_SUB, STACK_TOP, 0, TMP2, 0, SLJIT_IMM, stacksize * sizeof(sljit_sw)); - if (opcode == OP_SBRAPOS) - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), STACK(-framesize - 2)); - OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), STACK(-framesize - 2), STR_PTR, 0); - } - - /* Even if the match is empty, we need to reset the control head. */ - if (needs_control_head) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), STACK(stack)); - - if (opcode == OP_SBRAPOS || opcode == OP_SCBRAPOS) - add_jump(compiler, &emptymatch, CMP(SLJIT_EQUAL, TMP1, 0, STR_PTR, 0)); - - if (!zero) - { - if (framesize < 0) - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize - 1), SLJIT_IMM, 0); - else - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); - } - } - - JUMPTO(SLJIT_JUMP, loop); - flush_stubs(common); - - compile_backtrackingpath(common, backtrack->top); - if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) - return NULL; - set_jumps(backtrack->topbacktracks, LABEL()); - - if (framesize < 0) - { - if (offset != 0) - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), cbraprivptr); - else - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - } - else - { - if (offset != 0) - { - /* Last alternative. */ - if (*cc == OP_KETRPOS) - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), cbraprivptr); - } - else - { - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(TMP2), STACK(-framesize - 2)); - } - } - - if (*cc == OP_KETRPOS) - break; - ccbegin = cc + 1 + LINK_SIZE; - } - -/* We don't have to restore the control head in case of a failed match. */ - -backtrack->topbacktracks = NULL; -if (!zero) - { - if (framesize < 0) - add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_NOT_EQUAL, SLJIT_MEM1(STACK_TOP), STACK(stacksize - 1), SLJIT_IMM, 0)); - else /* TMP2 is set to [private_data_ptr] above. */ - add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_NOT_EQUAL, SLJIT_MEM1(TMP2), STACK(-stacksize), SLJIT_IMM, 0)); - } - -/* None of them matched. */ -set_jumps(emptymatch, LABEL()); -count_match(common); -return cc + 1 + LINK_SIZE; -} - -static SLJIT_INLINE PCRE2_SPTR get_iterator_parameters(compiler_common *common, PCRE2_SPTR cc, PCRE2_UCHAR *opcode, PCRE2_UCHAR *type, sljit_u32 *max, sljit_u32 *exact, PCRE2_SPTR *end) -{ -int class_len; - -*opcode = *cc; -*exact = 0; - -if (*opcode >= OP_STAR && *opcode <= OP_POSUPTO) - { - cc++; - *type = OP_CHAR; - } -else if (*opcode >= OP_STARI && *opcode <= OP_POSUPTOI) - { - cc++; - *type = OP_CHARI; - *opcode -= OP_STARI - OP_STAR; - } -else if (*opcode >= OP_NOTSTAR && *opcode <= OP_NOTPOSUPTO) - { - cc++; - *type = OP_NOT; - *opcode -= OP_NOTSTAR - OP_STAR; - } -else if (*opcode >= OP_NOTSTARI && *opcode <= OP_NOTPOSUPTOI) - { - cc++; - *type = OP_NOTI; - *opcode -= OP_NOTSTARI - OP_STAR; - } -else if (*opcode >= OP_TYPESTAR && *opcode <= OP_TYPEPOSUPTO) - { - cc++; - *opcode -= OP_TYPESTAR - OP_STAR; - *type = OP_END; - } -else - { - SLJIT_ASSERT(*opcode == OP_CLASS || *opcode == OP_NCLASS || *opcode == OP_XCLASS); - *type = *opcode; - cc++; - class_len = (*type < OP_XCLASS) ? (int)(1 + (32 / sizeof(PCRE2_UCHAR))) : GET(cc, 0); - *opcode = cc[class_len - 1]; - - if (*opcode >= OP_CRSTAR && *opcode <= OP_CRMINQUERY) - { - *opcode -= OP_CRSTAR - OP_STAR; - *end = cc + class_len; - - if (*opcode == OP_PLUS || *opcode == OP_MINPLUS) - { - *exact = 1; - *opcode -= OP_PLUS - OP_STAR; - } - } - else if (*opcode >= OP_CRPOSSTAR && *opcode <= OP_CRPOSQUERY) - { - *opcode -= OP_CRPOSSTAR - OP_POSSTAR; - *end = cc + class_len; - - if (*opcode == OP_POSPLUS) - { - *exact = 1; - *opcode = OP_POSSTAR; - } - } - else - { - SLJIT_ASSERT(*opcode == OP_CRRANGE || *opcode == OP_CRMINRANGE || *opcode == OP_CRPOSRANGE); - *max = GET2(cc, (class_len + IMM2_SIZE)); - *exact = GET2(cc, class_len); - - if (*max == 0) - { - if (*opcode == OP_CRPOSRANGE) - *opcode = OP_POSSTAR; - else - *opcode -= OP_CRRANGE - OP_STAR; - } - else - { - *max -= *exact; - if (*max == 0) - *opcode = OP_EXACT; - else if (*max == 1) - { - if (*opcode == OP_CRPOSRANGE) - *opcode = OP_POSQUERY; - else - *opcode -= OP_CRRANGE - OP_QUERY; - } - else - { - if (*opcode == OP_CRPOSRANGE) - *opcode = OP_POSUPTO; - else - *opcode -= OP_CRRANGE - OP_UPTO; - } - } - *end = cc + class_len + 2 * IMM2_SIZE; - } - return cc; - } - -switch(*opcode) - { - case OP_EXACT: - *exact = GET2(cc, 0); - cc += IMM2_SIZE; - break; - - case OP_PLUS: - case OP_MINPLUS: - *exact = 1; - *opcode -= OP_PLUS - OP_STAR; - break; - - case OP_POSPLUS: - *exact = 1; - *opcode = OP_POSSTAR; - break; - - case OP_UPTO: - case OP_MINUPTO: - case OP_POSUPTO: - *max = GET2(cc, 0); - cc += IMM2_SIZE; - break; - } - -if (*type == OP_END) - { - *type = *cc; - *end = next_opcode(common, cc); - cc++; - return cc; - } - -*end = cc + 1; -#ifdef SUPPORT_UNICODE -if (common->utf && HAS_EXTRALEN(*cc)) *end += GET_EXTRALEN(*cc); -#endif -return cc; -} - -static PCRE2_SPTR compile_iterator_matchingpath(compiler_common *common, PCRE2_SPTR cc, backtrack_common *parent) -{ -DEFINE_COMPILER; -backtrack_common *backtrack; -PCRE2_UCHAR opcode; -PCRE2_UCHAR type; -sljit_u32 max = 0, exact; -sljit_s32 early_fail_ptr = PRIVATE_DATA(cc + 1); -sljit_s32 early_fail_type; -BOOL charpos_enabled; -PCRE2_UCHAR charpos_char; -unsigned int charpos_othercasebit; -PCRE2_SPTR end; -jump_list *no_match = NULL; -jump_list *no_char1_match = NULL; -struct sljit_jump *jump = NULL; -struct sljit_label *label; -int private_data_ptr = PRIVATE_DATA(cc); -int base = (private_data_ptr == 0) ? SLJIT_MEM1(STACK_TOP) : SLJIT_MEM1(SLJIT_SP); -int offset0 = (private_data_ptr == 0) ? STACK(0) : private_data_ptr; -int offset1 = (private_data_ptr == 0) ? STACK(1) : private_data_ptr + SSIZE_OF(sw); -int tmp_base, tmp_offset; -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 -BOOL use_tmp; -#endif - -PUSH_BACKTRACK(sizeof(char_iterator_backtrack), cc, NULL); - -early_fail_type = (early_fail_ptr & 0x7); -early_fail_ptr >>= 3; - -/* During recursion, these optimizations are disabled. */ -if (common->early_fail_start_ptr == 0 && common->fast_forward_bc_ptr == NULL) - { - early_fail_ptr = 0; - early_fail_type = type_skip; - } - -SLJIT_ASSERT(common->fast_forward_bc_ptr != NULL || early_fail_ptr == 0 - || (early_fail_ptr >= common->early_fail_start_ptr && early_fail_ptr <= common->early_fail_end_ptr)); - -if (early_fail_type == type_fail) - add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), early_fail_ptr)); - -cc = get_iterator_parameters(common, cc, &opcode, &type, &max, &exact, &end); - -if (type != OP_EXTUNI) - { - tmp_base = TMP3; - tmp_offset = 0; - } -else - { - tmp_base = SLJIT_MEM1(SLJIT_SP); - tmp_offset = POSSESSIVE0; - } - -/* Handle fixed part first. */ -if (exact > 1) - { - SLJIT_ASSERT(early_fail_ptr == 0); - - if (common->mode == PCRE2_JIT_COMPLETE -#ifdef SUPPORT_UNICODE - && !common->utf -#endif - && type != OP_ANYNL && type != OP_EXTUNI) - { - OP2(SLJIT_ADD, TMP1, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(exact)); - add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_GREATER, TMP1, 0, STR_END, 0)); - OP1(SLJIT_MOV, tmp_base, tmp_offset, SLJIT_IMM, exact); - label = LABEL(); - compile_char1_matchingpath(common, type, cc, &backtrack->topbacktracks, FALSE); - OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1); - JUMPTO(SLJIT_NOT_ZERO, label); - } - else - { - OP1(SLJIT_MOV, tmp_base, tmp_offset, SLJIT_IMM, exact); - label = LABEL(); - compile_char1_matchingpath(common, type, cc, &backtrack->topbacktracks, TRUE); - OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1); - JUMPTO(SLJIT_NOT_ZERO, label); - } - } -else if (exact == 1) - compile_char1_matchingpath(common, type, cc, &backtrack->topbacktracks, TRUE); - -if (early_fail_type == type_fail_range) - { - /* Range end first, followed by range start. */ - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), early_fail_ptr); - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), early_fail_ptr + SSIZE_OF(sw)); - OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, TMP2, 0); - OP2(SLJIT_SUB, TMP2, 0, STR_PTR, 0, TMP2, 0); - add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_LESS_EQUAL, TMP2, 0, TMP1, 0)); - - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), early_fail_ptr, STR_PTR, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), early_fail_ptr + SSIZE_OF(sw), STR_PTR, 0); - } - -switch(opcode) - { - case OP_STAR: - case OP_UPTO: - SLJIT_ASSERT(early_fail_ptr == 0 || opcode == OP_STAR); - - if (type == OP_ANYNL || type == OP_EXTUNI) - { - SLJIT_ASSERT(private_data_ptr == 0); - SLJIT_ASSERT(early_fail_ptr == 0); - - allocate_stack(common, 2); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, 0); - - if (opcode == OP_UPTO) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE0, SLJIT_IMM, max); - - label = LABEL(); - compile_char1_matchingpath(common, type, cc, &BACKTRACK_AS(char_iterator_backtrack)->u.backtracks, TRUE); - if (opcode == OP_UPTO) - { - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), POSSESSIVE0); - OP2(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, TMP1, 0, SLJIT_IMM, 1); - jump = JUMP(SLJIT_ZERO); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE0, TMP1, 0); - } - - /* We cannot use TMP3 because of allocate_stack. */ - allocate_stack(common, 1); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); - JUMPTO(SLJIT_JUMP, label); - if (jump != NULL) - JUMPHERE(jump); - BACKTRACK_AS(char_iterator_backtrack)->matchingpath = LABEL(); - break; - } -#ifdef SUPPORT_UNICODE - else if (type == OP_ALLANY && !common->invalid_utf) -#else - else if (type == OP_ALLANY) -#endif - { - if (opcode == OP_STAR) - { - if (private_data_ptr == 0) - allocate_stack(common, 2); - - OP1(SLJIT_MOV, base, offset0, STR_END, 0); - OP1(SLJIT_MOV, base, offset1, STR_PTR, 0); - - OP1(SLJIT_MOV, STR_PTR, 0, STR_END, 0); - process_partial_match(common); - - if (early_fail_ptr != 0) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), early_fail_ptr, STR_END, 0); - BACKTRACK_AS(char_iterator_backtrack)->matchingpath = LABEL(); - break; - } -#ifdef SUPPORT_UNICODE - else if (!common->utf) -#else - else -#endif - { - if (private_data_ptr == 0) - allocate_stack(common, 2); - - OP1(SLJIT_MOV, base, offset1, STR_PTR, 0); - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(max)); - - if (common->mode == PCRE2_JIT_COMPLETE) - { - OP2U(SLJIT_SUB | SLJIT_SET_GREATER, STR_PTR, 0, STR_END, 0); - CMOV(SLJIT_GREATER, STR_PTR, STR_END, 0); - } - else - { - jump = CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, STR_END, 0); - process_partial_match(common); - JUMPHERE(jump); - } - - OP1(SLJIT_MOV, base, offset0, STR_PTR, 0); - - if (early_fail_ptr != 0) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), early_fail_ptr, STR_PTR, 0); - BACKTRACK_AS(char_iterator_backtrack)->matchingpath = LABEL(); - break; - } - } - - charpos_enabled = FALSE; - charpos_char = 0; - charpos_othercasebit = 0; - - if ((type != OP_CHAR && type != OP_CHARI) && (*end == OP_CHAR || *end == OP_CHARI)) - { -#ifdef SUPPORT_UNICODE - charpos_enabled = !common->utf || !HAS_EXTRALEN(end[1]); -#else - charpos_enabled = TRUE; -#endif - if (charpos_enabled && *end == OP_CHARI && char_has_othercase(common, end + 1)) - { - charpos_othercasebit = char_get_othercase_bit(common, end + 1); - if (charpos_othercasebit == 0) - charpos_enabled = FALSE; - } - - if (charpos_enabled) - { - charpos_char = end[1]; - /* Consume the OP_CHAR opcode. */ - end += 2; -#if PCRE2_CODE_UNIT_WIDTH == 8 - SLJIT_ASSERT((charpos_othercasebit >> 8) == 0); -#elif PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32 - SLJIT_ASSERT((charpos_othercasebit >> 9) == 0); - if ((charpos_othercasebit & 0x100) != 0) - charpos_othercasebit = (charpos_othercasebit & 0xff) << 8; -#endif - if (charpos_othercasebit != 0) - charpos_char |= charpos_othercasebit; - - BACKTRACK_AS(char_iterator_backtrack)->u.charpos.enabled = TRUE; - BACKTRACK_AS(char_iterator_backtrack)->u.charpos.chr = charpos_char; - BACKTRACK_AS(char_iterator_backtrack)->u.charpos.othercasebit = charpos_othercasebit; - } - } - - if (charpos_enabled) - { - if (opcode == OP_UPTO) - OP1(SLJIT_MOV, tmp_base, tmp_offset, SLJIT_IMM, max + 1); - - /* Search the first instance of charpos_char. */ - jump = JUMP(SLJIT_JUMP); - label = LABEL(); - if (opcode == OP_UPTO) - { - OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1); - add_jump(compiler, &backtrack->topbacktracks, JUMP(SLJIT_ZERO)); - } - compile_char1_matchingpath(common, type, cc, &backtrack->topbacktracks, FALSE); - if (early_fail_ptr != 0) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), early_fail_ptr, STR_PTR, 0); - JUMPHERE(jump); - - detect_partial_match(common, &backtrack->topbacktracks); - OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); - if (charpos_othercasebit != 0) - OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, charpos_othercasebit); - CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, charpos_char, label); - - if (private_data_ptr == 0) - allocate_stack(common, 2); - OP1(SLJIT_MOV, base, offset0, STR_PTR, 0); - OP1(SLJIT_MOV, base, offset1, STR_PTR, 0); - - if (opcode == OP_UPTO) - { - OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1); - add_jump(compiler, &no_match, JUMP(SLJIT_ZERO)); - } - - /* Search the last instance of charpos_char. */ - label = LABEL(); - compile_char1_matchingpath(common, type, cc, &no_match, FALSE); - if (early_fail_ptr != 0) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), early_fail_ptr, STR_PTR, 0); - detect_partial_match(common, &no_match); - OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); - if (charpos_othercasebit != 0) - OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, charpos_othercasebit); - - if (opcode == OP_STAR) - { - CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, charpos_char, label); - OP1(SLJIT_MOV, base, offset0, STR_PTR, 0); - JUMPTO(SLJIT_JUMP, label); - } - else - { - jump = CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, charpos_char); - OP1(SLJIT_MOV, base, offset0, STR_PTR, 0); - JUMPHERE(jump); - OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1); - JUMPTO(SLJIT_NOT_ZERO, label); - } - - set_jumps(no_match, LABEL()); - OP2(SLJIT_ADD, STR_PTR, 0, base, offset0, SLJIT_IMM, IN_UCHARS(1)); - OP1(SLJIT_MOV, base, offset0, STR_PTR, 0); - } - else - { - if (private_data_ptr == 0) - allocate_stack(common, 2); - - OP1(SLJIT_MOV, base, offset1, STR_PTR, 0); -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 - use_tmp = (!HAS_VIRTUAL_REGISTERS && opcode == OP_STAR); - SLJIT_ASSERT(!use_tmp || tmp_base == TMP3); - - if (common->utf) - OP1(SLJIT_MOV, use_tmp ? TMP3 : base, use_tmp ? 0 : offset0, STR_PTR, 0); -#endif - if (opcode == OP_UPTO) - OP1(SLJIT_MOV, tmp_base, tmp_offset, SLJIT_IMM, max); - - detect_partial_match(common, &no_match); - label = LABEL(); - compile_char1_matchingpath(common, type, cc, &no_char1_match, FALSE); -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 - if (common->utf) - OP1(SLJIT_MOV, use_tmp ? TMP3 : base, use_tmp ? 0 : offset0, STR_PTR, 0); -#endif - - if (opcode == OP_UPTO) - { - OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1); - add_jump(compiler, &no_match, JUMP(SLJIT_ZERO)); - } - - detect_partial_match_to(common, label); - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - - set_jumps(no_char1_match, LABEL()); -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 - if (common->utf) - { - set_jumps(no_match, LABEL()); - if (use_tmp) - { - OP1(SLJIT_MOV, STR_PTR, 0, TMP3, 0); - OP1(SLJIT_MOV, base, offset0, TMP3, 0); - } - else - OP1(SLJIT_MOV, STR_PTR, 0, base, offset0); - } - else -#endif - { - OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - set_jumps(no_match, LABEL()); - OP1(SLJIT_MOV, base, offset0, STR_PTR, 0); - } - - if (early_fail_ptr != 0) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), early_fail_ptr, STR_PTR, 0); - } - - BACKTRACK_AS(char_iterator_backtrack)->matchingpath = LABEL(); - break; - - case OP_MINSTAR: - if (private_data_ptr == 0) - allocate_stack(common, 1); - OP1(SLJIT_MOV, base, offset0, STR_PTR, 0); - BACKTRACK_AS(char_iterator_backtrack)->matchingpath = LABEL(); - if (early_fail_ptr != 0) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), early_fail_ptr, STR_PTR, 0); - break; - - case OP_MINUPTO: - SLJIT_ASSERT(early_fail_ptr == 0); - if (private_data_ptr == 0) - allocate_stack(common, 2); - OP1(SLJIT_MOV, base, offset0, STR_PTR, 0); - OP1(SLJIT_MOV, base, offset1, SLJIT_IMM, max + 1); - BACKTRACK_AS(char_iterator_backtrack)->matchingpath = LABEL(); - break; - - case OP_QUERY: - case OP_MINQUERY: - SLJIT_ASSERT(early_fail_ptr == 0); - if (private_data_ptr == 0) - allocate_stack(common, 1); - OP1(SLJIT_MOV, base, offset0, STR_PTR, 0); - if (opcode == OP_QUERY) - compile_char1_matchingpath(common, type, cc, &BACKTRACK_AS(char_iterator_backtrack)->u.backtracks, TRUE); - BACKTRACK_AS(char_iterator_backtrack)->matchingpath = LABEL(); - break; - - case OP_EXACT: - break; - - case OP_POSSTAR: -#if defined SUPPORT_UNICODE - if (type == OP_ALLANY && !common->invalid_utf) -#else - if (type == OP_ALLANY) -#endif - { - OP1(SLJIT_MOV, STR_PTR, 0, STR_END, 0); - process_partial_match(common); - if (early_fail_ptr != 0) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), early_fail_ptr, STR_END, 0); - break; - } - -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 - if (common->utf) - { - OP1(SLJIT_MOV, tmp_base, tmp_offset, STR_PTR, 0); - detect_partial_match(common, &no_match); - label = LABEL(); - compile_char1_matchingpath(common, type, cc, &no_match, FALSE); - OP1(SLJIT_MOV, tmp_base, tmp_offset, STR_PTR, 0); - detect_partial_match_to(common, label); - - set_jumps(no_match, LABEL()); - OP1(SLJIT_MOV, STR_PTR, 0, tmp_base, tmp_offset); - if (early_fail_ptr != 0) - { - if (!HAS_VIRTUAL_REGISTERS && tmp_base == TMP3) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), early_fail_ptr, TMP3, 0); - else - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), early_fail_ptr, STR_PTR, 0); - } - break; - } -#endif - - detect_partial_match(common, &no_match); - label = LABEL(); - compile_char1_matchingpath(common, type, cc, &no_char1_match, FALSE); - detect_partial_match_to(common, label); - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - - set_jumps(no_char1_match, LABEL()); - OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - set_jumps(no_match, LABEL()); - if (early_fail_ptr != 0) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), early_fail_ptr, STR_PTR, 0); - break; - - case OP_POSUPTO: - SLJIT_ASSERT(early_fail_ptr == 0); -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 - if (common->utf) - { - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE1, STR_PTR, 0); - OP1(SLJIT_MOV, tmp_base, tmp_offset, SLJIT_IMM, max); - - detect_partial_match(common, &no_match); - label = LABEL(); - compile_char1_matchingpath(common, type, cc, &no_match, FALSE); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE1, STR_PTR, 0); - OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1); - add_jump(compiler, &no_match, JUMP(SLJIT_ZERO)); - detect_partial_match_to(common, label); - - set_jumps(no_match, LABEL()); - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), POSSESSIVE1); - break; - } -#endif - - if (type == OP_ALLANY) - { - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(max)); - - if (common->mode == PCRE2_JIT_COMPLETE) - { - OP2U(SLJIT_SUB | SLJIT_SET_GREATER, STR_PTR, 0, STR_END, 0); - CMOV(SLJIT_GREATER, STR_PTR, STR_END, 0); - } - else - { - jump = CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, STR_END, 0); - process_partial_match(common); - JUMPHERE(jump); - } - break; - } - - OP1(SLJIT_MOV, tmp_base, tmp_offset, SLJIT_IMM, max); - - detect_partial_match(common, &no_match); - label = LABEL(); - compile_char1_matchingpath(common, type, cc, &no_char1_match, FALSE); - OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1); - add_jump(compiler, &no_match, JUMP(SLJIT_ZERO)); - detect_partial_match_to(common, label); - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - - set_jumps(no_char1_match, LABEL()); - OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - set_jumps(no_match, LABEL()); - break; - - case OP_POSQUERY: - SLJIT_ASSERT(early_fail_ptr == 0); - OP1(SLJIT_MOV, tmp_base, tmp_offset, STR_PTR, 0); - compile_char1_matchingpath(common, type, cc, &no_match, TRUE); - OP1(SLJIT_MOV, tmp_base, tmp_offset, STR_PTR, 0); - set_jumps(no_match, LABEL()); - OP1(SLJIT_MOV, STR_PTR, 0, tmp_base, tmp_offset); - break; - - default: - SLJIT_UNREACHABLE(); - break; - } - -count_match(common); -return end; -} - -static SLJIT_INLINE PCRE2_SPTR compile_fail_accept_matchingpath(compiler_common *common, PCRE2_SPTR cc, backtrack_common *parent) -{ -DEFINE_COMPILER; -backtrack_common *backtrack; - -PUSH_BACKTRACK(sizeof(backtrack_common), cc, NULL); - -if (*cc == OP_FAIL) - { - add_jump(compiler, &backtrack->topbacktracks, JUMP(SLJIT_JUMP)); - return cc + 1; - } - -if (*cc == OP_ACCEPT && common->currententry == NULL && (common->re->overall_options & PCRE2_ENDANCHORED) != 0) - add_jump(compiler, &common->reset_match, CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, STR_END, 0)); - -if (*cc == OP_ASSERT_ACCEPT || common->currententry != NULL || !common->might_be_empty) - { - /* No need to check notempty conditions. */ - if (common->accept_label == NULL) - add_jump(compiler, &common->accept, JUMP(SLJIT_JUMP)); - else - JUMPTO(SLJIT_JUMP, common->accept_label); - return cc + 1; - } - -if (common->accept_label == NULL) - add_jump(compiler, &common->accept, CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(0))); -else - CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(0), common->accept_label); - -if (HAS_VIRTUAL_REGISTERS) - { - OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0); - OP1(SLJIT_MOV_U32, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, options)); - } -else - OP1(SLJIT_MOV_U32, TMP2, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, options)); - -OP2U(SLJIT_AND | SLJIT_SET_Z, TMP2, 0, SLJIT_IMM, PCRE2_NOTEMPTY); -add_jump(compiler, &backtrack->topbacktracks, JUMP(SLJIT_NOT_ZERO)); -OP2U(SLJIT_AND | SLJIT_SET_Z, TMP2, 0, SLJIT_IMM, PCRE2_NOTEMPTY_ATSTART); -if (common->accept_label == NULL) - add_jump(compiler, &common->accept, JUMP(SLJIT_ZERO)); -else - JUMPTO(SLJIT_ZERO, common->accept_label); - -OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(HAS_VIRTUAL_REGISTERS ? TMP1 : ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, str)); -if (common->accept_label == NULL) - add_jump(compiler, &common->accept, CMP(SLJIT_NOT_EQUAL, TMP2, 0, STR_PTR, 0)); -else - CMPTO(SLJIT_NOT_EQUAL, TMP2, 0, STR_PTR, 0, common->accept_label); -add_jump(compiler, &backtrack->topbacktracks, JUMP(SLJIT_JUMP)); -return cc + 1; -} - -static SLJIT_INLINE PCRE2_SPTR compile_close_matchingpath(compiler_common *common, PCRE2_SPTR cc) -{ -DEFINE_COMPILER; -int offset = GET2(cc, 1); -BOOL optimized_cbracket = common->optimized_cbracket[offset] != 0; - -/* Data will be discarded anyway... */ -if (common->currententry != NULL) - return cc + 1 + IMM2_SIZE; - -if (!optimized_cbracket) - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR_PRIV(offset)); -offset <<= 1; -OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), STR_PTR, 0); -if (!optimized_cbracket) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset), TMP1, 0); -return cc + 1 + IMM2_SIZE; -} - -static SLJIT_INLINE PCRE2_SPTR compile_control_verb_matchingpath(compiler_common *common, PCRE2_SPTR cc, backtrack_common *parent) -{ -DEFINE_COMPILER; -backtrack_common *backtrack; -PCRE2_UCHAR opcode = *cc; -PCRE2_SPTR ccend = cc + 1; - -if (opcode == OP_COMMIT_ARG || opcode == OP_PRUNE_ARG || - opcode == OP_SKIP_ARG || opcode == OP_THEN_ARG) - ccend += 2 + cc[1]; - -PUSH_BACKTRACK(sizeof(backtrack_common), cc, NULL); - -if (opcode == OP_SKIP) - { - allocate_stack(common, 1); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); - return ccend; - } - -if (opcode == OP_COMMIT_ARG || opcode == OP_PRUNE_ARG || opcode == OP_THEN_ARG) - { - if (HAS_VIRTUAL_REGISTERS) - OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0); - OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, (sljit_sw)(cc + 2)); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->mark_ptr, TMP2, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(HAS_VIRTUAL_REGISTERS ? TMP1 : ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, mark_ptr), TMP2, 0); - } - -return ccend; -} - -static PCRE2_UCHAR then_trap_opcode[1] = { OP_THEN_TRAP }; - -static SLJIT_INLINE void compile_then_trap_matchingpath(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend, backtrack_common *parent) -{ -DEFINE_COMPILER; -backtrack_common *backtrack; -BOOL needs_control_head; -int size; - -PUSH_BACKTRACK_NOVALUE(sizeof(then_trap_backtrack), cc); -common->then_trap = BACKTRACK_AS(then_trap_backtrack); -BACKTRACK_AS(then_trap_backtrack)->common.cc = then_trap_opcode; -BACKTRACK_AS(then_trap_backtrack)->start = (sljit_sw)(cc - common->start); -BACKTRACK_AS(then_trap_backtrack)->framesize = get_framesize(common, cc, ccend, FALSE, &needs_control_head); - -size = BACKTRACK_AS(then_trap_backtrack)->framesize; -size = 3 + (size < 0 ? 0 : size); - -OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr); -allocate_stack(common, size); -if (size > 3) - OP2(SLJIT_ADD, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, STACK_TOP, 0, SLJIT_IMM, (size - 3) * sizeof(sljit_sw)); -else - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, STACK_TOP, 0); -OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(size - 1), SLJIT_IMM, BACKTRACK_AS(then_trap_backtrack)->start); -OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(size - 2), SLJIT_IMM, type_then_trap); -OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(size - 3), TMP2, 0); - -size = BACKTRACK_AS(then_trap_backtrack)->framesize; -if (size >= 0) - init_frame(common, cc, ccend, size - 1, 0); -} - -static void compile_matchingpath(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend, backtrack_common *parent) -{ -DEFINE_COMPILER; -backtrack_common *backtrack; -BOOL has_then_trap = FALSE; -then_trap_backtrack *save_then_trap = NULL; - -SLJIT_ASSERT(*ccend == OP_END || (*ccend >= OP_ALT && *ccend <= OP_KETRPOS)); - -if (common->has_then && common->then_offsets[cc - common->start] != 0) - { - SLJIT_ASSERT(*ccend != OP_END && common->control_head_ptr != 0); - has_then_trap = TRUE; - save_then_trap = common->then_trap; - /* Tail item on backtrack. */ - compile_then_trap_matchingpath(common, cc, ccend, parent); - } - -while (cc < ccend) - { - switch(*cc) - { - case OP_SOD: - case OP_SOM: - case OP_NOT_WORD_BOUNDARY: - case OP_WORD_BOUNDARY: - case OP_EODN: - case OP_EOD: - case OP_DOLL: - case OP_DOLLM: - case OP_CIRC: - case OP_CIRCM: - case OP_REVERSE: - cc = compile_simple_assertion_matchingpath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks); - break; - - case OP_NOT_DIGIT: - case OP_DIGIT: - case OP_NOT_WHITESPACE: - case OP_WHITESPACE: - case OP_NOT_WORDCHAR: - case OP_WORDCHAR: - case OP_ANY: - case OP_ALLANY: - case OP_ANYBYTE: - case OP_NOTPROP: - case OP_PROP: - case OP_ANYNL: - case OP_NOT_HSPACE: - case OP_HSPACE: - case OP_NOT_VSPACE: - case OP_VSPACE: - case OP_EXTUNI: - case OP_NOT: - case OP_NOTI: - cc = compile_char1_matchingpath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks, TRUE); - break; - - case OP_SET_SOM: - PUSH_BACKTRACK_NOVALUE(sizeof(backtrack_common), cc); - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(0)); - allocate_stack(common, 1); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(0), STR_PTR, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP2, 0); - cc++; - break; - - case OP_CHAR: - case OP_CHARI: - if (common->mode == PCRE2_JIT_COMPLETE) - cc = compile_charn_matchingpath(common, cc, ccend, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks); - else - cc = compile_char1_matchingpath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks, TRUE); - break; - - case OP_STAR: - case OP_MINSTAR: - case OP_PLUS: - case OP_MINPLUS: - case OP_QUERY: - case OP_MINQUERY: - case OP_UPTO: - case OP_MINUPTO: - case OP_EXACT: - case OP_POSSTAR: - case OP_POSPLUS: - case OP_POSQUERY: - case OP_POSUPTO: - case OP_STARI: - case OP_MINSTARI: - case OP_PLUSI: - case OP_MINPLUSI: - case OP_QUERYI: - case OP_MINQUERYI: - case OP_UPTOI: - case OP_MINUPTOI: - case OP_EXACTI: - case OP_POSSTARI: - case OP_POSPLUSI: - case OP_POSQUERYI: - case OP_POSUPTOI: - case OP_NOTSTAR: - case OP_NOTMINSTAR: - case OP_NOTPLUS: - case OP_NOTMINPLUS: - case OP_NOTQUERY: - case OP_NOTMINQUERY: - case OP_NOTUPTO: - case OP_NOTMINUPTO: - case OP_NOTEXACT: - case OP_NOTPOSSTAR: - case OP_NOTPOSPLUS: - case OP_NOTPOSQUERY: - case OP_NOTPOSUPTO: - case OP_NOTSTARI: - case OP_NOTMINSTARI: - case OP_NOTPLUSI: - case OP_NOTMINPLUSI: - case OP_NOTQUERYI: - case OP_NOTMINQUERYI: - case OP_NOTUPTOI: - case OP_NOTMINUPTOI: - case OP_NOTEXACTI: - case OP_NOTPOSSTARI: - case OP_NOTPOSPLUSI: - case OP_NOTPOSQUERYI: - case OP_NOTPOSUPTOI: - case OP_TYPESTAR: - case OP_TYPEMINSTAR: - case OP_TYPEPLUS: - case OP_TYPEMINPLUS: - case OP_TYPEQUERY: - case OP_TYPEMINQUERY: - case OP_TYPEUPTO: - case OP_TYPEMINUPTO: - case OP_TYPEEXACT: - case OP_TYPEPOSSTAR: - case OP_TYPEPOSPLUS: - case OP_TYPEPOSQUERY: - case OP_TYPEPOSUPTO: - cc = compile_iterator_matchingpath(common, cc, parent); - break; - - case OP_CLASS: - case OP_NCLASS: - if (cc[1 + (32 / sizeof(PCRE2_UCHAR))] >= OP_CRSTAR && cc[1 + (32 / sizeof(PCRE2_UCHAR))] <= OP_CRPOSRANGE) - cc = compile_iterator_matchingpath(common, cc, parent); - else - cc = compile_char1_matchingpath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks, TRUE); - break; - -#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32 - case OP_XCLASS: - if (*(cc + GET(cc, 1)) >= OP_CRSTAR && *(cc + GET(cc, 1)) <= OP_CRPOSRANGE) - cc = compile_iterator_matchingpath(common, cc, parent); - else - cc = compile_char1_matchingpath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks, TRUE); - break; -#endif - - case OP_REF: - case OP_REFI: - if (cc[1 + IMM2_SIZE] >= OP_CRSTAR && cc[1 + IMM2_SIZE] <= OP_CRPOSRANGE) - cc = compile_ref_iterator_matchingpath(common, cc, parent); - else - { - compile_ref_matchingpath(common, cc, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks, TRUE, FALSE); - cc += 1 + IMM2_SIZE; - } - break; - - case OP_DNREF: - case OP_DNREFI: - if (cc[1 + 2 * IMM2_SIZE] >= OP_CRSTAR && cc[1 + 2 * IMM2_SIZE] <= OP_CRPOSRANGE) - cc = compile_ref_iterator_matchingpath(common, cc, parent); - else - { - compile_dnref_search(common, cc, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks); - compile_ref_matchingpath(common, cc, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks, TRUE, FALSE); - cc += 1 + 2 * IMM2_SIZE; - } - break; - - case OP_RECURSE: - cc = compile_recurse_matchingpath(common, cc, parent); - break; - - case OP_CALLOUT: - case OP_CALLOUT_STR: - cc = compile_callout_matchingpath(common, cc, parent); - break; - - case OP_ASSERT: - case OP_ASSERT_NOT: - case OP_ASSERTBACK: - case OP_ASSERTBACK_NOT: - PUSH_BACKTRACK_NOVALUE(sizeof(assert_backtrack), cc); - cc = compile_assert_matchingpath(common, cc, BACKTRACK_AS(assert_backtrack), FALSE); - break; - - case OP_BRAMINZERO: - PUSH_BACKTRACK_NOVALUE(sizeof(braminzero_backtrack), cc); - cc = bracketend(cc + 1); - if (*(cc - 1 - LINK_SIZE) != OP_KETRMIN) - { - allocate_stack(common, 1); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); - } - else - { - allocate_stack(common, 2); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), STR_PTR, 0); - } - BACKTRACK_AS(braminzero_backtrack)->matchingpath = LABEL(); - count_match(common); - break; - - case OP_ASSERT_NA: - case OP_ASSERTBACK_NA: - case OP_ONCE: - case OP_SCRIPT_RUN: - case OP_BRA: - case OP_CBRA: - case OP_COND: - case OP_SBRA: - case OP_SCBRA: - case OP_SCOND: - cc = compile_bracket_matchingpath(common, cc, parent); - break; - - case OP_BRAZERO: - if (cc[1] > OP_ASSERTBACK_NOT) - cc = compile_bracket_matchingpath(common, cc, parent); - else - { - PUSH_BACKTRACK_NOVALUE(sizeof(assert_backtrack), cc); - cc = compile_assert_matchingpath(common, cc, BACKTRACK_AS(assert_backtrack), FALSE); - } - break; - - case OP_BRAPOS: - case OP_CBRAPOS: - case OP_SBRAPOS: - case OP_SCBRAPOS: - case OP_BRAPOSZERO: - cc = compile_bracketpos_matchingpath(common, cc, parent); - break; - - case OP_MARK: - PUSH_BACKTRACK_NOVALUE(sizeof(backtrack_common), cc); - SLJIT_ASSERT(common->mark_ptr != 0); - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->mark_ptr); - allocate_stack(common, common->has_skip_arg ? 5 : 1); - if (HAS_VIRTUAL_REGISTERS) - OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(common->has_skip_arg ? 4 : 0), TMP2, 0); - OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, (sljit_sw)(cc + 2)); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->mark_ptr, TMP2, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(HAS_VIRTUAL_REGISTERS ? TMP1 : ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, mark_ptr), TMP2, 0); - if (common->has_skip_arg) - { - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, STACK_TOP, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, type_mark); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(2), SLJIT_IMM, (sljit_sw)(cc + 2)); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(3), STR_PTR, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP1, 0); - } - cc += 1 + 2 + cc[1]; - break; - - case OP_PRUNE: - case OP_PRUNE_ARG: - case OP_SKIP: - case OP_SKIP_ARG: - case OP_THEN: - case OP_THEN_ARG: - case OP_COMMIT: - case OP_COMMIT_ARG: - cc = compile_control_verb_matchingpath(common, cc, parent); - break; - - case OP_FAIL: - case OP_ACCEPT: - case OP_ASSERT_ACCEPT: - cc = compile_fail_accept_matchingpath(common, cc, parent); - break; - - case OP_CLOSE: - cc = compile_close_matchingpath(common, cc); - break; - - case OP_SKIPZERO: - cc = bracketend(cc + 1); - break; - - default: - SLJIT_UNREACHABLE(); - return; - } - if (cc == NULL) - return; - } - -if (has_then_trap) - { - /* Head item on backtrack. */ - PUSH_BACKTRACK_NOVALUE(sizeof(then_trap_backtrack), cc); - BACKTRACK_AS(then_trap_backtrack)->common.cc = then_trap_opcode; - BACKTRACK_AS(then_trap_backtrack)->then_trap = common->then_trap; - common->then_trap = save_then_trap; - } -SLJIT_ASSERT(cc == ccend); -} - -#undef PUSH_BACKTRACK -#undef PUSH_BACKTRACK_NOVALUE -#undef BACKTRACK_AS - -#define COMPILE_BACKTRACKINGPATH(current) \ - do \ - { \ - compile_backtrackingpath(common, (current)); \ - if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) \ - return; \ - } \ - while (0) - -#define CURRENT_AS(type) ((type *)current) - -static void compile_iterator_backtrackingpath(compiler_common *common, struct backtrack_common *current) -{ -DEFINE_COMPILER; -PCRE2_SPTR cc = current->cc; -PCRE2_UCHAR opcode; -PCRE2_UCHAR type; -sljit_u32 max = 0, exact; -struct sljit_label *label = NULL; -struct sljit_jump *jump = NULL; -jump_list *jumplist = NULL; -PCRE2_SPTR end; -int private_data_ptr = PRIVATE_DATA(cc); -int base = (private_data_ptr == 0) ? SLJIT_MEM1(STACK_TOP) : SLJIT_MEM1(SLJIT_SP); -int offset0 = (private_data_ptr == 0) ? STACK(0) : private_data_ptr; -int offset1 = (private_data_ptr == 0) ? STACK(1) : private_data_ptr + SSIZE_OF(sw); - -cc = get_iterator_parameters(common, cc, &opcode, &type, &max, &exact, &end); - -switch(opcode) - { - case OP_STAR: - case OP_UPTO: - if (type == OP_ANYNL || type == OP_EXTUNI) - { - SLJIT_ASSERT(private_data_ptr == 0); - set_jumps(CURRENT_AS(char_iterator_backtrack)->u.backtracks, LABEL()); - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - free_stack(common, 1); - CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(char_iterator_backtrack)->matchingpath); - } - else - { - if (CURRENT_AS(char_iterator_backtrack)->u.charpos.enabled) - { - OP1(SLJIT_MOV, STR_PTR, 0, base, offset0); - OP1(SLJIT_MOV, TMP2, 0, base, offset1); - OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - - jump = CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, TMP2, 0); - label = LABEL(); - OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-1)); - OP1(SLJIT_MOV, base, offset0, STR_PTR, 0); - if (CURRENT_AS(char_iterator_backtrack)->u.charpos.othercasebit != 0) - OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, CURRENT_AS(char_iterator_backtrack)->u.charpos.othercasebit); - CMPTO(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, CURRENT_AS(char_iterator_backtrack)->u.charpos.chr, CURRENT_AS(char_iterator_backtrack)->matchingpath); - move_back(common, NULL, TRUE); - CMPTO(SLJIT_GREATER, STR_PTR, 0, TMP2, 0, label); - } - else - { - OP1(SLJIT_MOV, STR_PTR, 0, base, offset0); - jump = CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, base, offset1); - move_back(common, NULL, TRUE); - OP1(SLJIT_MOV, base, offset0, STR_PTR, 0); - JUMPTO(SLJIT_JUMP, CURRENT_AS(char_iterator_backtrack)->matchingpath); - } - JUMPHERE(jump); - if (private_data_ptr == 0) - free_stack(common, 2); - } - break; - - case OP_MINSTAR: - OP1(SLJIT_MOV, STR_PTR, 0, base, offset0); - compile_char1_matchingpath(common, type, cc, &jumplist, TRUE); - OP1(SLJIT_MOV, base, offset0, STR_PTR, 0); - JUMPTO(SLJIT_JUMP, CURRENT_AS(char_iterator_backtrack)->matchingpath); - set_jumps(jumplist, LABEL()); - if (private_data_ptr == 0) - free_stack(common, 1); - break; - - case OP_MINUPTO: - OP1(SLJIT_MOV, TMP1, 0, base, offset1); - OP1(SLJIT_MOV, STR_PTR, 0, base, offset0); - OP2(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, TMP1, 0, SLJIT_IMM, 1); - add_jump(compiler, &jumplist, JUMP(SLJIT_ZERO)); - - OP1(SLJIT_MOV, base, offset1, TMP1, 0); - compile_char1_matchingpath(common, type, cc, &jumplist, TRUE); - OP1(SLJIT_MOV, base, offset0, STR_PTR, 0); - JUMPTO(SLJIT_JUMP, CURRENT_AS(char_iterator_backtrack)->matchingpath); - - set_jumps(jumplist, LABEL()); - if (private_data_ptr == 0) - free_stack(common, 2); - break; - - case OP_QUERY: - OP1(SLJIT_MOV, STR_PTR, 0, base, offset0); - OP1(SLJIT_MOV, base, offset0, SLJIT_IMM, 0); - CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(char_iterator_backtrack)->matchingpath); - jump = JUMP(SLJIT_JUMP); - set_jumps(CURRENT_AS(char_iterator_backtrack)->u.backtracks, LABEL()); - OP1(SLJIT_MOV, STR_PTR, 0, base, offset0); - OP1(SLJIT_MOV, base, offset0, SLJIT_IMM, 0); - JUMPTO(SLJIT_JUMP, CURRENT_AS(char_iterator_backtrack)->matchingpath); - JUMPHERE(jump); - if (private_data_ptr == 0) - free_stack(common, 1); - break; - - case OP_MINQUERY: - OP1(SLJIT_MOV, STR_PTR, 0, base, offset0); - OP1(SLJIT_MOV, base, offset0, SLJIT_IMM, 0); - jump = CMP(SLJIT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0); - compile_char1_matchingpath(common, type, cc, &jumplist, TRUE); - JUMPTO(SLJIT_JUMP, CURRENT_AS(char_iterator_backtrack)->matchingpath); - set_jumps(jumplist, LABEL()); - JUMPHERE(jump); - if (private_data_ptr == 0) - free_stack(common, 1); - break; - - case OP_EXACT: - case OP_POSSTAR: - case OP_POSQUERY: - case OP_POSUPTO: - break; - - default: - SLJIT_UNREACHABLE(); - break; - } - -set_jumps(current->topbacktracks, LABEL()); -} - -static SLJIT_INLINE void compile_ref_iterator_backtrackingpath(compiler_common *common, struct backtrack_common *current) -{ -DEFINE_COMPILER; -PCRE2_SPTR cc = current->cc; -BOOL ref = (*cc == OP_REF || *cc == OP_REFI); -PCRE2_UCHAR type; - -type = cc[ref ? 1 + IMM2_SIZE : 1 + 2 * IMM2_SIZE]; - -if ((type & 0x1) == 0) - { - /* Maximize case. */ - set_jumps(current->topbacktracks, LABEL()); - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - free_stack(common, 1); - CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(ref_iterator_backtrack)->matchingpath); - return; - } - -OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); -CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(ref_iterator_backtrack)->matchingpath); -set_jumps(current->topbacktracks, LABEL()); -free_stack(common, ref ? 2 : 3); -} - -static SLJIT_INLINE void compile_recurse_backtrackingpath(compiler_common *common, struct backtrack_common *current) -{ -DEFINE_COMPILER; -recurse_entry *entry; - -if (!CURRENT_AS(recurse_backtrack)->inlined_pattern) - { - entry = CURRENT_AS(recurse_backtrack)->entry; - if (entry->backtrack_label == NULL) - add_jump(compiler, &entry->backtrack_calls, JUMP(SLJIT_FAST_CALL)); - else - JUMPTO(SLJIT_FAST_CALL, entry->backtrack_label); - CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, 0, CURRENT_AS(recurse_backtrack)->matchingpath); - } -else - compile_backtrackingpath(common, current->top); - -set_jumps(current->topbacktracks, LABEL()); -} - -static void compile_assert_backtrackingpath(compiler_common *common, struct backtrack_common *current) -{ -DEFINE_COMPILER; -PCRE2_SPTR cc = current->cc; -PCRE2_UCHAR bra = OP_BRA; -struct sljit_jump *brajump = NULL; - -SLJIT_ASSERT(*cc != OP_BRAMINZERO); -if (*cc == OP_BRAZERO) - { - bra = *cc; - cc++; - } - -if (bra == OP_BRAZERO) - { - SLJIT_ASSERT(current->topbacktracks == NULL); - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - } - -if (CURRENT_AS(assert_backtrack)->framesize < 0) - { - set_jumps(current->topbacktracks, LABEL()); - - if (bra == OP_BRAZERO) - { - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); - CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(assert_backtrack)->matchingpath); - free_stack(common, 1); - } - return; - } - -if (bra == OP_BRAZERO) - { - if (*cc == OP_ASSERT_NOT || *cc == OP_ASSERTBACK_NOT) - { - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); - CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(assert_backtrack)->matchingpath); - free_stack(common, 1); - return; - } - free_stack(common, 1); - brajump = CMP(SLJIT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0); - } - -if (*cc == OP_ASSERT || *cc == OP_ASSERTBACK) - { - OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), CURRENT_AS(assert_backtrack)->private_data_ptr); - add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL)); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(-2)); - OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (CURRENT_AS(assert_backtrack)->framesize - 1) * sizeof(sljit_sw)); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), CURRENT_AS(assert_backtrack)->private_data_ptr, TMP1, 0); - - set_jumps(current->topbacktracks, LABEL()); - } -else - set_jumps(current->topbacktracks, LABEL()); - -if (bra == OP_BRAZERO) - { - /* We know there is enough place on the stack. */ - OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw)); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); - JUMPTO(SLJIT_JUMP, CURRENT_AS(assert_backtrack)->matchingpath); - JUMPHERE(brajump); - } -} - -static void compile_bracket_backtrackingpath(compiler_common *common, struct backtrack_common *current) -{ -DEFINE_COMPILER; -int opcode, stacksize, alt_count, alt_max; -int offset = 0; -int private_data_ptr = CURRENT_AS(bracket_backtrack)->private_data_ptr; -int repeat_ptr = 0, repeat_type = 0, repeat_count = 0; -PCRE2_SPTR cc = current->cc; -PCRE2_SPTR ccbegin; -PCRE2_SPTR ccprev; -PCRE2_UCHAR bra = OP_BRA; -PCRE2_UCHAR ket; -assert_backtrack *assert; -BOOL has_alternatives; -BOOL needs_control_head = FALSE; -struct sljit_jump *brazero = NULL; -struct sljit_jump *next_alt = NULL; -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; - -if (*cc == OP_BRAZERO || *cc == OP_BRAMINZERO) - { - bra = *cc; - cc++; - } - -opcode = *cc; -ccbegin = bracketend(cc) - 1 - LINK_SIZE; -ket = *ccbegin; -if (ket == OP_KET && PRIVATE_DATA(ccbegin) != 0) - { - repeat_ptr = PRIVATE_DATA(ccbegin); - repeat_type = PRIVATE_DATA(ccbegin + 2); - repeat_count = PRIVATE_DATA(ccbegin + 3); - SLJIT_ASSERT(repeat_type != 0 && repeat_count != 0); - if (repeat_type == OP_UPTO) - ket = OP_KETRMAX; - if (repeat_type == OP_MINUPTO) - ket = OP_KETRMIN; - } -ccbegin = cc; -cc += GET(cc, 1); -has_alternatives = *cc == OP_ALT; -if (SLJIT_UNLIKELY(opcode == OP_COND) || SLJIT_UNLIKELY(opcode == OP_SCOND)) - has_alternatives = (ccbegin[1 + LINK_SIZE] >= OP_ASSERT && ccbegin[1 + LINK_SIZE] <= OP_ASSERTBACK_NOT) || CURRENT_AS(bracket_backtrack)->u.condfailed != NULL; -if (opcode == OP_CBRA || opcode == OP_SCBRA) - offset = (GET2(ccbegin, 1 + LINK_SIZE)) << 1; -if (SLJIT_UNLIKELY(opcode == OP_COND) && (*cc == OP_KETRMAX || *cc == OP_KETRMIN)) - opcode = OP_SCOND; - -alt_max = has_alternatives ? no_alternatives(ccbegin) : 0; - -/* Decoding the needs_control_head in framesize. */ -if (opcode == OP_ONCE) - { - needs_control_head = (CURRENT_AS(bracket_backtrack)->u.framesize & 0x1) != 0; - CURRENT_AS(bracket_backtrack)->u.framesize >>= 1; - } - -if (ket != OP_KET && repeat_type != 0) - { - /* TMP1 is used in OP_KETRMIN below. */ - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - free_stack(common, 1); - if (repeat_type == OP_UPTO) - OP2(SLJIT_ADD, SLJIT_MEM1(SLJIT_SP), repeat_ptr, TMP1, 0, SLJIT_IMM, 1); - else - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), repeat_ptr, TMP1, 0); - } - -if (ket == OP_KETRMAX) - { - if (bra == OP_BRAZERO) - { - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - free_stack(common, 1); - brazero = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0); - } - } -else if (ket == OP_KETRMIN) - { - if (bra != OP_BRAMINZERO) - { - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - if (repeat_type != 0) - { - /* TMP1 was set a few lines above. */ - CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, 0, CURRENT_AS(bracket_backtrack)->recursive_matchingpath); - /* Drop STR_PTR for non-greedy plus quantifier. */ - if (opcode != OP_ONCE) - free_stack(common, 1); - } - else if (opcode >= OP_SBRA || opcode == OP_ONCE) - { - /* Checking zero-length iteration. */ - if (opcode != OP_ONCE || CURRENT_AS(bracket_backtrack)->u.framesize < 0) - CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, CURRENT_AS(bracket_backtrack)->recursive_matchingpath); - else - { - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); - CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_MEM1(TMP1), STACK(-CURRENT_AS(bracket_backtrack)->u.framesize - 2), CURRENT_AS(bracket_backtrack)->recursive_matchingpath); - } - /* Drop STR_PTR for non-greedy plus quantifier. */ - if (opcode != OP_ONCE) - free_stack(common, 1); - } - else - JUMPTO(SLJIT_JUMP, CURRENT_AS(bracket_backtrack)->recursive_matchingpath); - } - rmin_label = LABEL(); - if (repeat_type != 0) - OP2(SLJIT_ADD, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_IMM, 1); - } -else if (bra == OP_BRAZERO) - { - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - free_stack(common, 1); - brazero = CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, 0); - } -else if (repeat_type == OP_EXACT) - { - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_IMM, 1); - exact_label = LABEL(); - } - -if (offset != 0) - { - if (common->capture_last_ptr != 0) - { - SLJIT_ASSERT(common->optimized_cbracket[offset >> 1] == 0); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(1)); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr, TMP1, 0); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(2)); - free_stack(common, 3); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset), TMP2, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), TMP1, 0); - } - else if (common->optimized_cbracket[offset >> 1] == 0) - { - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(1)); - free_stack(common, 2); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset), TMP1, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), TMP2, 0); - } - } - -if (SLJIT_UNLIKELY(opcode == OP_ONCE)) - { - if (CURRENT_AS(bracket_backtrack)->u.framesize >= 0) - { - OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); - add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL)); - OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (CURRENT_AS(bracket_backtrack)->u.framesize - 1) * sizeof(sljit_sw)); - } - once = JUMP(SLJIT_JUMP); - } -else if (SLJIT_UNLIKELY(opcode == OP_COND) || SLJIT_UNLIKELY(opcode == OP_SCOND)) - { - if (has_alternatives) - { - /* Always exactly one alternative. */ - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - free_stack(common, 1); - - alt_max = 2; - next_alt = CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, 0); - } - } -else if (has_alternatives) - { - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - free_stack(common, 1); - - if (alt_max > 3) - { - 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_emit_op0(compiler, SLJIT_ENDBR); - } - else - next_alt = CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, 0); - } - -COMPILE_BACKTRACKINGPATH(current->top); -if (current->topbacktracks) - set_jumps(current->topbacktracks, LABEL()); - -if (SLJIT_UNLIKELY(opcode == OP_COND) || SLJIT_UNLIKELY(opcode == OP_SCOND)) - { - /* Conditional block always has at most one alternative. */ - if (ccbegin[1 + LINK_SIZE] >= OP_ASSERT && ccbegin[1 + LINK_SIZE] <= OP_ASSERTBACK_NOT) - { - SLJIT_ASSERT(has_alternatives); - assert = CURRENT_AS(bracket_backtrack)->u.assert; - if (assert->framesize >= 0 && (ccbegin[1 + LINK_SIZE] == OP_ASSERT || ccbegin[1 + LINK_SIZE] == OP_ASSERTBACK)) - { - OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), assert->private_data_ptr); - add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL)); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(-2)); - OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (assert->framesize - 1) * sizeof(sljit_sw)); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), assert->private_data_ptr, TMP1, 0); - } - cond = JUMP(SLJIT_JUMP); - set_jumps(CURRENT_AS(bracket_backtrack)->u.assert->condfailed, LABEL()); - } - else if (CURRENT_AS(bracket_backtrack)->u.condfailed != NULL) - { - SLJIT_ASSERT(has_alternatives); - cond = JUMP(SLJIT_JUMP); - set_jumps(CURRENT_AS(bracket_backtrack)->u.condfailed, LABEL()); - } - else - SLJIT_ASSERT(!has_alternatives); - } - -if (has_alternatives) - { - alt_count = 1; - do - { - current->top = NULL; - current->topbacktracks = NULL; - current->nextbacktracks = NULL; - /* Conditional blocks always have an additional alternative, even if it is empty. */ - if (*cc == OP_ALT) - { - ccprev = cc + 1 + LINK_SIZE; - cc += GET(cc, 1); - if (opcode != OP_COND && opcode != OP_SCOND) - { - if (opcode != OP_ONCE) - { - if (private_data_ptr != 0) - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); - else - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - } - else - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(needs_control_head ? 1 : 0)); - } - compile_matchingpath(common, ccprev, cc, current); - if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) - return; - - if (opcode == OP_ASSERT_NA || opcode == OP_ASSERTBACK_NA) - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); - - if (opcode == OP_SCRIPT_RUN) - match_script_run_common(common, private_data_ptr, current); - } - - /* Instructions after the current alternative is successfully matched. */ - /* There is a similar code in compile_bracket_matchingpath. */ - if (opcode == OP_ONCE) - match_once_common(common, ket, CURRENT_AS(bracket_backtrack)->u.framesize, private_data_ptr, has_alternatives, needs_control_head); - - stacksize = 0; - if (repeat_type == OP_MINUPTO) - { - /* We need to preserve the counter. TMP2 will be used below. */ - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), repeat_ptr); - stacksize++; - } - if (ket != OP_KET || bra != OP_BRA) - stacksize++; - if (offset != 0) - { - if (common->capture_last_ptr != 0) - stacksize++; - if (common->optimized_cbracket[offset >> 1] == 0) - stacksize += 2; - } - if (opcode != OP_ONCE) - stacksize++; - - if (stacksize > 0) - allocate_stack(common, stacksize); - - stacksize = 0; - if (repeat_type == OP_MINUPTO) - { - /* TMP2 was set above. */ - OP2(SLJIT_SUB, SLJIT_MEM1(STACK_TOP), STACK(stacksize), TMP2, 0, SLJIT_IMM, 1); - stacksize++; - } - - if (ket != OP_KET || bra != OP_BRA) - { - if (ket != OP_KET) - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), STR_PTR, 0); - else - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), SLJIT_IMM, 0); - stacksize++; - } - - if (offset != 0) - stacksize = match_capture_common(common, stacksize, offset, private_data_ptr); - - if (opcode != OP_ONCE) - { - 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)); - } - - if (offset != 0 && ket == OP_KETRMAX && common->optimized_cbracket[offset >> 1] != 0) - { - /* If ket is not OP_KETRMAX, this code path is executed after the jump to alternative_matchingpath. */ - SLJIT_ASSERT(private_data_ptr == OVECTOR(offset + 0)); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), STR_PTR, 0); - } - - JUMPTO(SLJIT_JUMP, CURRENT_AS(bracket_backtrack)->alternative_matchingpath); - - if (opcode != OP_ONCE) - { - if (alt_max <= 3) - { - JUMPHERE(next_alt); - alt_count++; - if (alt_count < alt_max) - { - SLJIT_ASSERT(alt_count == 2 && alt_max == 3); - next_alt = CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, 1); - } - } - else - { - sljit_set_put_label(put_label, LABEL()); - sljit_emit_op0(compiler, SLJIT_ENDBR); - } - } - - COMPILE_BACKTRACKINGPATH(current->top); - if (current->topbacktracks) - set_jumps(current->topbacktracks, LABEL()); - SLJIT_ASSERT(!current->nextbacktracks); - } - while (*cc == OP_ALT); - - if (cond != NULL) - { - SLJIT_ASSERT(opcode == OP_COND || opcode == OP_SCOND); - assert = CURRENT_AS(bracket_backtrack)->u.assert; - if ((ccbegin[1 + LINK_SIZE] == OP_ASSERT_NOT || ccbegin[1 + LINK_SIZE] == OP_ASSERTBACK_NOT) && assert->framesize >= 0) - { - OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), assert->private_data_ptr); - add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL)); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(-2)); - OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (assert->framesize - 1) * sizeof(sljit_sw)); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), assert->private_data_ptr, TMP1, 0); - } - JUMPHERE(cond); - } - - /* Free the STR_PTR. */ - if (private_data_ptr == 0) - free_stack(common, 1); - } - -if (offset != 0) - { - /* Using both tmp register is better for instruction scheduling. */ - if (common->optimized_cbracket[offset >> 1] != 0) - { - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(1)); - free_stack(common, 2); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset), TMP1, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), TMP2, 0); - } - else - { - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - free_stack(common, 1); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP1, 0); - } - } -else if (opcode == OP_ASSERT_NA || opcode == OP_ASSERTBACK_NA || opcode == OP_SCRIPT_RUN || opcode == OP_SBRA || opcode == OP_SCOND) - { - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_MEM1(STACK_TOP), STACK(0)); - free_stack(common, 1); - } -else if (opcode == OP_ONCE) - { - cc = ccbegin + GET(ccbegin, 1); - stacksize = needs_control_head ? 1 : 0; - - if (CURRENT_AS(bracket_backtrack)->u.framesize >= 0) - { - /* Reset head and drop saved frame. */ - stacksize += CURRENT_AS(bracket_backtrack)->u.framesize + ((ket != OP_KET || *cc == OP_ALT) ? 2 : 1); - } - else if (ket == OP_KETRMAX || (*cc == OP_ALT && ket != OP_KETRMIN)) - { - /* The STR_PTR must be released. */ - stacksize++; - } - - if (stacksize > 0) - free_stack(common, stacksize); - - JUMPHERE(once); - /* Restore previous private_data_ptr */ - if (CURRENT_AS(bracket_backtrack)->u.framesize >= 0) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_MEM1(STACK_TOP), STACK(-CURRENT_AS(bracket_backtrack)->u.framesize - 1)); - else if (ket == OP_KETRMIN) - { - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(1)); - /* See the comment below. */ - free_stack(common, 2); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP1, 0); - } - } - -if (repeat_type == OP_EXACT) - { - OP2(SLJIT_ADD, TMP1, 0, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_IMM, 1); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), repeat_ptr, TMP1, 0); - CMPTO(SLJIT_LESS_EQUAL, TMP1, 0, SLJIT_IMM, repeat_count, exact_label); - } -else if (ket == OP_KETRMAX) - { - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - if (bra != OP_BRAZERO) - free_stack(common, 1); - - CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(bracket_backtrack)->recursive_matchingpath); - if (bra == OP_BRAZERO) - { - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(1)); - JUMPTO(SLJIT_JUMP, CURRENT_AS(bracket_backtrack)->zero_matchingpath); - JUMPHERE(brazero); - free_stack(common, 1); - } - } -else if (ket == OP_KETRMIN) - { - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - - /* OP_ONCE removes everything in case of a backtrack, so we don't - need to explicitly release the STR_PTR. The extra release would - affect badly the free_stack(2) above. */ - if (opcode != OP_ONCE) - free_stack(common, 1); - CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, 0, rmin_label); - if (opcode == OP_ONCE) - free_stack(common, bra == OP_BRAMINZERO ? 2 : 1); - else if (bra == OP_BRAMINZERO) - free_stack(common, 1); - } -else if (bra == OP_BRAZERO) - { - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - JUMPTO(SLJIT_JUMP, CURRENT_AS(bracket_backtrack)->zero_matchingpath); - JUMPHERE(brazero); - } -} - -static SLJIT_INLINE void compile_bracketpos_backtrackingpath(compiler_common *common, struct backtrack_common *current) -{ -DEFINE_COMPILER; -int offset; -struct sljit_jump *jump; - -if (CURRENT_AS(bracketpos_backtrack)->framesize < 0) - { - if (*current->cc == OP_CBRAPOS || *current->cc == OP_SCBRAPOS) - { - offset = (GET2(current->cc, 1 + LINK_SIZE)) << 1; - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(1)); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset), TMP1, 0); - if (common->capture_last_ptr != 0) - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(2)); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), TMP2, 0); - if (common->capture_last_ptr != 0) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr, TMP1, 0); - } - set_jumps(current->topbacktracks, LABEL()); - free_stack(common, CURRENT_AS(bracketpos_backtrack)->stacksize); - return; - } - -OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), CURRENT_AS(bracketpos_backtrack)->private_data_ptr); -add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL)); -OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (CURRENT_AS(bracketpos_backtrack)->framesize - 1) * sizeof(sljit_sw)); - -if (current->topbacktracks) - { - jump = JUMP(SLJIT_JUMP); - set_jumps(current->topbacktracks, LABEL()); - /* Drop the stack frame. */ - free_stack(common, CURRENT_AS(bracketpos_backtrack)->stacksize); - JUMPHERE(jump); - } -OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), CURRENT_AS(bracketpos_backtrack)->private_data_ptr, SLJIT_MEM1(STACK_TOP), STACK(-CURRENT_AS(bracketpos_backtrack)->framesize - 1)); -} - -static SLJIT_INLINE void compile_braminzero_backtrackingpath(compiler_common *common, struct backtrack_common *current) -{ -assert_backtrack backtrack; - -current->top = NULL; -current->topbacktracks = NULL; -current->nextbacktracks = NULL; -if (current->cc[1] > OP_ASSERTBACK_NOT) - { - /* Manual call of compile_bracket_matchingpath and compile_bracket_backtrackingpath. */ - compile_bracket_matchingpath(common, current->cc, current); - compile_bracket_backtrackingpath(common, current->top); - } -else - { - memset(&backtrack, 0, sizeof(backtrack)); - backtrack.common.cc = current->cc; - backtrack.matchingpath = CURRENT_AS(braminzero_backtrack)->matchingpath; - /* Manual call of compile_assert_matchingpath. */ - compile_assert_matchingpath(common, current->cc, &backtrack, FALSE); - } -SLJIT_ASSERT(!current->nextbacktracks && !current->topbacktracks); -} - -static SLJIT_INLINE void compile_control_verb_backtrackingpath(compiler_common *common, struct backtrack_common *current) -{ -DEFINE_COMPILER; -PCRE2_UCHAR opcode = *current->cc; -struct sljit_label *loop; -struct sljit_jump *jump; - -if (opcode == OP_THEN || opcode == OP_THEN_ARG) - { - if (common->then_trap != NULL) - { - SLJIT_ASSERT(common->control_head_ptr != 0); - - OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, type_then_trap); - OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, common->then_trap->start); - jump = JUMP(SLJIT_JUMP); - - loop = LABEL(); - OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - JUMPHERE(jump); - CMPTO(SLJIT_NOT_EQUAL, SLJIT_MEM1(STACK_TOP), STACK(1), TMP1, 0, loop); - CMPTO(SLJIT_NOT_EQUAL, SLJIT_MEM1(STACK_TOP), STACK(2), TMP2, 0, loop); - add_jump(compiler, &common->then_trap->quit, JUMP(SLJIT_JUMP)); - return; - } - else if (!common->local_quit_available && common->in_positive_assertion) - { - add_jump(compiler, &common->positive_assertion_quit, JUMP(SLJIT_JUMP)); - return; - } - } - -if (common->local_quit_available) - { - /* Abort match with a fail. */ - if (common->quit_label == NULL) - add_jump(compiler, &common->quit, JUMP(SLJIT_JUMP)); - else - JUMPTO(SLJIT_JUMP, common->quit_label); - return; - } - -if (opcode == OP_SKIP_ARG) - { - SLJIT_ASSERT(common->control_head_ptr != 0 && TMP1 == SLJIT_R0 && STR_PTR == SLJIT_R1); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr); - OP1(SLJIT_MOV, SLJIT_R1, 0, SLJIT_IMM, (sljit_sw)(current->cc + 2)); - sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_ARGS2(W, W, W), SLJIT_IMM, SLJIT_FUNC_ADDR(do_search_mark)); - - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_R0, 0); - add_jump(compiler, &common->reset_match, CMP(SLJIT_NOT_EQUAL, SLJIT_R0, 0, SLJIT_IMM, 0)); - return; - } - -if (opcode == OP_SKIP) - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); -else - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_IMM, 0); -add_jump(compiler, &common->reset_match, JUMP(SLJIT_JUMP)); -} - -static SLJIT_INLINE void compile_then_trap_backtrackingpath(compiler_common *common, struct backtrack_common *current) -{ -DEFINE_COMPILER; -struct sljit_jump *jump; -int size; - -if (CURRENT_AS(then_trap_backtrack)->then_trap) - { - common->then_trap = CURRENT_AS(then_trap_backtrack)->then_trap; - return; - } - -size = CURRENT_AS(then_trap_backtrack)->framesize; -size = 3 + (size < 0 ? 0 : size); - -OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(size - 3)); -free_stack(common, size); -jump = JUMP(SLJIT_JUMP); - -set_jumps(CURRENT_AS(then_trap_backtrack)->quit, LABEL()); -/* STACK_TOP is set by THEN. */ -if (CURRENT_AS(then_trap_backtrack)->framesize >= 0) - { - add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL)); - OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (CURRENT_AS(then_trap_backtrack)->framesize - 1) * sizeof(sljit_sw)); - } -OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); -free_stack(common, 3); - -JUMPHERE(jump); -OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, TMP1, 0); -} - -static void compile_backtrackingpath(compiler_common *common, struct backtrack_common *current) -{ -DEFINE_COMPILER; -then_trap_backtrack *save_then_trap = common->then_trap; - -while (current) - { - if (current->nextbacktracks != NULL) - set_jumps(current->nextbacktracks, LABEL()); - switch(*current->cc) - { - case OP_SET_SOM: - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - free_stack(common, 1); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(0), TMP1, 0); - break; - - case OP_STAR: - case OP_MINSTAR: - case OP_PLUS: - case OP_MINPLUS: - case OP_QUERY: - case OP_MINQUERY: - case OP_UPTO: - case OP_MINUPTO: - case OP_EXACT: - case OP_POSSTAR: - case OP_POSPLUS: - case OP_POSQUERY: - case OP_POSUPTO: - case OP_STARI: - case OP_MINSTARI: - case OP_PLUSI: - case OP_MINPLUSI: - case OP_QUERYI: - case OP_MINQUERYI: - case OP_UPTOI: - case OP_MINUPTOI: - case OP_EXACTI: - case OP_POSSTARI: - case OP_POSPLUSI: - case OP_POSQUERYI: - case OP_POSUPTOI: - case OP_NOTSTAR: - case OP_NOTMINSTAR: - case OP_NOTPLUS: - case OP_NOTMINPLUS: - case OP_NOTQUERY: - case OP_NOTMINQUERY: - case OP_NOTUPTO: - case OP_NOTMINUPTO: - case OP_NOTEXACT: - case OP_NOTPOSSTAR: - case OP_NOTPOSPLUS: - case OP_NOTPOSQUERY: - case OP_NOTPOSUPTO: - case OP_NOTSTARI: - case OP_NOTMINSTARI: - case OP_NOTPLUSI: - case OP_NOTMINPLUSI: - case OP_NOTQUERYI: - case OP_NOTMINQUERYI: - case OP_NOTUPTOI: - case OP_NOTMINUPTOI: - case OP_NOTEXACTI: - case OP_NOTPOSSTARI: - case OP_NOTPOSPLUSI: - case OP_NOTPOSQUERYI: - case OP_NOTPOSUPTOI: - case OP_TYPESTAR: - case OP_TYPEMINSTAR: - case OP_TYPEPLUS: - case OP_TYPEMINPLUS: - case OP_TYPEQUERY: - case OP_TYPEMINQUERY: - case OP_TYPEUPTO: - case OP_TYPEMINUPTO: - case OP_TYPEEXACT: - case OP_TYPEPOSSTAR: - case OP_TYPEPOSPLUS: - case OP_TYPEPOSQUERY: - case OP_TYPEPOSUPTO: - case OP_CLASS: - case OP_NCLASS: -#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8 - case OP_XCLASS: -#endif - compile_iterator_backtrackingpath(common, current); - break; - - case OP_REF: - case OP_REFI: - case OP_DNREF: - case OP_DNREFI: - compile_ref_iterator_backtrackingpath(common, current); - break; - - case OP_RECURSE: - compile_recurse_backtrackingpath(common, current); - break; - - case OP_ASSERT: - case OP_ASSERT_NOT: - case OP_ASSERTBACK: - case OP_ASSERTBACK_NOT: - compile_assert_backtrackingpath(common, current); - break; - - case OP_ASSERT_NA: - case OP_ASSERTBACK_NA: - case OP_ONCE: - case OP_SCRIPT_RUN: - case OP_BRA: - case OP_CBRA: - case OP_COND: - case OP_SBRA: - case OP_SCBRA: - case OP_SCOND: - compile_bracket_backtrackingpath(common, current); - break; - - case OP_BRAZERO: - if (current->cc[1] > OP_ASSERTBACK_NOT) - compile_bracket_backtrackingpath(common, current); - else - compile_assert_backtrackingpath(common, current); - break; - - case OP_BRAPOS: - case OP_CBRAPOS: - case OP_SBRAPOS: - case OP_SCBRAPOS: - case OP_BRAPOSZERO: - compile_bracketpos_backtrackingpath(common, current); - break; - - case OP_BRAMINZERO: - compile_braminzero_backtrackingpath(common, current); - break; - - case OP_MARK: - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(common->has_skip_arg ? 4 : 0)); - if (common->has_skip_arg) - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - free_stack(common, common->has_skip_arg ? 5 : 1); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->mark_ptr, TMP1, 0); - if (common->has_skip_arg) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, TMP2, 0); - break; - - case OP_THEN: - case OP_THEN_ARG: - case OP_PRUNE: - case OP_PRUNE_ARG: - case OP_SKIP: - case OP_SKIP_ARG: - compile_control_verb_backtrackingpath(common, current); - break; - - case OP_COMMIT: - case OP_COMMIT_ARG: - if (!common->local_quit_available) - OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE2_ERROR_NOMATCH); - if (common->quit_label == NULL) - add_jump(compiler, &common->quit, JUMP(SLJIT_JUMP)); - else - JUMPTO(SLJIT_JUMP, common->quit_label); - break; - - case OP_CALLOUT: - case OP_CALLOUT_STR: - case OP_FAIL: - case OP_ACCEPT: - case OP_ASSERT_ACCEPT: - set_jumps(current->topbacktracks, LABEL()); - break; - - case OP_THEN_TRAP: - /* A virtual opcode for then traps. */ - compile_then_trap_backtrackingpath(common, current); - break; - - default: - SLJIT_UNREACHABLE(); - break; - } - current = current->prev; - } -common->then_trap = save_then_trap; -} - -static SLJIT_INLINE void compile_recurse(compiler_common *common) -{ -DEFINE_COMPILER; -PCRE2_SPTR cc = common->start + common->currententry->start; -PCRE2_SPTR ccbegin = cc + 1 + LINK_SIZE + (*cc == OP_BRA ? 0 : IMM2_SIZE); -PCRE2_SPTR ccend = bracketend(cc) - (1 + LINK_SIZE); -uint32_t recurse_flags = 0; -int private_data_size = get_recurse_data_length(common, ccbegin, ccend, &recurse_flags); -int alt_count, alt_max, local_size; -backtrack_common altbacktrack; -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; - -/* Recurse captures then. */ -common->then_trap = NULL; - -SLJIT_ASSERT(*cc == OP_BRA || *cc == OP_CBRA || *cc == OP_CBRAPOS || *cc == OP_SCBRA || *cc == OP_SCBRAPOS); - -alt_max = no_alternatives(cc); -alt_count = 0; - -/* Matching path. */ -SLJIT_ASSERT(common->currententry->entry_label == NULL && common->recursive_head_ptr != 0); -common->currententry->entry_label = LABEL(); -set_jumps(common->currententry->entry_calls, common->currententry->entry_label); - -sljit_emit_fast_enter(compiler, TMP2, 0); -count_match(common); - -local_size = (alt_max > 1) ? 2 : 1; - -/* (Reversed) stack layout: - [private data][return address][optional: str ptr] ... [optional: alternative index][recursive_head_ptr] */ - -allocate_stack(common, private_data_size + local_size); -/* Save return address. */ -OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(local_size - 1), TMP2, 0); - -copy_recurse_data(common, ccbegin, ccend, recurse_copy_from_global, local_size, private_data_size + local_size, recurse_flags); - -/* This variable is saved and restored all time when we enter or exit from a recursive context. */ -OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->recursive_head_ptr, STACK_TOP, 0); - -if (recurse_flags & recurse_flag_control_head_found) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_IMM, 0); - -if (alt_max > 1) - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); - -memset(&altbacktrack, 0, sizeof(backtrack_common)); -common->quit_label = NULL; -common->accept_label = NULL; -common->quit = NULL; -common->accept = NULL; -altbacktrack.cc = ccbegin; -cc += GET(cc, 1); -while (1) - { - altbacktrack.top = NULL; - altbacktrack.topbacktracks = NULL; - - if (altbacktrack.cc != ccbegin) - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - - compile_matchingpath(common, altbacktrack.cc, cc, &altbacktrack); - if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) - return; - - allocate_stack(common, (alt_max > 1 || (recurse_flags & recurse_flag_accept_found)) ? 2 : 1); - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->recursive_head_ptr); - - 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)); - else - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, alt_count); - } - - add_jump(compiler, &match, JUMP(SLJIT_JUMP)); - - if (alt_count == 0) - { - /* Backtracking path entry. */ - SLJIT_ASSERT(common->currententry->backtrack_label == NULL); - common->currententry->backtrack_label = LABEL(); - set_jumps(common->currententry->backtrack_calls, common->currententry->backtrack_label); - - sljit_emit_fast_enter(compiler, TMP1, 0); - - if (recurse_flags & recurse_flag_accept_found) - accept_exit = CMP(SLJIT_EQUAL, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, -1); - - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - /* Save return address. */ - OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), STACK(local_size - 1), TMP1, 0); - - copy_recurse_data(common, ccbegin, ccend, recurse_swap_global, local_size, private_data_size + local_size, recurse_flags); - - if (alt_max > 1) - { - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(1)); - free_stack(common, 2); - - if (alt_max > 3) - { - sljit_emit_ijump(compiler, SLJIT_JUMP, TMP1, 0); - sljit_set_put_label(put_label, LABEL()); - sljit_emit_op0(compiler, SLJIT_ENDBR); - } - else - next_alt = CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, 0); - } - else - free_stack(common, (recurse_flags & recurse_flag_accept_found) ? 2 : 1); - } - else if (alt_max > 3) - { - sljit_set_put_label(put_label, LABEL()); - sljit_emit_op0(compiler, SLJIT_ENDBR); - } - else - { - JUMPHERE(next_alt); - if (alt_count + 1 < alt_max) - { - SLJIT_ASSERT(alt_count == 1 && alt_max == 3); - next_alt = CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, 1); - } - } - - alt_count++; - - compile_backtrackingpath(common, altbacktrack.top); - if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) - return; - set_jumps(altbacktrack.topbacktracks, LABEL()); - - if (*cc != OP_ALT) - break; - - altbacktrack.cc = cc + 1 + LINK_SIZE; - cc += GET(cc, 1); - } - -/* No alternative is matched. */ - -quit = LABEL(); - -copy_recurse_data(common, ccbegin, ccend, recurse_copy_private_to_global, local_size, private_data_size + local_size, recurse_flags); - -OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(local_size - 1)); -free_stack(common, private_data_size + local_size); -OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0); -OP_SRC(SLJIT_FAST_RETURN, TMP2, 0); - -if (common->quit != NULL) - { - SLJIT_ASSERT(recurse_flags & recurse_flag_quit_found); - - set_jumps(common->quit, LABEL()); - OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), common->recursive_head_ptr); - copy_recurse_data(common, ccbegin, ccend, recurse_copy_shared_to_global, local_size, private_data_size + local_size, recurse_flags); - JUMPTO(SLJIT_JUMP, quit); - } - -if (recurse_flags & recurse_flag_accept_found) - { - JUMPHERE(accept_exit); - free_stack(common, 2); - - /* Save return address. */ - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(local_size - 1), TMP1, 0); - - copy_recurse_data(common, ccbegin, ccend, recurse_copy_kept_shared_to_global, local_size, private_data_size + local_size, recurse_flags); - - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(local_size - 1)); - free_stack(common, private_data_size + local_size); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0); - OP_SRC(SLJIT_FAST_RETURN, TMP2, 0); - } - -if (common->accept != NULL) - { - SLJIT_ASSERT(recurse_flags & recurse_flag_accept_found); - - set_jumps(common->accept, LABEL()); - - OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), common->recursive_head_ptr); - OP1(SLJIT_MOV, TMP2, 0, STACK_TOP, 0); - - allocate_stack(common, 2); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, -1); - } - -set_jumps(match, LABEL()); - -OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP2, 0); - -copy_recurse_data(common, ccbegin, ccend, recurse_swap_global, local_size, private_data_size + local_size, recurse_flags); - -OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP2), STACK(local_size - 1)); -OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 1); -OP_SRC(SLJIT_FAST_RETURN, TMP2, 0); -} - -#undef COMPILE_BACKTRACKINGPATH -#undef CURRENT_AS - -#define PUBLIC_JIT_COMPILE_CONFIGURATION_OPTIONS \ - (PCRE2_JIT_INVALID_UTF) - -static int jit_compile(pcre2_code *code, sljit_u32 mode) -{ -pcre2_real_code *re = (pcre2_real_code *)code; -struct sljit_compiler *compiler; -backtrack_common rootbacktrack; -compiler_common common_data; -compiler_common *common = &common_data; -const sljit_u8 *tables = re->tables; -void *allocator_data = &re->memctl; -int private_data_size; -PCRE2_SPTR ccend; -executable_functions *functions; -void *executable_func; -sljit_uw executable_size; -sljit_uw total_length; -struct sljit_label *mainloop_label = NULL; -struct sljit_label *continue_match_label; -struct sljit_label *empty_match_found_label = NULL; -struct sljit_label *empty_match_backtrack_label = NULL; -struct sljit_label *reset_match_label; -struct sljit_label *quit_label; -struct sljit_jump *jump; -struct sljit_jump *minlength_check_failed = NULL; -struct sljit_jump *empty_match = NULL; -struct sljit_jump *end_anchor_failed = NULL; -jump_list *reqcu_not_found = NULL; - -SLJIT_ASSERT(tables); - -#if HAS_VIRTUAL_REGISTERS == 1 -SLJIT_ASSERT(sljit_get_register_index(TMP3) < 0 && sljit_get_register_index(ARGUMENTS) < 0 && sljit_get_register_index(RETURN_ADDR) < 0); -#elif HAS_VIRTUAL_REGISTERS == 0 -SLJIT_ASSERT(sljit_get_register_index(TMP3) >= 0 && sljit_get_register_index(ARGUMENTS) >= 0 && sljit_get_register_index(RETURN_ADDR) >= 0); -#else -#error "Invalid value for HAS_VIRTUAL_REGISTERS" -#endif - -memset(&rootbacktrack, 0, sizeof(backtrack_common)); -memset(common, 0, sizeof(compiler_common)); -common->re = re; -common->name_table = (PCRE2_SPTR)((uint8_t *)re + sizeof(pcre2_real_code)); -rootbacktrack.cc = common->name_table + re->name_count * re->name_entry_size; - -#ifdef SUPPORT_UNICODE -common->invalid_utf = (mode & PCRE2_JIT_INVALID_UTF) != 0; -#endif /* SUPPORT_UNICODE */ -mode &= ~PUBLIC_JIT_COMPILE_CONFIGURATION_OPTIONS; - -common->start = rootbacktrack.cc; -common->read_only_data_head = NULL; -common->fcc = tables + fcc_offset; -common->lcc = (sljit_sw)(tables + lcc_offset); -common->mode = mode; -common->might_be_empty = (re->minlength == 0) || (re->flags & PCRE2_MATCH_EMPTY); -common->allow_empty_partial = (re->max_lookbehind > 0) || (re->flags & PCRE2_MATCH_EMPTY); -common->nltype = NLTYPE_FIXED; -switch(re->newline_convention) - { - case PCRE2_NEWLINE_CR: common->newline = CHAR_CR; break; - case PCRE2_NEWLINE_LF: common->newline = CHAR_NL; break; - case PCRE2_NEWLINE_CRLF: common->newline = (CHAR_CR << 8) | CHAR_NL; break; - case PCRE2_NEWLINE_ANY: common->newline = (CHAR_CR << 8) | CHAR_NL; common->nltype = NLTYPE_ANY; break; - case PCRE2_NEWLINE_ANYCRLF: common->newline = (CHAR_CR << 8) | CHAR_NL; common->nltype = NLTYPE_ANYCRLF; break; - case PCRE2_NEWLINE_NUL: common->newline = CHAR_NUL; break; - default: return PCRE2_ERROR_INTERNAL; - } -common->nlmax = READ_CHAR_MAX; -common->nlmin = 0; -if (re->bsr_convention == PCRE2_BSR_UNICODE) - common->bsr_nltype = NLTYPE_ANY; -else if (re->bsr_convention == PCRE2_BSR_ANYCRLF) - common->bsr_nltype = NLTYPE_ANYCRLF; -else - { -#ifdef BSR_ANYCRLF - common->bsr_nltype = NLTYPE_ANYCRLF; -#else - common->bsr_nltype = NLTYPE_ANY; -#endif - } -common->bsr_nlmax = READ_CHAR_MAX; -common->bsr_nlmin = 0; -common->endonly = (re->overall_options & PCRE2_DOLLAR_ENDONLY) != 0; -common->ctypes = (sljit_sw)(tables + ctypes_offset); -common->name_count = re->name_count; -common->name_entry_size = re->name_entry_size; -common->unset_backref = (re->overall_options & PCRE2_MATCH_UNSET_BACKREF) != 0; -common->alt_circumflex = (re->overall_options & PCRE2_ALT_CIRCUMFLEX) != 0; -#ifdef SUPPORT_UNICODE -/* PCRE_UTF[16|32] have the same value as PCRE_UTF8. */ -common->utf = (re->overall_options & PCRE2_UTF) != 0; -common->ucp = (re->overall_options & PCRE2_UCP) != 0; -if (common->utf) - { - if (common->nltype == NLTYPE_ANY) - common->nlmax = 0x2029; - else if (common->nltype == NLTYPE_ANYCRLF) - common->nlmax = (CHAR_CR > CHAR_NL) ? CHAR_CR : CHAR_NL; - else - { - /* We only care about the first newline character. */ - common->nlmax = common->newline & 0xff; - } - - if (common->nltype == NLTYPE_FIXED) - common->nlmin = common->newline & 0xff; - else - common->nlmin = (CHAR_CR < CHAR_NL) ? CHAR_CR : CHAR_NL; - - if (common->bsr_nltype == NLTYPE_ANY) - common->bsr_nlmax = 0x2029; - else - common->bsr_nlmax = (CHAR_CR > CHAR_NL) ? CHAR_CR : CHAR_NL; - common->bsr_nlmin = (CHAR_CR < CHAR_NL) ? CHAR_CR : CHAR_NL; - } -else - common->invalid_utf = FALSE; -#endif /* SUPPORT_UNICODE */ -ccend = bracketend(common->start); - -/* Calculate the local space size on the stack. */ -common->ovector_start = LIMIT_MATCH + sizeof(sljit_sw); -common->optimized_cbracket = (sljit_u8 *)SLJIT_MALLOC(re->top_bracket + 1, allocator_data); -if (!common->optimized_cbracket) - return PCRE2_ERROR_NOMEMORY; -#if defined DEBUG_FORCE_UNOPTIMIZED_CBRAS && DEBUG_FORCE_UNOPTIMIZED_CBRAS == 1 -memset(common->optimized_cbracket, 0, re->top_bracket + 1); -#else -memset(common->optimized_cbracket, 1, re->top_bracket + 1); -#endif - -SLJIT_ASSERT(*common->start == OP_BRA && ccend[-(1 + LINK_SIZE)] == OP_KET); -#if defined DEBUG_FORCE_UNOPTIMIZED_CBRAS && DEBUG_FORCE_UNOPTIMIZED_CBRAS == 2 -common->capture_last_ptr = common->ovector_start; -common->ovector_start += sizeof(sljit_sw); -#endif -if (!check_opcode_types(common, common->start, ccend)) - { - SLJIT_FREE(common->optimized_cbracket, allocator_data); - return PCRE2_ERROR_NOMEMORY; - } - -/* Checking flags and updating ovector_start. */ -if (mode == PCRE2_JIT_COMPLETE && (re->flags & PCRE2_LASTSET) != 0 && (re->overall_options & PCRE2_NO_START_OPTIMIZE) == 0) - { - common->req_char_ptr = common->ovector_start; - common->ovector_start += sizeof(sljit_sw); - } -if (mode != PCRE2_JIT_COMPLETE) - { - common->start_used_ptr = common->ovector_start; - common->ovector_start += sizeof(sljit_sw); - if (mode == PCRE2_JIT_PARTIAL_SOFT) - { - common->hit_start = common->ovector_start; - common->ovector_start += sizeof(sljit_sw); - } - } -if ((re->overall_options & (PCRE2_FIRSTLINE | PCRE2_USE_OFFSET_LIMIT)) != 0) - { - common->match_end_ptr = common->ovector_start; - common->ovector_start += sizeof(sljit_sw); - } -#if defined DEBUG_FORCE_CONTROL_HEAD && DEBUG_FORCE_CONTROL_HEAD -common->control_head_ptr = 1; -#endif -if (common->control_head_ptr != 0) - { - common->control_head_ptr = common->ovector_start; - common->ovector_start += sizeof(sljit_sw); - } -if (common->has_set_som) - { - /* Saving the real start pointer is necessary. */ - common->start_ptr = common->ovector_start; - common->ovector_start += sizeof(sljit_sw); - } - -/* Aligning ovector to even number of sljit words. */ -if ((common->ovector_start & sizeof(sljit_sw)) != 0) - common->ovector_start += sizeof(sljit_sw); - -if (common->start_ptr == 0) - common->start_ptr = OVECTOR(0); - -/* Capturing brackets cannot be optimized if callouts are allowed. */ -if (common->capture_last_ptr != 0) - memset(common->optimized_cbracket, 0, re->top_bracket + 1); - -SLJIT_ASSERT(!(common->req_char_ptr != 0 && common->start_used_ptr != 0)); -common->cbra_ptr = OVECTOR_START + (re->top_bracket + 1) * 2 * sizeof(sljit_sw); - -total_length = ccend - common->start; -common->private_data_ptrs = (sljit_s32*)SLJIT_MALLOC(total_length * (sizeof(sljit_s32) + (common->has_then ? 1 : 0)), allocator_data); -if (!common->private_data_ptrs) - { - SLJIT_FREE(common->optimized_cbracket, allocator_data); - return PCRE2_ERROR_NOMEMORY; - } -memset(common->private_data_ptrs, 0, total_length * sizeof(sljit_s32)); - -private_data_size = common->cbra_ptr + (re->top_bracket + 1) * sizeof(sljit_sw); - -if ((re->overall_options & PCRE2_ANCHORED) == 0 && (re->overall_options & PCRE2_NO_START_OPTIMIZE) == 0 && !common->has_skip_in_assert_back) - detect_early_fail(common, common->start, &private_data_size, 0, 0, TRUE); - -set_private_data_ptrs(common, &private_data_size, ccend); - -SLJIT_ASSERT(common->early_fail_start_ptr <= common->early_fail_end_ptr); - -if (private_data_size > SLJIT_MAX_LOCAL_SIZE) - { - SLJIT_FREE(common->private_data_ptrs, allocator_data); - SLJIT_FREE(common->optimized_cbracket, allocator_data); - return PCRE2_ERROR_NOMEMORY; - } - -if (common->has_then) - { - common->then_offsets = (sljit_u8 *)(common->private_data_ptrs + total_length); - memset(common->then_offsets, 0, total_length); - set_then_offsets(common, common->start, NULL); - } - -compiler = sljit_create_compiler(allocator_data, NULL); -if (!compiler) - { - SLJIT_FREE(common->optimized_cbracket, allocator_data); - SLJIT_FREE(common->private_data_ptrs, allocator_data); - return PCRE2_ERROR_NOMEMORY; - } -common->compiler = compiler; - -/* Main pcre2_jit_exec entry. */ -SLJIT_ASSERT((private_data_size & (sizeof(sljit_sw) - 1)) == 0); -sljit_emit_enter(compiler, 0, SLJIT_ARGS1(W, W), 5, 5, 0, 0, private_data_size); - -/* Register init. */ -reset_ovector(common, (re->top_bracket + 1) * 2); -if (common->req_char_ptr != 0) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->req_char_ptr, SLJIT_R0, 0); - -OP1(SLJIT_MOV, ARGUMENTS, 0, SLJIT_S0, 0); -OP1(SLJIT_MOV, TMP1, 0, SLJIT_S0, 0); -OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, str)); -OP1(SLJIT_MOV, STR_END, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, end)); -OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, stack)); -OP1(SLJIT_MOV_U32, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, limit_match)); -OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(struct sljit_stack, end)); -OP1(SLJIT_MOV, STACK_LIMIT, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(struct sljit_stack, start)); -OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 1); -OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LIMIT_MATCH, TMP1, 0); - -if (common->early_fail_start_ptr < common->early_fail_end_ptr) - reset_early_fail(common); - -if (mode == PCRE2_JIT_PARTIAL_SOFT) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->hit_start, SLJIT_IMM, -1); -if (common->mark_ptr != 0) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->mark_ptr, SLJIT_IMM, 0); -if (common->control_head_ptr != 0) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_IMM, 0); - -/* Main part of the matching */ -if ((re->overall_options & PCRE2_ANCHORED) == 0) - { - mainloop_label = mainloop_entry(common); - continue_match_label = LABEL(); - /* Forward search if possible. */ - if ((re->overall_options & PCRE2_NO_START_OPTIMIZE) == 0) - { - if (mode == PCRE2_JIT_COMPLETE && fast_forward_first_n_chars(common)) - ; - else if ((re->flags & PCRE2_FIRSTSET) != 0) - fast_forward_first_char(common); - else if ((re->flags & PCRE2_STARTLINE) != 0) - fast_forward_newline(common); - else if ((re->flags & PCRE2_FIRSTMAPSET) != 0) - fast_forward_start_bits(common); - } - } -else - continue_match_label = LABEL(); - -if (mode == PCRE2_JIT_COMPLETE && re->minlength > 0 && (re->overall_options & PCRE2_NO_START_OPTIMIZE) == 0) - { - OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE2_ERROR_NOMATCH); - OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(re->minlength)); - minlength_check_failed = CMP(SLJIT_GREATER, TMP2, 0, STR_END, 0); - } -if (common->req_char_ptr != 0) - reqcu_not_found = search_requested_char(common, (PCRE2_UCHAR)(re->last_codeunit), (re->flags & PCRE2_LASTCASELESS) != 0, (re->flags & PCRE2_FIRSTSET) != 0); - -/* Store the current STR_PTR in OVECTOR(0). */ -OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(0), STR_PTR, 0); -/* Copy the limit of allowed recursions. */ -OP1(SLJIT_MOV, COUNT_MATCH, 0, SLJIT_MEM1(SLJIT_SP), LIMIT_MATCH); -if (common->capture_last_ptr != 0) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr, SLJIT_IMM, 0); -if (common->fast_forward_bc_ptr != NULL) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), PRIVATE_DATA(common->fast_forward_bc_ptr + 1) >> 3, STR_PTR, 0); - -if (common->start_ptr != OVECTOR(0)) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->start_ptr, STR_PTR, 0); - -/* Copy the beginning of the string. */ -if (mode == PCRE2_JIT_PARTIAL_SOFT) - { - jump = CMP(SLJIT_NOT_EQUAL, SLJIT_MEM1(SLJIT_SP), common->hit_start, SLJIT_IMM, -1); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0); - JUMPHERE(jump); - } -else if (mode == PCRE2_JIT_PARTIAL_HARD) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0); - -compile_matchingpath(common, common->start, ccend, &rootbacktrack); -if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) - { - sljit_free_compiler(compiler); - SLJIT_FREE(common->optimized_cbracket, allocator_data); - SLJIT_FREE(common->private_data_ptrs, allocator_data); - PRIV(jit_free_rodata)(common->read_only_data_head, allocator_data); - return PCRE2_ERROR_NOMEMORY; - } - -if ((re->overall_options & PCRE2_ENDANCHORED) != 0) - end_anchor_failed = CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, STR_END, 0); - -if (common->might_be_empty) - { - empty_match = CMP(SLJIT_EQUAL, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(0)); - empty_match_found_label = LABEL(); - } - -common->accept_label = LABEL(); -if (common->accept != NULL) - set_jumps(common->accept, common->accept_label); - -/* This means we have a match. Update the ovector. */ -copy_ovector(common, re->top_bracket + 1); -common->quit_label = common->abort_label = LABEL(); -if (common->quit != NULL) - set_jumps(common->quit, common->quit_label); -if (common->abort != NULL) - set_jumps(common->abort, common->abort_label); -if (minlength_check_failed != NULL) - SET_LABEL(minlength_check_failed, common->abort_label); - -sljit_emit_op0(compiler, SLJIT_SKIP_FRAMES_BEFORE_RETURN); -sljit_emit_return(compiler, SLJIT_MOV, SLJIT_RETURN_REG, 0); - -if (common->failed_match != NULL) - { - SLJIT_ASSERT(common->mode == PCRE2_JIT_COMPLETE); - set_jumps(common->failed_match, LABEL()); - OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE2_ERROR_NOMATCH); - JUMPTO(SLJIT_JUMP, common->abort_label); - } - -if ((re->overall_options & PCRE2_ENDANCHORED) != 0) - JUMPHERE(end_anchor_failed); - -if (mode != PCRE2_JIT_COMPLETE) - { - common->partialmatchlabel = LABEL(); - set_jumps(common->partialmatch, common->partialmatchlabel); - return_with_partial_match(common, common->quit_label); - } - -if (common->might_be_empty) - empty_match_backtrack_label = LABEL(); -compile_backtrackingpath(common, rootbacktrack.top); -if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) - { - sljit_free_compiler(compiler); - SLJIT_FREE(common->optimized_cbracket, allocator_data); - SLJIT_FREE(common->private_data_ptrs, allocator_data); - PRIV(jit_free_rodata)(common->read_only_data_head, allocator_data); - return PCRE2_ERROR_NOMEMORY; - } - -SLJIT_ASSERT(rootbacktrack.prev == NULL); -reset_match_label = LABEL(); - -if (mode == PCRE2_JIT_PARTIAL_SOFT) - { - /* Update hit_start only in the first time. */ - jump = CMP(SLJIT_NOT_EQUAL, SLJIT_MEM1(SLJIT_SP), common->hit_start, SLJIT_IMM, 0); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->start_ptr); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, SLJIT_IMM, -1); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->hit_start, TMP1, 0); - JUMPHERE(jump); - } - -/* Check we have remaining characters. */ -if ((re->overall_options & PCRE2_ANCHORED) == 0 && common->match_end_ptr != 0) - { - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr); - } - -OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), - (common->fast_forward_bc_ptr != NULL) ? (PRIVATE_DATA(common->fast_forward_bc_ptr + 1) >> 3) : common->start_ptr); - -if ((re->overall_options & PCRE2_ANCHORED) == 0) - { - if (common->ff_newline_shortcut != NULL) - { - /* There cannot be more newlines if PCRE2_FIRSTLINE is set. */ - if ((re->overall_options & PCRE2_FIRSTLINE) == 0) - { - if (common->match_end_ptr != 0) - { - OP1(SLJIT_MOV, TMP3, 0, STR_END, 0); - OP1(SLJIT_MOV, STR_END, 0, TMP1, 0); - CMPTO(SLJIT_LESS, STR_PTR, 0, TMP1, 0, common->ff_newline_shortcut); - OP1(SLJIT_MOV, STR_END, 0, TMP3, 0); - } - else - CMPTO(SLJIT_LESS, STR_PTR, 0, STR_END, 0, common->ff_newline_shortcut); - } - } - else - CMPTO(SLJIT_LESS, STR_PTR, 0, (common->match_end_ptr == 0) ? STR_END : TMP1, 0, mainloop_label); - } - -/* No more remaining characters. */ -if (reqcu_not_found != NULL) - set_jumps(reqcu_not_found, LABEL()); - -if (mode == PCRE2_JIT_PARTIAL_SOFT) - CMPTO(SLJIT_NOT_EQUAL, SLJIT_MEM1(SLJIT_SP), common->hit_start, SLJIT_IMM, -1, common->partialmatchlabel); - -OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE2_ERROR_NOMATCH); -JUMPTO(SLJIT_JUMP, common->quit_label); - -flush_stubs(common); - -if (common->might_be_empty) - { - JUMPHERE(empty_match); - OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0); - OP1(SLJIT_MOV_U32, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, options)); - OP2U(SLJIT_AND | SLJIT_SET_Z, TMP2, 0, SLJIT_IMM, PCRE2_NOTEMPTY); - JUMPTO(SLJIT_NOT_ZERO, empty_match_backtrack_label); - OP2U(SLJIT_AND | SLJIT_SET_Z, TMP2, 0, SLJIT_IMM, PCRE2_NOTEMPTY_ATSTART); - JUMPTO(SLJIT_ZERO, empty_match_found_label); - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, str)); - CMPTO(SLJIT_NOT_EQUAL, TMP2, 0, STR_PTR, 0, empty_match_found_label); - JUMPTO(SLJIT_JUMP, empty_match_backtrack_label); - } - -common->fast_forward_bc_ptr = NULL; -common->early_fail_start_ptr = 0; -common->early_fail_end_ptr = 0; -common->currententry = common->entries; -common->local_quit_available = TRUE; -quit_label = common->quit_label; -if (common->currententry != NULL) - { - /* A free bit for each private data. */ - common->recurse_bitset_size = ((private_data_size / SSIZE_OF(sw)) + 7) >> 3; - SLJIT_ASSERT(common->recurse_bitset_size > 0); - common->recurse_bitset = (sljit_u8*)SLJIT_MALLOC(common->recurse_bitset_size, allocator_data);; - - if (common->recurse_bitset != NULL) - { - do - { - /* Might add new entries. */ - compile_recurse(common); - if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) - break; - flush_stubs(common); - common->currententry = common->currententry->next; - } - while (common->currententry != NULL); - - SLJIT_FREE(common->recurse_bitset, allocator_data); - } - - if (common->currententry != NULL) - { - /* The common->recurse_bitset has been freed. */ - SLJIT_ASSERT(sljit_get_compiler_error(compiler) || common->recurse_bitset == NULL); - - sljit_free_compiler(compiler); - SLJIT_FREE(common->optimized_cbracket, allocator_data); - SLJIT_FREE(common->private_data_ptrs, allocator_data); - PRIV(jit_free_rodata)(common->read_only_data_head, allocator_data); - return PCRE2_ERROR_NOMEMORY; - } - } -common->local_quit_available = FALSE; -common->quit_label = quit_label; - -/* Allocating stack, returns with PCRE_ERROR_JIT_STACKLIMIT if fails. */ -/* This is a (really) rare case. */ -set_jumps(common->stackalloc, LABEL()); -/* RETURN_ADDR is not a saved register. */ -sljit_emit_fast_enter(compiler, SLJIT_MEM1(SLJIT_SP), LOCALS0); - -SLJIT_ASSERT(TMP1 == SLJIT_R0 && STR_PTR == SLJIT_R1); - -OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS1, STR_PTR, 0); -OP1(SLJIT_MOV, SLJIT_R0, 0, ARGUMENTS, 0); -OP2(SLJIT_SUB, SLJIT_R1, 0, STACK_LIMIT, 0, SLJIT_IMM, STACK_GROWTH_RATE); -OP1(SLJIT_MOV, SLJIT_R0, 0, SLJIT_MEM1(SLJIT_R0), SLJIT_OFFSETOF(jit_arguments, stack)); -OP1(SLJIT_MOV, STACK_LIMIT, 0, TMP2, 0); - -sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_ARGS2(W, W, W), SLJIT_IMM, SLJIT_FUNC_ADDR(sljit_stack_resize)); - -jump = CMP(SLJIT_EQUAL, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0); -OP1(SLJIT_MOV, TMP2, 0, STACK_LIMIT, 0); -OP1(SLJIT_MOV, STACK_LIMIT, 0, SLJIT_RETURN_REG, 0); -OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0); -OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), LOCALS1); -OP_SRC(SLJIT_FAST_RETURN, TMP1, 0); - -/* Allocation failed. */ -JUMPHERE(jump); -/* We break the return address cache here, but this is a really rare case. */ -OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE2_ERROR_JIT_STACKLIMIT); -JUMPTO(SLJIT_JUMP, common->quit_label); - -/* Call limit reached. */ -set_jumps(common->calllimit, LABEL()); -OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE2_ERROR_MATCHLIMIT); -JUMPTO(SLJIT_JUMP, common->quit_label); - -if (common->revertframes != NULL) - { - set_jumps(common->revertframes, LABEL()); - do_revertframes(common); - } -if (common->wordboundary != NULL) - { - set_jumps(common->wordboundary, LABEL()); - check_wordboundary(common); - } -if (common->anynewline != NULL) - { - set_jumps(common->anynewline, LABEL()); - check_anynewline(common); - } -if (common->hspace != NULL) - { - set_jumps(common->hspace, LABEL()); - check_hspace(common); - } -if (common->vspace != NULL) - { - set_jumps(common->vspace, LABEL()); - check_vspace(common); - } -if (common->casefulcmp != NULL) - { - set_jumps(common->casefulcmp, LABEL()); - do_casefulcmp(common); - } -if (common->caselesscmp != NULL) - { - set_jumps(common->caselesscmp, LABEL()); - do_caselesscmp(common); - } -if (common->reset_match != NULL) - { - set_jumps(common->reset_match, LABEL()); - do_reset_match(common, (re->top_bracket + 1) * 2); - CMPTO(SLJIT_GREATER, STR_PTR, 0, TMP1, 0, continue_match_label); - OP1(SLJIT_MOV, STR_PTR, 0, TMP1, 0); - JUMPTO(SLJIT_JUMP, reset_match_label); - } -#ifdef SUPPORT_UNICODE -#if PCRE2_CODE_UNIT_WIDTH == 8 -if (common->utfreadchar != NULL) - { - set_jumps(common->utfreadchar, LABEL()); - do_utfreadchar(common); - } -if (common->utfreadtype8 != NULL) - { - set_jumps(common->utfreadtype8, LABEL()); - do_utfreadtype8(common); - } -if (common->utfpeakcharback != NULL) - { - set_jumps(common->utfpeakcharback, LABEL()); - do_utfpeakcharback(common); - } -#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */ -#if PCRE2_CODE_UNIT_WIDTH == 8 || PCRE2_CODE_UNIT_WIDTH == 16 -if (common->utfreadchar_invalid != NULL) - { - set_jumps(common->utfreadchar_invalid, LABEL()); - do_utfreadchar_invalid(common); - } -if (common->utfreadnewline_invalid != NULL) - { - set_jumps(common->utfreadnewline_invalid, LABEL()); - do_utfreadnewline_invalid(common); - } -if (common->utfmoveback_invalid) - { - set_jumps(common->utfmoveback_invalid, LABEL()); - do_utfmoveback_invalid(common); - } -if (common->utfpeakcharback_invalid) - { - set_jumps(common->utfpeakcharback_invalid, LABEL()); - do_utfpeakcharback_invalid(common); - } -#endif /* PCRE2_CODE_UNIT_WIDTH == 8 || PCRE2_CODE_UNIT_WIDTH == 16 */ -if (common->getucd != NULL) - { - set_jumps(common->getucd, LABEL()); - do_getucd(common); - } -if (common->getucdtype != NULL) - { - set_jumps(common->getucdtype, LABEL()); - do_getucdtype(common); - } -#endif /* SUPPORT_UNICODE */ - -SLJIT_FREE(common->optimized_cbracket, allocator_data); -SLJIT_FREE(common->private_data_ptrs, allocator_data); - -executable_func = sljit_generate_code(compiler); -executable_size = sljit_get_generated_code_size(compiler); -sljit_free_compiler(compiler); - -if (executable_func == NULL) - { - PRIV(jit_free_rodata)(common->read_only_data_head, allocator_data); - return PCRE2_ERROR_NOMEMORY; - } - -/* Reuse the function descriptor if possible. */ -if (re->executable_jit != NULL) - functions = (executable_functions *)re->executable_jit; -else - { - functions = SLJIT_MALLOC(sizeof(executable_functions), allocator_data); - if (functions == NULL) - { - /* This case is highly unlikely since we just recently - freed a lot of memory. Not impossible though. */ - sljit_free_code(executable_func, NULL); - PRIV(jit_free_rodata)(common->read_only_data_head, allocator_data); - return PCRE2_ERROR_NOMEMORY; - } - memset(functions, 0, sizeof(executable_functions)); - functions->top_bracket = re->top_bracket + 1; - functions->limit_match = re->limit_match; - re->executable_jit = functions; - } - -/* Turn mode into an index. */ -if (mode == PCRE2_JIT_COMPLETE) - mode = 0; -else - mode = (mode == PCRE2_JIT_PARTIAL_SOFT) ? 1 : 2; - -SLJIT_ASSERT(mode < JIT_NUMBER_OF_COMPILE_MODES); -functions->executable_funcs[mode] = executable_func; -functions->read_only_data_heads[mode] = common->read_only_data_head; -functions->executable_sizes[mode] = executable_size; -return 0; -} - -#endif - -/************************************************* -* JIT compile a Regular Expression * -*************************************************/ - -/* This function used JIT to convert a previously-compiled pattern into machine -code. - -Arguments: - code a compiled pattern - options JIT option bits - -Returns: 0: success or (*NOJIT) was used - <0: an error code -*/ - -#define PUBLIC_JIT_COMPILE_OPTIONS \ - (PCRE2_JIT_COMPLETE|PCRE2_JIT_PARTIAL_SOFT|PCRE2_JIT_PARTIAL_HARD|PCRE2_JIT_INVALID_UTF) - -PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION -pcre2_jit_compile(pcre2_code *code, uint32_t options) -{ -pcre2_real_code *re = (pcre2_real_code *)code; -#ifdef SUPPORT_JIT -executable_functions *functions; -static int executable_allocator_is_working = -1; -#endif - -if (code == NULL) - return PCRE2_ERROR_NULL; - -if ((options & ~PUBLIC_JIT_COMPILE_OPTIONS) != 0) - return PCRE2_ERROR_JIT_BADOPTION; - -/* Support for invalid UTF was first introduced in JIT, with the option -PCRE2_JIT_INVALID_UTF. Later, support was added to the interpreter, and the -compile-time option PCRE2_MATCH_INVALID_UTF was created. This is now the -preferred feature, with the earlier option deprecated. However, for backward -compatibility, if the earlier option is set, it forces the new option so that -if JIT matching falls back to the interpreter, there is still support for -invalid UTF. However, if this function has already been successfully called -without PCRE2_JIT_INVALID_UTF and without PCRE2_MATCH_INVALID_UTF (meaning that -non-invalid-supporting JIT code was compiled), give an error. - -If in the future support for PCRE2_JIT_INVALID_UTF is withdrawn, the following -actions are needed: - - 1. Remove the definition from pcre2.h.in and from the list in - PUBLIC_JIT_COMPILE_OPTIONS above. - - 2. Replace PCRE2_JIT_INVALID_UTF with a local flag in this module. - - 3. Replace PCRE2_JIT_INVALID_UTF in pcre2_jit_test.c. - - 4. Delete the following short block of code. The setting of "re" and - "functions" can be moved into the JIT-only block below, but if that is - done, (void)re and (void)functions will be needed in the non-JIT case, to - avoid compiler warnings. -*/ - -#ifdef SUPPORT_JIT -functions = (executable_functions *)re->executable_jit; -#endif - -if ((options & PCRE2_JIT_INVALID_UTF) != 0) - { - if ((re->overall_options & PCRE2_MATCH_INVALID_UTF) == 0) - { -#ifdef SUPPORT_JIT - if (functions != NULL) return PCRE2_ERROR_JIT_BADOPTION; -#endif - re->overall_options |= PCRE2_MATCH_INVALID_UTF; - } - } - -/* The above tests are run with and without JIT support. This means that -PCRE2_JIT_INVALID_UTF propagates back into the regex options (ensuring -interpreter support) even in the absence of JIT. But now, if there is no JIT -support, give an error return. */ - -#ifndef SUPPORT_JIT -return PCRE2_ERROR_JIT_BADOPTION; -#else /* SUPPORT_JIT */ - -/* There is JIT support. Do the necessary. */ - -if ((re->flags & PCRE2_NOJIT) != 0) return 0; - -if (executable_allocator_is_working == -1) - { - /* Checks whether the executable allocator is working. This check - might run multiple times in multi-threaded environments, but the - result should not be affected by it. */ - void *ptr = SLJIT_MALLOC_EXEC(32, NULL); - if (ptr != NULL) - { - SLJIT_FREE_EXEC(((sljit_u8*)(ptr)) + SLJIT_EXEC_OFFSET(ptr), NULL); - executable_allocator_is_working = 1; - } - else executable_allocator_is_working = 0; - } - -if (!executable_allocator_is_working) - return PCRE2_ERROR_NOMEMORY; - -if ((re->overall_options & PCRE2_MATCH_INVALID_UTF) != 0) - options |= PCRE2_JIT_INVALID_UTF; - -if ((options & PCRE2_JIT_COMPLETE) != 0 && (functions == NULL - || functions->executable_funcs[0] == NULL)) { - uint32_t excluded_options = (PCRE2_JIT_PARTIAL_SOFT | PCRE2_JIT_PARTIAL_HARD); - int result = jit_compile(code, options & ~excluded_options); - if (result != 0) - return result; - } - -if ((options & PCRE2_JIT_PARTIAL_SOFT) != 0 && (functions == NULL - || functions->executable_funcs[1] == NULL)) { - uint32_t excluded_options = (PCRE2_JIT_COMPLETE | PCRE2_JIT_PARTIAL_HARD); - int result = jit_compile(code, options & ~excluded_options); - if (result != 0) - return result; - } - -if ((options & PCRE2_JIT_PARTIAL_HARD) != 0 && (functions == NULL - || functions->executable_funcs[2] == NULL)) { - uint32_t excluded_options = (PCRE2_JIT_COMPLETE | PCRE2_JIT_PARTIAL_SOFT); - int result = jit_compile(code, options & ~excluded_options); - if (result != 0) - return result; - } - -return 0; - -#endif /* SUPPORT_JIT */ -} - -/* JIT compiler uses an all-in-one approach. This improves security, - since the code generator functions are not exported. */ - -#define INCLUDED_FROM_PCRE2_JIT_COMPILE - -#include "pcre2_jit_match.c" -#include "pcre2_jit_misc.c" - -/* End of pcre2_jit_compile.c */ diff --git a/modules/regex/pcre2/src/pcre2_jit_match.c b/modules/regex/pcre2/src/pcre2_jit_match.c deleted file mode 100644 index 1ab3af0..0000000 --- a/modules/regex/pcre2/src/pcre2_jit_match.c +++ /dev/null @@ -1,186 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -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-2018 University of Cambridge - ------------------------------------------------------------------------------ -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 OWNER 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. ------------------------------------------------------------------------------ -*/ - -#ifndef INCLUDED_FROM_PCRE2_JIT_COMPILE -#error This file must be included from pcre2_jit_compile.c. -#endif - -#ifdef SUPPORT_JIT - -static SLJIT_NOINLINE int jit_machine_stack_exec(jit_arguments *arguments, jit_function executable_func) -{ -sljit_u8 local_space[MACHINE_STACK_SIZE]; -struct sljit_stack local_stack; - -local_stack.min_start = local_space; -local_stack.start = local_space; -local_stack.end = local_space + MACHINE_STACK_SIZE; -local_stack.top = local_space + MACHINE_STACK_SIZE; -arguments->stack = &local_stack; -return executable_func(arguments); -} - -#endif - - -/************************************************* -* Do a JIT pattern match * -*************************************************/ - -/* This function runs a JIT pattern match. - -Arguments: - code points to the compiled expression - subject points to the subject string - length length of subject string (may contain binary zeros) - start_offset where to start in the subject string - options option bits - match_data points to a match_data block - mcontext points to a match context - -Returns: > 0 => success; value is the number of ovector pairs filled - = 0 => success, but ovector is not big enough - -1 => failed to match (PCRE_ERROR_NOMATCH) - < -1 => some kind of unexpected problem -*/ - -PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION -pcre2_jit_match(const pcre2_code *code, PCRE2_SPTR subject, PCRE2_SIZE length, - PCRE2_SIZE start_offset, uint32_t options, pcre2_match_data *match_data, - pcre2_match_context *mcontext) -{ -#ifndef SUPPORT_JIT - -(void)code; -(void)subject; -(void)length; -(void)start_offset; -(void)options; -(void)match_data; -(void)mcontext; -return PCRE2_ERROR_JIT_BADOPTION; - -#else /* SUPPORT_JIT */ - -pcre2_real_code *re = (pcre2_real_code *)code; -executable_functions *functions = (executable_functions *)re->executable_jit; -pcre2_jit_stack *jit_stack; -uint32_t oveccount = match_data->oveccount; -uint32_t max_oveccount; -union { - void *executable_func; - jit_function call_executable_func; -} convert_executable_func; -jit_arguments arguments; -int rc; -int index = 0; - -if ((options & PCRE2_PARTIAL_HARD) != 0) - index = 2; -else if ((options & PCRE2_PARTIAL_SOFT) != 0) - index = 1; - -if (functions == NULL || functions->executable_funcs[index] == NULL) - return PCRE2_ERROR_JIT_BADOPTION; - -/* Sanity checks should be handled by pcre2_match. */ -arguments.str = subject + start_offset; -arguments.begin = subject; -arguments.end = subject + length; -arguments.match_data = match_data; -arguments.startchar_ptr = subject; -arguments.mark_ptr = NULL; -arguments.options = options; - -if (mcontext != NULL) - { - arguments.callout = mcontext->callout; - arguments.callout_data = mcontext->callout_data; - arguments.offset_limit = mcontext->offset_limit; - arguments.limit_match = (mcontext->match_limit < re->limit_match)? - mcontext->match_limit : re->limit_match; - if (mcontext->jit_callback != NULL) - jit_stack = mcontext->jit_callback(mcontext->jit_callback_data); - else - jit_stack = (pcre2_jit_stack *)mcontext->jit_callback_data; - } -else - { - arguments.callout = NULL; - arguments.callout_data = NULL; - arguments.offset_limit = PCRE2_UNSET; - arguments.limit_match = (MATCH_LIMIT < re->limit_match)? - MATCH_LIMIT : re->limit_match; - jit_stack = NULL; - } - - -max_oveccount = functions->top_bracket; -if (oveccount > max_oveccount) - oveccount = max_oveccount; -arguments.oveccount = oveccount << 1; - - -convert_executable_func.executable_func = functions->executable_funcs[index]; -if (jit_stack != NULL) - { - arguments.stack = (struct sljit_stack *)(jit_stack->stack); - rc = convert_executable_func.call_executable_func(&arguments); - } -else - rc = jit_machine_stack_exec(&arguments, convert_executable_func.call_executable_func); - -if (rc > (int)oveccount) - rc = 0; -match_data->code = re; -match_data->subject = (rc >= 0 || rc == PCRE2_ERROR_PARTIAL)? subject : NULL; -match_data->rc = rc; -match_data->startchar = arguments.startchar_ptr - subject; -match_data->leftchar = 0; -match_data->rightchar = 0; -match_data->mark = arguments.mark_ptr; -match_data->matchedby = PCRE2_MATCHEDBY_JIT; - -return match_data->rc; - -#endif /* SUPPORT_JIT */ -} - -/* End of pcre2_jit_match.c */ diff --git a/modules/regex/pcre2/src/pcre2_jit_misc.c b/modules/regex/pcre2/src/pcre2_jit_misc.c deleted file mode 100644 index bb6a558..0000000 --- a/modules/regex/pcre2/src/pcre2_jit_misc.c +++ /dev/null @@ -1,234 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -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 University of Cambridge - ------------------------------------------------------------------------------ -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 OWNER 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. ------------------------------------------------------------------------------ -*/ - - -#ifndef INCLUDED_FROM_PCRE2_JIT_COMPILE -#error This file must be included from pcre2_jit_compile.c. -#endif - - - -/************************************************* -* Free JIT read-only data * -*************************************************/ - -void -PRIV(jit_free_rodata)(void *current, void *allocator_data) -{ -#ifndef SUPPORT_JIT -(void)current; -(void)allocator_data; -#else /* SUPPORT_JIT */ -void *next; - -SLJIT_UNUSED_ARG(allocator_data); - -while (current != NULL) - { - next = *(void**)current; - SLJIT_FREE(current, allocator_data); - current = next; - } - -#endif /* SUPPORT_JIT */ -} - -/************************************************* -* Free JIT compiled code * -*************************************************/ - -void -PRIV(jit_free)(void *executable_jit, pcre2_memctl *memctl) -{ -#ifndef SUPPORT_JIT -(void)executable_jit; -(void)memctl; -#else /* SUPPORT_JIT */ - -executable_functions *functions = (executable_functions *)executable_jit; -void *allocator_data = memctl; -int i; - -for (i = 0; i < JIT_NUMBER_OF_COMPILE_MODES; i++) - { - if (functions->executable_funcs[i] != NULL) - sljit_free_code(functions->executable_funcs[i], NULL); - PRIV(jit_free_rodata)(functions->read_only_data_heads[i], allocator_data); - } - -SLJIT_FREE(functions, allocator_data); - -#endif /* SUPPORT_JIT */ -} - - -/************************************************* -* Free unused JIT memory * -*************************************************/ - -PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION -pcre2_jit_free_unused_memory(pcre2_general_context *gcontext) -{ -#ifndef SUPPORT_JIT -(void)gcontext; /* Suppress warning */ -#else /* SUPPORT_JIT */ -SLJIT_UNUSED_ARG(gcontext); -#if (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR) -sljit_free_unused_memory_exec(); -#endif /* SLJIT_EXECUTABLE_ALLOCATOR */ -#endif /* SUPPORT_JIT */ -} - - - -/************************************************* -* Allocate a JIT stack * -*************************************************/ - -PCRE2_EXP_DEFN pcre2_jit_stack * PCRE2_CALL_CONVENTION -pcre2_jit_stack_create(size_t startsize, size_t maxsize, - pcre2_general_context *gcontext) -{ -#ifndef SUPPORT_JIT - -(void)gcontext; -(void)startsize; -(void)maxsize; -return NULL; - -#else /* SUPPORT_JIT */ - -pcre2_jit_stack *jit_stack; - -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); - -jit_stack = PRIV(memctl_malloc)(sizeof(pcre2_real_jit_stack), (pcre2_memctl *)gcontext); -if (jit_stack == NULL) return NULL; -jit_stack->stack = sljit_allocate_stack(startsize, maxsize, &jit_stack->memctl); -if (jit_stack->stack == NULL) - { - jit_stack->memctl.free(jit_stack, jit_stack->memctl.memory_data); - return NULL; - } -return jit_stack; - -#endif -} - - -/************************************************* -* Assign a JIT stack to a pattern * -*************************************************/ - -PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION -pcre2_jit_stack_assign(pcre2_match_context *mcontext, pcre2_jit_callback callback, - void *callback_data) -{ -#ifndef SUPPORT_JIT -(void)mcontext; -(void)callback; -(void)callback_data; -#else /* SUPPORT_JIT */ - -if (mcontext == NULL) return; -mcontext->jit_callback = callback; -mcontext->jit_callback_data = callback_data; - -#endif /* SUPPORT_JIT */ -} - - -/************************************************* -* Free a JIT stack * -*************************************************/ - -PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION -pcre2_jit_stack_free(pcre2_jit_stack *jit_stack) -{ -#ifndef SUPPORT_JIT -(void)jit_stack; -#else /* SUPPORT_JIT */ -if (jit_stack != NULL) - { - sljit_free_stack((struct sljit_stack *)(jit_stack->stack), &jit_stack->memctl); - jit_stack->memctl.free(jit_stack, jit_stack->memctl.memory_data); - } -#endif /* SUPPORT_JIT */ -} - - -/************************************************* -* Get target CPU type * -*************************************************/ - -const char* -PRIV(jit_get_target)(void) -{ -#ifndef SUPPORT_JIT -return "JIT is not supported"; -#else /* SUPPORT_JIT */ -return sljit_get_platform_name(); -#endif /* SUPPORT_JIT */ -} - - -/************************************************* -* Get size of JIT code * -*************************************************/ - -size_t -PRIV(jit_get_size)(void *executable_jit) -{ -#ifndef SUPPORT_JIT -(void)executable_jit; -return 0; -#else /* SUPPORT_JIT */ -sljit_uw *executable_sizes = ((executable_functions *)executable_jit)->executable_sizes; -SLJIT_COMPILE_ASSERT(JIT_NUMBER_OF_COMPILE_MODES == 3, number_of_compile_modes_changed); -return executable_sizes[0] + executable_sizes[1] + executable_sizes[2]; -#endif -} - -/* End of pcre2_jit_misc.c */ diff --git a/modules/regex/pcre2/src/pcre2_jit_neon_inc.h b/modules/regex/pcre2/src/pcre2_jit_neon_inc.h deleted file mode 100644 index 165602e..0000000 --- a/modules/regex/pcre2/src/pcre2_jit_neon_inc.h +++ /dev/null @@ -1,349 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -and semantics are as close as possible to those of the Perl 5 language. - - Written by Philip Hazel - This module by Zoltan Herczeg and Sebastian Pop - Original API code Copyright (c) 1997-2012 University of Cambridge - New API code Copyright (c) 2016-2019 University of Cambridge - ------------------------------------------------------------------------------ -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 OWNER 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. ------------------------------------------------------------------------------ -*/ - -# if defined(FFCS) -# if defined(FF_UTF) -# define FF_FUN ffcs_utf -# else -# define FF_FUN ffcs -# endif - -# elif defined(FFCS_2) -# if defined(FF_UTF) -# define FF_FUN ffcs_2_utf -# else -# define FF_FUN ffcs_2 -# endif - -# elif defined(FFCS_MASK) -# if defined(FF_UTF) -# define FF_FUN ffcs_mask_utf -# else -# define FF_FUN ffcs_mask -# endif - -# elif defined(FFCPS_0) -# if defined (FF_UTF) -# define FF_FUN ffcps_0_utf -# else -# define FF_FUN ffcps_0 -# endif - -# elif defined (FFCPS_1) -# if defined (FF_UTF) -# define FF_FUN ffcps_1_utf -# else -# define FF_FUN ffcps_1 -# endif - -# elif defined (FFCPS_DEFAULT) -# if defined (FF_UTF) -# define FF_FUN ffcps_default_utf -# else -# define FF_FUN ffcps_default -# endif -# endif - -static sljit_u8* SLJIT_FUNC FF_FUN(sljit_u8 *str_end, sljit_u8 *str_ptr, sljit_uw offs1, sljit_uw offs2, sljit_uw chars) -#undef FF_FUN -{ -quad_word qw; -int_char ic; - -SLJIT_UNUSED_ARG(offs1); -SLJIT_UNUSED_ARG(offs2); - -ic.x = chars; - -#if defined(FFCS) -sljit_u8 c1 = ic.c.c1; -vect_t vc1 = VDUPQ(c1); - -#elif defined(FFCS_2) -sljit_u8 c1 = ic.c.c1; -vect_t vc1 = VDUPQ(c1); -sljit_u8 c2 = ic.c.c2; -vect_t vc2 = VDUPQ(c2); - -#elif defined(FFCS_MASK) -sljit_u8 c1 = ic.c.c1; -vect_t vc1 = VDUPQ(c1); -sljit_u8 mask = ic.c.c2; -vect_t vmask = VDUPQ(mask); -#endif - -#if defined(FFCPS) -compare_type compare1_type = compare_match1; -compare_type compare2_type = compare_match1; -vect_t cmp1a, cmp1b, cmp2a, cmp2b; -const sljit_u32 diff = IN_UCHARS(offs1 - offs2); -PCRE2_UCHAR char1a = ic.c.c1; -PCRE2_UCHAR char2a = ic.c.c3; - -# ifdef FFCPS_CHAR1A2A -cmp1a = VDUPQ(char1a); -cmp2a = VDUPQ(char2a); -cmp1b = VDUPQ(0); /* to avoid errors on older compilers -Werror=maybe-uninitialized */ -cmp2b = VDUPQ(0); /* to avoid errors on older compilers -Werror=maybe-uninitialized */ -# else -PCRE2_UCHAR char1b = ic.c.c2; -PCRE2_UCHAR char2b = ic.c.c4; -if (char1a == char1b) - { - cmp1a = VDUPQ(char1a); - cmp1b = VDUPQ(0); /* to avoid errors on older compilers -Werror=maybe-uninitialized */ - } -else - { - sljit_u32 bit1 = char1a ^ char1b; - if (is_powerof2(bit1)) - { - compare1_type = compare_match1i; - cmp1a = VDUPQ(char1a | bit1); - cmp1b = VDUPQ(bit1); - } - else - { - compare1_type = compare_match2; - cmp1a = VDUPQ(char1a); - cmp1b = VDUPQ(char1b); - } - } - -if (char2a == char2b) - { - cmp2a = VDUPQ(char2a); - cmp2b = VDUPQ(0); /* to avoid errors on older compilers -Werror=maybe-uninitialized */ - } -else - { - sljit_u32 bit2 = char2a ^ char2b; - if (is_powerof2(bit2)) - { - compare2_type = compare_match1i; - cmp2a = VDUPQ(char2a | bit2); - cmp2b = VDUPQ(bit2); - } - else - { - compare2_type = compare_match2; - cmp2a = VDUPQ(char2a); - cmp2b = VDUPQ(char2b); - } - } -# endif - -str_ptr += IN_UCHARS(offs1); -#endif - -#if PCRE2_CODE_UNIT_WIDTH != 8 -vect_t char_mask = VDUPQ(0xff); -#endif - -#if defined(FF_UTF) -restart:; -#endif - -#if defined(FFCPS) -if (str_ptr >= str_end) - return NULL; -sljit_u8 *p1 = str_ptr - diff; -#endif -sljit_s32 align_offset = ((uint64_t)str_ptr & 0xf); -str_ptr = (sljit_u8 *) ((uint64_t)str_ptr & ~0xf); -vect_t data = VLD1Q(str_ptr); -#if PCRE2_CODE_UNIT_WIDTH != 8 -data = VANDQ(data, char_mask); -#endif - -#if defined(FFCS) -vect_t eq = VCEQQ(data, vc1); - -#elif defined(FFCS_2) -vect_t eq1 = VCEQQ(data, vc1); -vect_t eq2 = VCEQQ(data, vc2); -vect_t eq = VORRQ(eq1, eq2); - -#elif defined(FFCS_MASK) -vect_t eq = VORRQ(data, vmask); -eq = VCEQQ(eq, vc1); - -#elif defined(FFCPS) -# if defined(FFCPS_DIFF1) -vect_t prev_data = data; -# endif - -vect_t data2; -if (p1 < str_ptr) - { - data2 = VLD1Q(str_ptr - diff); -#if PCRE2_CODE_UNIT_WIDTH != 8 - data2 = VANDQ(data2, char_mask); -#endif - } -else - data2 = shift_left_n_lanes(data, offs1 - offs2); - -if (compare1_type == compare_match1) - data = VCEQQ(data, cmp1a); -else - data = fast_forward_char_pair_compare(compare1_type, data, cmp1a, cmp1b); - -if (compare2_type == compare_match1) - data2 = VCEQQ(data2, cmp2a); -else - data2 = fast_forward_char_pair_compare(compare2_type, data2, cmp2a, cmp2b); - -vect_t eq = VANDQ(data, data2); -#endif - -VST1Q(qw.mem, eq); -/* Ignore matches before the first STR_PTR. */ -if (align_offset < 8) - { - qw.dw[0] >>= align_offset * 8; - if (qw.dw[0]) - { - str_ptr += align_offset + __builtin_ctzll(qw.dw[0]) / 8; - goto match; - } - if (qw.dw[1]) - { - str_ptr += 8 + __builtin_ctzll(qw.dw[1]) / 8; - goto match; - } - } -else - { - qw.dw[1] >>= (align_offset - 8) * 8; - if (qw.dw[1]) - { - str_ptr += align_offset + __builtin_ctzll(qw.dw[1]) / 8; - goto match; - } - } -str_ptr += 16; - -while (str_ptr < str_end) - { - vect_t orig_data = VLD1Q(str_ptr); -#if PCRE2_CODE_UNIT_WIDTH != 8 - orig_data = VANDQ(orig_data, char_mask); -#endif - data = orig_data; - -#if defined(FFCS) - eq = VCEQQ(data, vc1); - -#elif defined(FFCS_2) - eq1 = VCEQQ(data, vc1); - eq2 = VCEQQ(data, vc2); - eq = VORRQ(eq1, eq2); - -#elif defined(FFCS_MASK) - eq = VORRQ(data, vmask); - eq = VCEQQ(eq, vc1); -#endif - -#if defined(FFCPS) -# if defined (FFCPS_DIFF1) - data2 = VEXTQ(prev_data, data, VECTOR_FACTOR - 1); -# else - data2 = VLD1Q(str_ptr - diff); -# if PCRE2_CODE_UNIT_WIDTH != 8 - data2 = VANDQ(data2, char_mask); -# endif -# endif - -# ifdef FFCPS_CHAR1A2A - data = VCEQQ(data, cmp1a); - data2 = VCEQQ(data2, cmp2a); -# else - if (compare1_type == compare_match1) - data = VCEQQ(data, cmp1a); - else - data = fast_forward_char_pair_compare(compare1_type, data, cmp1a, cmp1b); - if (compare2_type == compare_match1) - data2 = VCEQQ(data2, cmp2a); - else - data2 = fast_forward_char_pair_compare(compare2_type, data2, cmp2a, cmp2b); -# endif - - eq = VANDQ(data, data2); -#endif - - VST1Q(qw.mem, eq); - if (qw.dw[0]) - str_ptr += __builtin_ctzll(qw.dw[0]) / 8; - else if (qw.dw[1]) - str_ptr += 8 + __builtin_ctzll(qw.dw[1]) / 8; - else { - str_ptr += 16; -#if defined (FFCPS_DIFF1) - prev_data = orig_data; -#endif - continue; - } - -match:; - if (str_ptr >= str_end) - /* Failed match. */ - return NULL; - -#if defined(FF_UTF) - if (utf_continue((PCRE2_SPTR)str_ptr - offs1)) - { - /* Not a match. */ - str_ptr += IN_UCHARS(1); - goto restart; - } -#endif - - /* Match. */ -#if defined (FFCPS) - str_ptr -= IN_UCHARS(offs1); -#endif - return str_ptr; - } - -/* Failed match. */ -return NULL; -} diff --git a/modules/regex/pcre2/src/pcre2_jit_simd_inc.h b/modules/regex/pcre2/src/pcre2_jit_simd_inc.h deleted file mode 100644 index 1a5ce4e..0000000 --- a/modules/regex/pcre2/src/pcre2_jit_simd_inc.h +++ /dev/null @@ -1,1858 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -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-2019 University of Cambridge - ------------------------------------------------------------------------------ -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 OWNER 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. ------------------------------------------------------------------------------ -*/ - -#if !(defined SUPPORT_VALGRIND) - -#if ((defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) \ - || (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X)) - -typedef enum { - vector_compare_match1, - vector_compare_match1i, - vector_compare_match2, -} vector_compare_type; - -static SLJIT_INLINE sljit_u32 max_fast_forward_char_pair_offset(void) -{ -#if PCRE2_CODE_UNIT_WIDTH == 8 -return 15; -#elif PCRE2_CODE_UNIT_WIDTH == 16 -return 7; -#elif PCRE2_CODE_UNIT_WIDTH == 32 -return 3; -#else -#error "Unsupported unit width" -#endif -} - -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 -static struct sljit_jump *jump_if_utf_char_start(struct sljit_compiler *compiler, sljit_s32 reg) -{ -#if PCRE2_CODE_UNIT_WIDTH == 8 -OP2(SLJIT_AND, reg, 0, reg, 0, SLJIT_IMM, 0xc0); -return CMP(SLJIT_NOT_EQUAL, reg, 0, SLJIT_IMM, 0x80); -#elif PCRE2_CODE_UNIT_WIDTH == 16 -OP2(SLJIT_AND, reg, 0, reg, 0, SLJIT_IMM, 0xfc00); -return CMP(SLJIT_NOT_EQUAL, reg, 0, SLJIT_IMM, 0xdc00); -#else -#error "Unknown code width" -#endif -} -#endif - -#endif /* SLJIT_CONFIG_X86 || SLJIT_CONFIG_S390X */ - -#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) - -static sljit_s32 character_to_int32(PCRE2_UCHAR chr) -{ -sljit_u32 value = chr; -#if PCRE2_CODE_UNIT_WIDTH == 8 -#define SSE2_COMPARE_TYPE_INDEX 0 -return (sljit_s32)((value << 24) | (value << 16) | (value << 8) | value); -#elif PCRE2_CODE_UNIT_WIDTH == 16 -#define SSE2_COMPARE_TYPE_INDEX 1 -return (sljit_s32)((value << 16) | value); -#elif PCRE2_CODE_UNIT_WIDTH == 32 -#define SSE2_COMPARE_TYPE_INDEX 2 -return (sljit_s32)(value); -#else -#error "Unsupported unit width" -#endif -} - -static void load_from_mem_sse2(struct sljit_compiler *compiler, sljit_s32 dst_xmm_reg, sljit_s32 src_general_reg, sljit_s8 offset) -{ -sljit_u8 instruction[5]; - -SLJIT_ASSERT(dst_xmm_reg < 8); -SLJIT_ASSERT(src_general_reg < 8); - -/* MOVDQA xmm1, xmm2/m128 */ -instruction[0] = ((sljit_u8)offset & 0xf) == 0 ? 0x66 : 0xf3; -instruction[1] = 0x0f; -instruction[2] = 0x6f; - -if (offset == 0) - { - instruction[3] = (dst_xmm_reg << 3) | src_general_reg; - sljit_emit_op_custom(compiler, instruction, 4); - return; - } - -instruction[3] = 0x40 | (dst_xmm_reg << 3) | src_general_reg; -instruction[4] = (sljit_u8)offset; -sljit_emit_op_custom(compiler, instruction, 5); -} - -static void fast_forward_char_pair_sse2_compare(struct sljit_compiler *compiler, vector_compare_type compare_type, - int step, sljit_s32 dst_ind, sljit_s32 cmp1_ind, sljit_s32 cmp2_ind, sljit_s32 tmp_ind) -{ -sljit_u8 instruction[4]; -instruction[0] = 0x66; -instruction[1] = 0x0f; - -SLJIT_ASSERT(step >= 0 && step <= 3); - -if (compare_type != vector_compare_match2) - { - if (step == 0) - { - if (compare_type == vector_compare_match1i) - { - /* POR xmm1, xmm2/m128 */ - /* instruction[0] = 0x66; */ - /* instruction[1] = 0x0f; */ - instruction[2] = 0xeb; - instruction[3] = 0xc0 | (dst_ind << 3) | cmp2_ind; - sljit_emit_op_custom(compiler, instruction, 4); - } - return; - } - - if (step != 2) - return; - - /* PCMPEQB/W/D xmm1, xmm2/m128 */ - /* instruction[0] = 0x66; */ - /* instruction[1] = 0x0f; */ - instruction[2] = 0x74 + SSE2_COMPARE_TYPE_INDEX; - instruction[3] = 0xc0 | (dst_ind << 3) | cmp1_ind; - sljit_emit_op_custom(compiler, instruction, 4); - return; - } - -switch (step) - { - case 0: - /* MOVDQA xmm1, xmm2/m128 */ - /* instruction[0] = 0x66; */ - /* instruction[1] = 0x0f; */ - instruction[2] = 0x6f; - instruction[3] = 0xc0 | (tmp_ind << 3) | dst_ind; - sljit_emit_op_custom(compiler, instruction, 4); - return; - - case 1: - /* PCMPEQB/W/D xmm1, xmm2/m128 */ - /* instruction[0] = 0x66; */ - /* instruction[1] = 0x0f; */ - instruction[2] = 0x74 + SSE2_COMPARE_TYPE_INDEX; - instruction[3] = 0xc0 | (dst_ind << 3) | cmp1_ind; - sljit_emit_op_custom(compiler, instruction, 4); - return; - - case 2: - /* PCMPEQB/W/D xmm1, xmm2/m128 */ - /* instruction[0] = 0x66; */ - /* instruction[1] = 0x0f; */ - instruction[2] = 0x74 + SSE2_COMPARE_TYPE_INDEX; - instruction[3] = 0xc0 | (tmp_ind << 3) | cmp2_ind; - sljit_emit_op_custom(compiler, instruction, 4); - return; - - case 3: - /* POR xmm1, xmm2/m128 */ - /* instruction[0] = 0x66; */ - /* instruction[1] = 0x0f; */ - instruction[2] = 0xeb; - instruction[3] = 0xc0 | (dst_ind << 3) | tmp_ind; - sljit_emit_op_custom(compiler, instruction, 4); - return; - } -} - -#define JIT_HAS_FAST_FORWARD_CHAR_SIMD (sljit_has_cpu_feature(SLJIT_HAS_SSE2)) - -static void fast_forward_char_simd(compiler_common *common, PCRE2_UCHAR char1, PCRE2_UCHAR char2, sljit_s32 offset) -{ -DEFINE_COMPILER; -sljit_u8 instruction[8]; -struct sljit_label *start; -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 -struct sljit_label *restart; -#endif -struct sljit_jump *quit; -struct sljit_jump *partial_quit[2]; -vector_compare_type compare_type = vector_compare_match1; -sljit_s32 tmp1_reg_ind = sljit_get_register_index(TMP1); -sljit_s32 str_ptr_reg_ind = sljit_get_register_index(STR_PTR); -sljit_s32 data_ind = 0; -sljit_s32 tmp_ind = 1; -sljit_s32 cmp1_ind = 2; -sljit_s32 cmp2_ind = 3; -sljit_u32 bit = 0; -int i; - -SLJIT_UNUSED_ARG(offset); - -if (char1 != char2) - { - bit = char1 ^ char2; - compare_type = vector_compare_match1i; - - if (!is_powerof2(bit)) - { - bit = 0; - compare_type = vector_compare_match2; - } - } - -partial_quit[0] = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); -if (common->mode == PCRE2_JIT_COMPLETE) - add_jump(compiler, &common->failed_match, partial_quit[0]); - -/* First part (unaligned start) */ - -OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char1 | bit)); - -SLJIT_ASSERT(tmp1_reg_ind < 8); - -/* MOVD xmm, r/m32 */ -instruction[0] = 0x66; -instruction[1] = 0x0f; -instruction[2] = 0x6e; -instruction[3] = 0xc0 | (cmp1_ind << 3) | tmp1_reg_ind; -sljit_emit_op_custom(compiler, instruction, 4); - -if (char1 != char2) - { - OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(bit != 0 ? bit : char2)); - - /* MOVD xmm, r/m32 */ - instruction[3] = 0xc0 | (cmp2_ind << 3) | tmp1_reg_ind; - sljit_emit_op_custom(compiler, instruction, 4); - } - -OP1(SLJIT_MOV, TMP2, 0, STR_PTR, 0); - -/* PSHUFD xmm1, xmm2/m128, imm8 */ -/* instruction[0] = 0x66; */ -/* instruction[1] = 0x0f; */ -instruction[2] = 0x70; -instruction[3] = 0xc0 | (cmp1_ind << 3) | cmp1_ind; -instruction[4] = 0; -sljit_emit_op_custom(compiler, instruction, 5); - -if (char1 != char2) - { - /* PSHUFD xmm1, xmm2/m128, imm8 */ - instruction[3] = 0xc0 | (cmp2_ind << 3) | cmp2_ind; - sljit_emit_op_custom(compiler, instruction, 5); - } - -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 -restart = LABEL(); -#endif -OP2(SLJIT_AND, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, ~0xf); -OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xf); - -load_from_mem_sse2(compiler, data_ind, str_ptr_reg_ind, 0); -for (i = 0; i < 4; i++) - fast_forward_char_pair_sse2_compare(compiler, compare_type, i, data_ind, cmp1_ind, cmp2_ind, tmp_ind); - -/* PMOVMSKB reg, xmm */ -/* instruction[0] = 0x66; */ -/* instruction[1] = 0x0f; */ -instruction[2] = 0xd7; -instruction[3] = 0xc0 | (tmp1_reg_ind << 3) | data_ind; -sljit_emit_op_custom(compiler, instruction, 4); - -OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0); -OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, TMP2, 0); - -quit = CMP(SLJIT_NOT_ZERO, TMP1, 0, SLJIT_IMM, 0); - -OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0); - -/* Second part (aligned) */ -start = LABEL(); - -OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 16); - -partial_quit[1] = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); -if (common->mode == PCRE2_JIT_COMPLETE) - add_jump(compiler, &common->failed_match, partial_quit[1]); - -load_from_mem_sse2(compiler, data_ind, str_ptr_reg_ind, 0); -for (i = 0; i < 4; i++) - fast_forward_char_pair_sse2_compare(compiler, compare_type, i, data_ind, cmp1_ind, cmp2_ind, tmp_ind); - -/* PMOVMSKB reg, xmm */ -/* instruction[0] = 0x66; */ -/* instruction[1] = 0x0f; */ -instruction[2] = 0xd7; -instruction[3] = 0xc0 | (tmp1_reg_ind << 3) | data_ind; -sljit_emit_op_custom(compiler, instruction, 4); - -CMPTO(SLJIT_ZERO, TMP1, 0, SLJIT_IMM, 0, start); - -JUMPHERE(quit); - -/* BSF r32, r/m32 */ -instruction[0] = 0x0f; -instruction[1] = 0xbc; -instruction[2] = 0xc0 | (tmp1_reg_ind << 3) | tmp1_reg_ind; -sljit_emit_op_custom(compiler, instruction, 3); - -OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0); - -if (common->mode != PCRE2_JIT_COMPLETE) - { - JUMPHERE(partial_quit[0]); - JUMPHERE(partial_quit[1]); - OP2U(SLJIT_SUB | SLJIT_SET_GREATER, STR_PTR, 0, STR_END, 0); - CMOV(SLJIT_GREATER, STR_PTR, STR_END, 0); - } -else - add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0)); - -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 -if (common->utf && offset > 0) - { - SLJIT_ASSERT(common->mode == PCRE2_JIT_COMPLETE); - - OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-offset)); - - quit = jump_if_utf_char_start(compiler, TMP1); - - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0)); - OP1(SLJIT_MOV, TMP2, 0, STR_PTR, 0); - JUMPTO(SLJIT_JUMP, restart); - - JUMPHERE(quit); - } -#endif -} - -#define JIT_HAS_FAST_REQUESTED_CHAR_SIMD (sljit_has_cpu_feature(SLJIT_HAS_SSE2)) - -static jump_list *fast_requested_char_simd(compiler_common *common, PCRE2_UCHAR char1, PCRE2_UCHAR char2) -{ -DEFINE_COMPILER; -sljit_u8 instruction[8]; -struct sljit_label *start; -struct sljit_jump *quit; -jump_list *not_found = NULL; -vector_compare_type compare_type = vector_compare_match1; -sljit_s32 tmp1_reg_ind = sljit_get_register_index(TMP1); -sljit_s32 str_ptr_reg_ind = sljit_get_register_index(STR_PTR); -sljit_s32 data_ind = 0; -sljit_s32 tmp_ind = 1; -sljit_s32 cmp1_ind = 2; -sljit_s32 cmp2_ind = 3; -sljit_u32 bit = 0; -int i; - -if (char1 != char2) - { - bit = char1 ^ char2; - compare_type = vector_compare_match1i; - - if (!is_powerof2(bit)) - { - bit = 0; - compare_type = vector_compare_match2; - } - } - -add_jump(compiler, ¬_found, CMP(SLJIT_GREATER_EQUAL, TMP1, 0, STR_END, 0)); -OP1(SLJIT_MOV, TMP2, 0, TMP1, 0); -OP1(SLJIT_MOV, TMP3, 0, STR_PTR, 0); - -/* First part (unaligned start) */ - -OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char1 | bit)); - -SLJIT_ASSERT(tmp1_reg_ind < 8); - -/* MOVD xmm, r/m32 */ -instruction[0] = 0x66; -instruction[1] = 0x0f; -instruction[2] = 0x6e; -instruction[3] = 0xc0 | (cmp1_ind << 3) | tmp1_reg_ind; -sljit_emit_op_custom(compiler, instruction, 4); - -if (char1 != char2) - { - OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(bit != 0 ? bit : char2)); - - /* MOVD xmm, r/m32 */ - instruction[3] = 0xc0 | (cmp2_ind << 3) | tmp1_reg_ind; - sljit_emit_op_custom(compiler, instruction, 4); - } - -OP1(SLJIT_MOV, STR_PTR, 0, TMP2, 0); - -/* PSHUFD xmm1, xmm2/m128, imm8 */ -/* instruction[0] = 0x66; */ -/* instruction[1] = 0x0f; */ -instruction[2] = 0x70; -instruction[3] = 0xc0 | (cmp1_ind << 3) | cmp1_ind; -instruction[4] = 0; -sljit_emit_op_custom(compiler, instruction, 5); - -if (char1 != char2) - { - /* PSHUFD xmm1, xmm2/m128, imm8 */ - instruction[3] = 0xc0 | (cmp2_ind << 3) | cmp2_ind; - sljit_emit_op_custom(compiler, instruction, 5); - } - -OP2(SLJIT_AND, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, ~0xf); -OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xf); - -load_from_mem_sse2(compiler, data_ind, str_ptr_reg_ind, 0); -for (i = 0; i < 4; i++) - fast_forward_char_pair_sse2_compare(compiler, compare_type, i, data_ind, cmp1_ind, cmp2_ind, tmp_ind); - -/* PMOVMSKB reg, xmm */ -/* instruction[0] = 0x66; */ -/* instruction[1] = 0x0f; */ -instruction[2] = 0xd7; -instruction[3] = 0xc0 | (tmp1_reg_ind << 3) | data_ind; -sljit_emit_op_custom(compiler, instruction, 4); - -OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0); -OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, TMP2, 0); - -quit = CMP(SLJIT_NOT_ZERO, TMP1, 0, SLJIT_IMM, 0); - -OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0); - -/* Second part (aligned) */ -start = LABEL(); - -OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 16); - -add_jump(compiler, ¬_found, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0)); - -load_from_mem_sse2(compiler, data_ind, str_ptr_reg_ind, 0); -for (i = 0; i < 4; i++) - fast_forward_char_pair_sse2_compare(compiler, compare_type, i, data_ind, cmp1_ind, cmp2_ind, tmp_ind); - -/* PMOVMSKB reg, xmm */ -/* instruction[0] = 0x66; */ -/* instruction[1] = 0x0f; */ -instruction[2] = 0xd7; -instruction[3] = 0xc0 | (tmp1_reg_ind << 3) | data_ind; -sljit_emit_op_custom(compiler, instruction, 4); - -CMPTO(SLJIT_ZERO, TMP1, 0, SLJIT_IMM, 0, start); - -JUMPHERE(quit); - -/* BSF r32, r/m32 */ -instruction[0] = 0x0f; -instruction[1] = 0xbc; -instruction[2] = 0xc0 | (tmp1_reg_ind << 3) | tmp1_reg_ind; -sljit_emit_op_custom(compiler, instruction, 3); - -OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, STR_PTR, 0); -add_jump(compiler, ¬_found, CMP(SLJIT_GREATER_EQUAL, TMP1, 0, STR_END, 0)); - -OP1(SLJIT_MOV, STR_PTR, 0, TMP3, 0); -return not_found; -} - -#ifndef _WIN64 - -#define JIT_HAS_FAST_FORWARD_CHAR_PAIR_SIMD (sljit_has_cpu_feature(SLJIT_HAS_SSE2)) - -static void fast_forward_char_pair_simd(compiler_common *common, sljit_s32 offs1, - PCRE2_UCHAR char1a, PCRE2_UCHAR char1b, sljit_s32 offs2, PCRE2_UCHAR char2a, PCRE2_UCHAR char2b) -{ -DEFINE_COMPILER; -sljit_u8 instruction[8]; -vector_compare_type compare1_type = vector_compare_match1; -vector_compare_type compare2_type = vector_compare_match1; -sljit_u32 bit1 = 0; -sljit_u32 bit2 = 0; -sljit_u32 diff = IN_UCHARS(offs1 - offs2); -sljit_s32 tmp1_reg_ind = sljit_get_register_index(TMP1); -sljit_s32 tmp2_reg_ind = sljit_get_register_index(TMP2); -sljit_s32 str_ptr_reg_ind = sljit_get_register_index(STR_PTR); -sljit_s32 data1_ind = 0; -sljit_s32 data2_ind = 1; -sljit_s32 tmp1_ind = 2; -sljit_s32 tmp2_ind = 3; -sljit_s32 cmp1a_ind = 4; -sljit_s32 cmp1b_ind = 5; -sljit_s32 cmp2a_ind = 6; -sljit_s32 cmp2b_ind = 7; -struct sljit_label *start; -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 -struct sljit_label *restart; -#endif -struct sljit_jump *jump[2]; -int i; - -SLJIT_ASSERT(common->mode == PCRE2_JIT_COMPLETE && offs1 > offs2); -SLJIT_ASSERT(diff <= IN_UCHARS(max_fast_forward_char_pair_offset())); -SLJIT_ASSERT(tmp1_reg_ind < 8 && tmp2_reg_ind == 1); - -/* Initialize. */ -if (common->match_end_ptr != 0) - { - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr); - OP1(SLJIT_MOV, TMP3, 0, STR_END, 0); - OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(offs1 + 1)); - - OP2U(SLJIT_SUB | SLJIT_SET_LESS, TMP1, 0, STR_END, 0); - CMOV(SLJIT_LESS, STR_END, TMP1, 0); - } - -OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(offs1)); -add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0)); - -/* MOVD xmm, r/m32 */ -instruction[0] = 0x66; -instruction[1] = 0x0f; -instruction[2] = 0x6e; - -if (char1a == char1b) - OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char1a)); -else - { - bit1 = char1a ^ char1b; - if (is_powerof2(bit1)) - { - compare1_type = vector_compare_match1i; - OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char1a | bit1)); - OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, character_to_int32(bit1)); - } - else - { - compare1_type = vector_compare_match2; - bit1 = 0; - OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char1a)); - OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, character_to_int32(char1b)); - } - } - -instruction[3] = 0xc0 | (cmp1a_ind << 3) | tmp1_reg_ind; -sljit_emit_op_custom(compiler, instruction, 4); - -if (char1a != char1b) - { - instruction[3] = 0xc0 | (cmp1b_ind << 3) | tmp2_reg_ind; - sljit_emit_op_custom(compiler, instruction, 4); - } - -if (char2a == char2b) - OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char2a)); -else - { - bit2 = char2a ^ char2b; - if (is_powerof2(bit2)) - { - compare2_type = vector_compare_match1i; - OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char2a | bit2)); - OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, character_to_int32(bit2)); - } - else - { - compare2_type = vector_compare_match2; - bit2 = 0; - OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char2a)); - OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, character_to_int32(char2b)); - } - } - -instruction[3] = 0xc0 | (cmp2a_ind << 3) | tmp1_reg_ind; -sljit_emit_op_custom(compiler, instruction, 4); - -if (char2a != char2b) - { - instruction[3] = 0xc0 | (cmp2b_ind << 3) | tmp2_reg_ind; - sljit_emit_op_custom(compiler, instruction, 4); - } - -/* PSHUFD xmm1, xmm2/m128, imm8 */ -/* instruction[0] = 0x66; */ -/* instruction[1] = 0x0f; */ -instruction[2] = 0x70; -instruction[4] = 0; - -instruction[3] = 0xc0 | (cmp1a_ind << 3) | cmp1a_ind; -sljit_emit_op_custom(compiler, instruction, 5); - -if (char1a != char1b) - { - instruction[3] = 0xc0 | (cmp1b_ind << 3) | cmp1b_ind; - sljit_emit_op_custom(compiler, instruction, 5); - } - -instruction[3] = 0xc0 | (cmp2a_ind << 3) | cmp2a_ind; -sljit_emit_op_custom(compiler, instruction, 5); - -if (char2a != char2b) - { - instruction[3] = 0xc0 | (cmp2b_ind << 3) | cmp2b_ind; - sljit_emit_op_custom(compiler, instruction, 5); - } - -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 -restart = LABEL(); -#endif - -OP2(SLJIT_SUB, TMP1, 0, STR_PTR, 0, SLJIT_IMM, diff); -OP1(SLJIT_MOV, TMP2, 0, STR_PTR, 0); -OP2(SLJIT_AND, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, ~0xf); - -load_from_mem_sse2(compiler, data1_ind, str_ptr_reg_ind, 0); - -jump[0] = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, STR_PTR, 0); - -load_from_mem_sse2(compiler, data2_ind, str_ptr_reg_ind, -(sljit_s8)diff); -jump[1] = JUMP(SLJIT_JUMP); - -JUMPHERE(jump[0]); - -/* MOVDQA xmm1, xmm2/m128 */ -/* instruction[0] = 0x66; */ -/* instruction[1] = 0x0f; */ -instruction[2] = 0x6f; -instruction[3] = 0xc0 | (data2_ind << 3) | data1_ind; -sljit_emit_op_custom(compiler, instruction, 4); - -/* PSLLDQ xmm1, imm8 */ -/* instruction[0] = 0x66; */ -/* instruction[1] = 0x0f; */ -instruction[2] = 0x73; -instruction[3] = 0xc0 | (7 << 3) | data2_ind; -instruction[4] = diff; -sljit_emit_op_custom(compiler, instruction, 5); - -JUMPHERE(jump[1]); - -OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xf); - -for (i = 0; i < 4; i++) - { - fast_forward_char_pair_sse2_compare(compiler, compare2_type, i, data2_ind, cmp2a_ind, cmp2b_ind, tmp2_ind); - fast_forward_char_pair_sse2_compare(compiler, compare1_type, i, data1_ind, cmp1a_ind, cmp1b_ind, tmp1_ind); - } - -/* PAND xmm1, xmm2/m128 */ -/* instruction[0] = 0x66; */ -/* instruction[1] = 0x0f; */ -instruction[2] = 0xdb; -instruction[3] = 0xc0 | (data1_ind << 3) | data2_ind; -sljit_emit_op_custom(compiler, instruction, 4); - -/* PMOVMSKB reg, xmm */ -/* instruction[0] = 0x66; */ -/* instruction[1] = 0x0f; */ -instruction[2] = 0xd7; -instruction[3] = 0xc0 | (tmp1_reg_ind << 3) | 0; -sljit_emit_op_custom(compiler, instruction, 4); - -/* Ignore matches before the first STR_PTR. */ -OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0); -OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, TMP2, 0); - -jump[0] = CMP(SLJIT_NOT_ZERO, TMP1, 0, SLJIT_IMM, 0); - -OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0); - -/* Main loop. */ -start = LABEL(); - -OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 16); -add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0)); - -load_from_mem_sse2(compiler, data1_ind, str_ptr_reg_ind, 0); -load_from_mem_sse2(compiler, data2_ind, str_ptr_reg_ind, -(sljit_s8)diff); - -for (i = 0; i < 4; i++) - { - fast_forward_char_pair_sse2_compare(compiler, compare1_type, i, data1_ind, cmp1a_ind, cmp1b_ind, tmp2_ind); - fast_forward_char_pair_sse2_compare(compiler, compare2_type, i, data2_ind, cmp2a_ind, cmp2b_ind, tmp1_ind); - } - -/* PAND xmm1, xmm2/m128 */ -/* instruction[0] = 0x66; */ -/* instruction[1] = 0x0f; */ -instruction[2] = 0xdb; -instruction[3] = 0xc0 | (data1_ind << 3) | data2_ind; -sljit_emit_op_custom(compiler, instruction, 4); - -/* PMOVMSKB reg, xmm */ -/* instruction[0] = 0x66; */ -/* instruction[1] = 0x0f; */ -instruction[2] = 0xd7; -instruction[3] = 0xc0 | (tmp1_reg_ind << 3) | 0; -sljit_emit_op_custom(compiler, instruction, 4); - -CMPTO(SLJIT_ZERO, TMP1, 0, SLJIT_IMM, 0, start); - -JUMPHERE(jump[0]); - -/* BSF r32, r/m32 */ -instruction[0] = 0x0f; -instruction[1] = 0xbc; -instruction[2] = 0xc0 | (tmp1_reg_ind << 3) | tmp1_reg_ind; -sljit_emit_op_custom(compiler, instruction, 3); - -OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0); - -add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0)); - -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 -if (common->utf) - { - OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-offs1)); - - jump[0] = jump_if_utf_char_start(compiler, TMP1); - - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - CMPTO(SLJIT_LESS, STR_PTR, 0, STR_END, 0, restart); - - add_jump(compiler, &common->failed_match, JUMP(SLJIT_JUMP)); - - JUMPHERE(jump[0]); - } -#endif - -OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(offs1)); - -if (common->match_end_ptr != 0) - OP1(SLJIT_MOV, STR_END, 0, TMP3, 0); -} - -#endif /* !_WIN64 */ - -#undef SSE2_COMPARE_TYPE_INDEX - -#endif /* SLJIT_CONFIG_X86 */ - -#if (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64 && (defined __ARM_NEON || defined __ARM_NEON__)) - -#include - -typedef union { - unsigned int x; - struct { unsigned char c1, c2, c3, c4; } c; -} int_char; - -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 -static SLJIT_INLINE int utf_continue(PCRE2_SPTR s) -{ -#if PCRE2_CODE_UNIT_WIDTH == 8 -return (*s & 0xc0) == 0x80; -#elif PCRE2_CODE_UNIT_WIDTH == 16 -return (*s & 0xfc00) == 0xdc00; -#else -#error "Unknown code width" -#endif -} -#endif /* SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 */ - -#if PCRE2_CODE_UNIT_WIDTH == 8 -# define VECTOR_FACTOR 16 -# define vect_t uint8x16_t -# define VLD1Q(X) vld1q_u8((sljit_u8 *)(X)) -# define VCEQQ vceqq_u8 -# define VORRQ vorrq_u8 -# define VST1Q vst1q_u8 -# define VDUPQ vdupq_n_u8 -# define VEXTQ vextq_u8 -# define VANDQ vandq_u8 -typedef union { - uint8_t mem[16]; - uint64_t dw[2]; -} quad_word; -#elif PCRE2_CODE_UNIT_WIDTH == 16 -# define VECTOR_FACTOR 8 -# define vect_t uint16x8_t -# define VLD1Q(X) vld1q_u16((sljit_u16 *)(X)) -# define VCEQQ vceqq_u16 -# define VORRQ vorrq_u16 -# define VST1Q vst1q_u16 -# define VDUPQ vdupq_n_u16 -# define VEXTQ vextq_u16 -# define VANDQ vandq_u16 -typedef union { - uint16_t mem[8]; - uint64_t dw[2]; -} quad_word; -#else -# define VECTOR_FACTOR 4 -# define vect_t uint32x4_t -# define VLD1Q(X) vld1q_u32((sljit_u32 *)(X)) -# define VCEQQ vceqq_u32 -# define VORRQ vorrq_u32 -# define VST1Q vst1q_u32 -# define VDUPQ vdupq_n_u32 -# define VEXTQ vextq_u32 -# define VANDQ vandq_u32 -typedef union { - uint32_t mem[4]; - uint64_t dw[2]; -} quad_word; -#endif - -#define FFCS -#include "pcre2_jit_neon_inc.h" -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 -# define FF_UTF -# include "pcre2_jit_neon_inc.h" -# undef FF_UTF -#endif -#undef FFCS - -#define FFCS_2 -#include "pcre2_jit_neon_inc.h" -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 -# define FF_UTF -# include "pcre2_jit_neon_inc.h" -# undef FF_UTF -#endif -#undef FFCS_2 - -#define FFCS_MASK -#include "pcre2_jit_neon_inc.h" -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 -# define FF_UTF -# include "pcre2_jit_neon_inc.h" -# undef FF_UTF -#endif -#undef FFCS_MASK - -#define JIT_HAS_FAST_FORWARD_CHAR_SIMD 1 - -static void fast_forward_char_simd(compiler_common *common, PCRE2_UCHAR char1, PCRE2_UCHAR char2, sljit_s32 offset) -{ -DEFINE_COMPILER; -int_char ic; -struct sljit_jump *partial_quit; -/* Save temporary registers. */ -OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS0, STR_PTR, 0); -OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS1, TMP3, 0); - -/* Prepare function arguments */ -OP1(SLJIT_MOV, SLJIT_R0, 0, STR_END, 0); -OP1(SLJIT_MOV, SLJIT_R1, 0, STR_PTR, 0); -OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_IMM, offset); - -if (char1 == char2) - { - ic.c.c1 = char1; - ic.c.c2 = char2; - OP1(SLJIT_MOV, SLJIT_R4, 0, SLJIT_IMM, ic.x); - -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 - if (common->utf && offset > 0) - sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_ARGS4(W, W, W, W, W), - SLJIT_IMM, SLJIT_FUNC_ADDR(ffcs_utf)); - else - sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_ARGS4(W, W, W, W, W), - SLJIT_IMM, SLJIT_FUNC_ADDR(ffcs)); -#else - sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_ARGS4(W, W, W, W, W), - SLJIT_IMM, SLJIT_FUNC_ADDR(ffcs)); -#endif - } -else - { - PCRE2_UCHAR mask = char1 ^ char2; - if (is_powerof2(mask)) - { - ic.c.c1 = char1 | mask; - ic.c.c2 = mask; - OP1(SLJIT_MOV, SLJIT_R4, 0, SLJIT_IMM, ic.x); - -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 - if (common->utf && offset > 0) - sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_ARGS4(W, W, W, W, W), - SLJIT_IMM, SLJIT_FUNC_ADDR(ffcs_mask_utf)); - else - sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_ARGS4(W, W, W, W, W), - SLJIT_IMM, SLJIT_FUNC_ADDR(ffcs_mask)); -#else - sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_ARGS4(W, W, W, W, W), - SLJIT_IMM, SLJIT_FUNC_ADDR(ffcs_mask)); -#endif - } - else - { - ic.c.c1 = char1; - ic.c.c2 = char2; - OP1(SLJIT_MOV, SLJIT_R4, 0, SLJIT_IMM, ic.x); - -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 - if (common->utf && offset > 0) - sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_ARGS4(W, W, W, W, W), - SLJIT_IMM, SLJIT_FUNC_ADDR(ffcs_2_utf)); - else - sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_ARGS4(W, W, W, W, W), - SLJIT_IMM, SLJIT_FUNC_ADDR(ffcs_2)); -#else - sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_ARGS4(W, W, W, W, W), - SLJIT_IMM, SLJIT_FUNC_ADDR(ffcs_2)); -#endif - } - } -/* Restore registers. */ -OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0); -OP1(SLJIT_MOV, TMP3, 0, SLJIT_MEM1(SLJIT_SP), LOCALS1); - -/* Check return value. */ -partial_quit = CMP(SLJIT_EQUAL, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0); -if (common->mode == PCRE2_JIT_COMPLETE) - add_jump(compiler, &common->failed_match, partial_quit); - -/* Fast forward STR_PTR to the result of memchr. */ -OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_RETURN_REG, 0); - -if (common->mode != PCRE2_JIT_COMPLETE) - JUMPHERE(partial_quit); -} - -typedef enum { - compare_match1, - compare_match1i, - compare_match2, -} compare_type; - -static inline vect_t fast_forward_char_pair_compare(compare_type ctype, vect_t dst, vect_t cmp1, vect_t cmp2) -{ -if (ctype == compare_match2) - { - vect_t tmp = dst; - dst = VCEQQ(dst, cmp1); - tmp = VCEQQ(tmp, cmp2); - dst = VORRQ(dst, tmp); - return dst; - } - -if (ctype == compare_match1i) - dst = VORRQ(dst, cmp2); -dst = VCEQQ(dst, cmp1); -return dst; -} - -static SLJIT_INLINE sljit_u32 max_fast_forward_char_pair_offset(void) -{ -#if PCRE2_CODE_UNIT_WIDTH == 8 -return 15; -#elif PCRE2_CODE_UNIT_WIDTH == 16 -return 7; -#elif PCRE2_CODE_UNIT_WIDTH == 32 -return 3; -#else -#error "Unsupported unit width" -#endif -} - -/* ARM doesn't have a shift left across lanes. */ -static SLJIT_INLINE vect_t shift_left_n_lanes(vect_t a, sljit_u8 n) -{ -vect_t zero = VDUPQ(0); -SLJIT_ASSERT(0 < n && n < VECTOR_FACTOR); -/* VEXTQ takes an immediate as last argument. */ -#define C(X) case X: return VEXTQ(zero, a, VECTOR_FACTOR - X); -switch (n) - { - C(1); C(2); C(3); -#if PCRE2_CODE_UNIT_WIDTH != 32 - C(4); C(5); C(6); C(7); -# if PCRE2_CODE_UNIT_WIDTH != 16 - C(8); C(9); C(10); C(11); C(12); C(13); C(14); C(15); -# endif -#endif - default: - /* Based on the ASSERT(0 < n && n < VECTOR_FACTOR) above, this won't - happen. The return is still here for compilers to not warn. */ - return a; - } -} - -#define FFCPS -#define FFCPS_DIFF1 -#define FFCPS_CHAR1A2A - -#define FFCPS_0 -#include "pcre2_jit_neon_inc.h" -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 -# define FF_UTF -# include "pcre2_jit_neon_inc.h" -# undef FF_UTF -#endif -#undef FFCPS_0 - -#undef FFCPS_CHAR1A2A - -#define FFCPS_1 -#include "pcre2_jit_neon_inc.h" -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 -# define FF_UTF -# include "pcre2_jit_neon_inc.h" -# undef FF_UTF -#endif -#undef FFCPS_1 - -#undef FFCPS_DIFF1 - -#define FFCPS_DEFAULT -#include "pcre2_jit_neon_inc.h" -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 -# define FF_UTF -# include "pcre2_jit_neon_inc.h" -# undef FF_UTF -#endif -#undef FFCPS - -#define JIT_HAS_FAST_FORWARD_CHAR_PAIR_SIMD 1 - -static void fast_forward_char_pair_simd(compiler_common *common, sljit_s32 offs1, - PCRE2_UCHAR char1a, PCRE2_UCHAR char1b, sljit_s32 offs2, PCRE2_UCHAR char2a, PCRE2_UCHAR char2b) -{ -DEFINE_COMPILER; -sljit_u32 diff = IN_UCHARS(offs1 - offs2); -struct sljit_jump *partial_quit; -int_char ic; -SLJIT_ASSERT(common->mode == PCRE2_JIT_COMPLETE && offs1 > offs2); -SLJIT_ASSERT(diff <= IN_UCHARS(max_fast_forward_char_pair_offset())); -SLJIT_ASSERT(compiler->scratches == 5); - -/* Save temporary register STR_PTR. */ -OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS0, STR_PTR, 0); - -/* Prepare arguments for the function call. */ -if (common->match_end_ptr == 0) - OP1(SLJIT_MOV, SLJIT_R0, 0, STR_END, 0); -else - { - OP1(SLJIT_MOV, SLJIT_R0, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr); - OP2(SLJIT_ADD, SLJIT_R0, 0, SLJIT_R0, 0, SLJIT_IMM, IN_UCHARS(offs1 + 1)); - - OP2U(SLJIT_SUB | SLJIT_SET_LESS, STR_END, 0, SLJIT_R0, 0); - CMOV(SLJIT_LESS, SLJIT_R0, STR_END, 0); - } - -OP1(SLJIT_MOV, SLJIT_R1, 0, STR_PTR, 0); -OP1(SLJIT_MOV_S32, SLJIT_R2, 0, SLJIT_IMM, offs1); -OP1(SLJIT_MOV_S32, SLJIT_R3, 0, SLJIT_IMM, offs2); -ic.c.c1 = char1a; -ic.c.c2 = char1b; -ic.c.c3 = char2a; -ic.c.c4 = char2b; -OP1(SLJIT_MOV_U32, SLJIT_R4, 0, SLJIT_IMM, ic.x); - -if (diff == 1) { - if (char1a == char1b && char2a == char2b) { -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 - if (common->utf) - sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_ARGS4(W, W, W, W, W), - SLJIT_IMM, SLJIT_FUNC_ADDR(ffcps_0_utf)); - else -#endif - sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_ARGS4(W, W, W, W, W), - SLJIT_IMM, SLJIT_FUNC_ADDR(ffcps_0)); - } else { -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 - if (common->utf) - sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_ARGS4(W, W, W, W, W), - SLJIT_IMM, SLJIT_FUNC_ADDR(ffcps_1_utf)); - else -#endif - sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_ARGS4(W, W, W, W, W), - SLJIT_IMM, SLJIT_FUNC_ADDR(ffcps_1)); - } -} else { -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 - if (common->utf) - sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_ARGS4(W, W, W, W, W), - SLJIT_IMM, SLJIT_FUNC_ADDR(ffcps_default_utf)); - else -#endif - sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_ARGS4(W, W, W, W, W), - SLJIT_IMM, SLJIT_FUNC_ADDR(ffcps_default)); -} - -/* Restore STR_PTR register. */ -OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0); - -/* Check return value. */ -partial_quit = CMP(SLJIT_EQUAL, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0); -add_jump(compiler, &common->failed_match, partial_quit); - -/* Fast forward STR_PTR to the result of memchr. */ -OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_RETURN_REG, 0); - -JUMPHERE(partial_quit); -} - -#endif /* SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64 */ - -#if (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X) - -#if PCRE2_CODE_UNIT_WIDTH == 8 -#define VECTOR_ELEMENT_SIZE 0 -#elif PCRE2_CODE_UNIT_WIDTH == 16 -#define VECTOR_ELEMENT_SIZE 1 -#elif PCRE2_CODE_UNIT_WIDTH == 32 -#define VECTOR_ELEMENT_SIZE 2 -#else -#error "Unsupported unit width" -#endif - -static void load_from_mem_vector(struct sljit_compiler *compiler, BOOL vlbb, sljit_s32 dst_vreg, - sljit_s32 base_reg, sljit_s32 index_reg) -{ -sljit_u16 instruction[3]; - -instruction[0] = (sljit_u16)(0xe700 | (dst_vreg << 4) | index_reg); -instruction[1] = (sljit_u16)(base_reg << 12); -instruction[2] = (sljit_u16)((0x8 << 8) | (vlbb ? 0x07 : 0x06)); - -sljit_emit_op_custom(compiler, instruction, 6); -} - -#if PCRE2_CODE_UNIT_WIDTH == 32 - -static void replicate_imm_vector(struct sljit_compiler *compiler, int step, sljit_s32 dst_vreg, - PCRE2_UCHAR chr, sljit_s32 tmp_general_reg) -{ -sljit_u16 instruction[3]; - -SLJIT_ASSERT(step >= 0 && step <= 1); - -if (chr < 0x7fff) - { - if (step == 1) - return; - - /* VREPI */ - instruction[0] = (sljit_u16)(0xe700 | (dst_vreg << 4)); - instruction[1] = (sljit_u16)chr; - instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0x8 << 8) | 0x45); - sljit_emit_op_custom(compiler, instruction, 6); - return; - } - -if (step == 0) - { - OP1(SLJIT_MOV, tmp_general_reg, 0, SLJIT_IMM, chr); - - /* VLVG */ - instruction[0] = (sljit_u16)(0xe700 | (dst_vreg << 4) | sljit_get_register_index(tmp_general_reg)); - instruction[1] = 0; - instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0x8 << 8) | 0x22); - sljit_emit_op_custom(compiler, instruction, 6); - return; - } - -/* VREP */ -instruction[0] = (sljit_u16)(0xe700 | (dst_vreg << 4) | dst_vreg); -instruction[1] = 0; -instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0xc << 8) | 0x4d); -sljit_emit_op_custom(compiler, instruction, 6); -} - -#endif - -static void fast_forward_char_pair_sse2_compare(struct sljit_compiler *compiler, vector_compare_type compare_type, - int step, sljit_s32 dst_ind, sljit_s32 cmp1_ind, sljit_s32 cmp2_ind, sljit_s32 tmp_ind) -{ -sljit_u16 instruction[3]; - -SLJIT_ASSERT(step >= 0 && step <= 2); - -if (step == 1) - { - /* VCEQ */ - instruction[0] = (sljit_u16)(0xe700 | (dst_ind << 4) | dst_ind); - instruction[1] = (sljit_u16)(cmp1_ind << 12); - instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0xe << 8) | 0xf8); - sljit_emit_op_custom(compiler, instruction, 6); - return; - } - -if (compare_type != vector_compare_match2) - { - if (step == 0 && compare_type == vector_compare_match1i) - { - /* VO */ - instruction[0] = (sljit_u16)(0xe700 | (dst_ind << 4) | dst_ind); - instruction[1] = (sljit_u16)(cmp2_ind << 12); - instruction[2] = (sljit_u16)((0xe << 8) | 0x6a); - sljit_emit_op_custom(compiler, instruction, 6); - } - return; - } - -switch (step) - { - case 0: - /* VCEQ */ - instruction[0] = (sljit_u16)(0xe700 | (tmp_ind << 4) | dst_ind); - instruction[1] = (sljit_u16)(cmp2_ind << 12); - instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0xe << 8) | 0xf8); - sljit_emit_op_custom(compiler, instruction, 6); - return; - - case 2: - /* VO */ - instruction[0] = (sljit_u16)(0xe700 | (dst_ind << 4) | dst_ind); - instruction[1] = (sljit_u16)(tmp_ind << 12); - instruction[2] = (sljit_u16)((0xe << 8) | 0x6a); - sljit_emit_op_custom(compiler, instruction, 6); - return; - } -} - -#define JIT_HAS_FAST_FORWARD_CHAR_SIMD 1 - -static void fast_forward_char_simd(compiler_common *common, PCRE2_UCHAR char1, PCRE2_UCHAR char2, sljit_s32 offset) -{ -DEFINE_COMPILER; -sljit_u16 instruction[3]; -struct sljit_label *start; -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 -struct sljit_label *restart; -#endif -struct sljit_jump *quit; -struct sljit_jump *partial_quit[2]; -vector_compare_type compare_type = vector_compare_match1; -sljit_s32 tmp1_reg_ind = sljit_get_register_index(TMP1); -sljit_s32 str_ptr_reg_ind = sljit_get_register_index(STR_PTR); -sljit_s32 data_ind = 0; -sljit_s32 tmp_ind = 1; -sljit_s32 cmp1_ind = 2; -sljit_s32 cmp2_ind = 3; -sljit_s32 zero_ind = 4; -sljit_u32 bit = 0; -int i; - -SLJIT_UNUSED_ARG(offset); - -if (char1 != char2) - { - bit = char1 ^ char2; - compare_type = vector_compare_match1i; - - if (!is_powerof2(bit)) - { - bit = 0; - compare_type = vector_compare_match2; - } - } - -partial_quit[0] = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); -if (common->mode == PCRE2_JIT_COMPLETE) - add_jump(compiler, &common->failed_match, partial_quit[0]); - -/* First part (unaligned start) */ - -OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, 16); - -#if PCRE2_CODE_UNIT_WIDTH != 32 - -/* VREPI */ -instruction[0] = (sljit_u16)(0xe700 | (cmp1_ind << 4)); -instruction[1] = (sljit_u16)(char1 | bit); -instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0x8 << 8) | 0x45); -sljit_emit_op_custom(compiler, instruction, 6); - -if (char1 != char2) - { - /* VREPI */ - instruction[0] = (sljit_u16)(0xe700 | (cmp2_ind << 4)); - instruction[1] = (sljit_u16)(bit != 0 ? bit : char2); - /* instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0x8 << 8) | 0x45); */ - sljit_emit_op_custom(compiler, instruction, 6); - } - -#else /* PCRE2_CODE_UNIT_WIDTH == 32 */ - -for (int i = 0; i < 2; i++) - { - replicate_imm_vector(compiler, i, cmp1_ind, char1 | bit, TMP1); - - if (char1 != char2) - replicate_imm_vector(compiler, i, cmp2_ind, bit != 0 ? bit : char2, TMP1); - } - -#endif /* PCRE2_CODE_UNIT_WIDTH != 32 */ - -if (compare_type == vector_compare_match2) - { - /* VREPI */ - instruction[0] = (sljit_u16)(0xe700 | (zero_ind << 4)); - instruction[1] = 0; - instruction[2] = (sljit_u16)((0x8 << 8) | 0x45); - sljit_emit_op_custom(compiler, instruction, 6); - } - -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 -restart = LABEL(); -#endif - -load_from_mem_vector(compiler, TRUE, data_ind, str_ptr_reg_ind, 0); -OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, ~15); - -if (compare_type != vector_compare_match2) - { - if (compare_type == vector_compare_match1i) - fast_forward_char_pair_sse2_compare(compiler, compare_type, 0, data_ind, cmp1_ind, cmp2_ind, tmp_ind); - - /* VFEE */ - instruction[0] = (sljit_u16)(0xe700 | (data_ind << 4) | data_ind); - instruction[1] = (sljit_u16)((cmp1_ind << 12) | (1 << 4)); - instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0xe << 8) | 0x80); - sljit_emit_op_custom(compiler, instruction, 6); - } -else - { - for (i = 0; i < 3; i++) - fast_forward_char_pair_sse2_compare(compiler, compare_type, i, data_ind, cmp1_ind, cmp2_ind, tmp_ind); - - /* VFENE */ - instruction[0] = (sljit_u16)(0xe700 | (data_ind << 4) | data_ind); - instruction[1] = (sljit_u16)((zero_ind << 12) | (1 << 4)); - instruction[2] = (sljit_u16)((0xe << 8) | 0x81); - sljit_emit_op_custom(compiler, instruction, 6); - } - -/* VLGVB */ -instruction[0] = (sljit_u16)(0xe700 | (tmp1_reg_ind << 4) | data_ind); -instruction[1] = 7; -instruction[2] = (sljit_u16)((0x4 << 8) | 0x21); -sljit_emit_op_custom(compiler, instruction, 6); - -OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0); -quit = CMP(SLJIT_LESS, STR_PTR, 0, TMP2, 0); - -OP2(SLJIT_SUB, STR_PTR, 0, TMP2, 0, SLJIT_IMM, 16); - -/* Second part (aligned) */ -start = LABEL(); - -OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 16); - -partial_quit[1] = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); -if (common->mode == PCRE2_JIT_COMPLETE) - add_jump(compiler, &common->failed_match, partial_quit[1]); - -load_from_mem_vector(compiler, TRUE, data_ind, str_ptr_reg_ind, 0); - -if (compare_type != vector_compare_match2) - { - if (compare_type == vector_compare_match1i) - fast_forward_char_pair_sse2_compare(compiler, compare_type, 0, data_ind, cmp1_ind, cmp2_ind, tmp_ind); - - /* VFEE */ - instruction[0] = (sljit_u16)(0xe700 | (data_ind << 4) | data_ind); - instruction[1] = (sljit_u16)((cmp1_ind << 12) | (1 << 4)); - instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0xe << 8) | 0x80); - sljit_emit_op_custom(compiler, instruction, 6); - } -else - { - for (i = 0; i < 3; i++) - fast_forward_char_pair_sse2_compare(compiler, compare_type, i, data_ind, cmp1_ind, cmp2_ind, tmp_ind); - - /* VFENE */ - instruction[0] = (sljit_u16)(0xe700 | (data_ind << 4) | data_ind); - instruction[1] = (sljit_u16)((zero_ind << 12) | (1 << 4)); - instruction[2] = (sljit_u16)((0xe << 8) | 0x81); - sljit_emit_op_custom(compiler, instruction, 6); - } - -sljit_set_current_flags(compiler, SLJIT_SET_OVERFLOW); -JUMPTO(SLJIT_OVERFLOW, start); - -/* VLGVB */ -instruction[0] = (sljit_u16)(0xe700 | (tmp1_reg_ind << 4) | data_ind); -instruction[1] = 7; -instruction[2] = (sljit_u16)((0x4 << 8) | 0x21); -sljit_emit_op_custom(compiler, instruction, 6); - -OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0); - -JUMPHERE(quit); - -if (common->mode != PCRE2_JIT_COMPLETE) - { - JUMPHERE(partial_quit[0]); - JUMPHERE(partial_quit[1]); - OP2U(SLJIT_SUB | SLJIT_SET_GREATER, STR_PTR, 0, STR_END, 0); - CMOV(SLJIT_GREATER, STR_PTR, STR_END, 0); - } -else - add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0)); - -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 -if (common->utf && offset > 0) - { - SLJIT_ASSERT(common->mode == PCRE2_JIT_COMPLETE); - - OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-offset)); - - quit = jump_if_utf_char_start(compiler, TMP1); - - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0)); - - OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, 16); - JUMPTO(SLJIT_JUMP, restart); - - JUMPHERE(quit); - } -#endif -} - -#define JIT_HAS_FAST_REQUESTED_CHAR_SIMD 1 - -static jump_list *fast_requested_char_simd(compiler_common *common, PCRE2_UCHAR char1, PCRE2_UCHAR char2) -{ -DEFINE_COMPILER; -sljit_u16 instruction[3]; -struct sljit_label *start; -struct sljit_jump *quit; -jump_list *not_found = NULL; -vector_compare_type compare_type = vector_compare_match1; -sljit_s32 tmp1_reg_ind = sljit_get_register_index(TMP1); -sljit_s32 tmp3_reg_ind = sljit_get_register_index(TMP3); -sljit_s32 data_ind = 0; -sljit_s32 tmp_ind = 1; -sljit_s32 cmp1_ind = 2; -sljit_s32 cmp2_ind = 3; -sljit_s32 zero_ind = 4; -sljit_u32 bit = 0; -int i; - -if (char1 != char2) - { - bit = char1 ^ char2; - compare_type = vector_compare_match1i; - - if (!is_powerof2(bit)) - { - bit = 0; - compare_type = vector_compare_match2; - } - } - -add_jump(compiler, ¬_found, CMP(SLJIT_GREATER_EQUAL, TMP1, 0, STR_END, 0)); - -/* First part (unaligned start) */ - -OP2(SLJIT_ADD, TMP2, 0, TMP1, 0, SLJIT_IMM, 16); - -#if PCRE2_CODE_UNIT_WIDTH != 32 - -/* VREPI */ -instruction[0] = (sljit_u16)(0xe700 | (cmp1_ind << 4)); -instruction[1] = (sljit_u16)(char1 | bit); -instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0x8 << 8) | 0x45); -sljit_emit_op_custom(compiler, instruction, 6); - -if (char1 != char2) - { - /* VREPI */ - instruction[0] = (sljit_u16)(0xe700 | (cmp2_ind << 4)); - instruction[1] = (sljit_u16)(bit != 0 ? bit : char2); - /* instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0x8 << 8) | 0x45); */ - sljit_emit_op_custom(compiler, instruction, 6); - } - -#else /* PCRE2_CODE_UNIT_WIDTH == 32 */ - -for (int i = 0; i < 2; i++) - { - replicate_imm_vector(compiler, i, cmp1_ind, char1 | bit, TMP3); - - if (char1 != char2) - replicate_imm_vector(compiler, i, cmp2_ind, bit != 0 ? bit : char2, TMP3); - } - -#endif /* PCRE2_CODE_UNIT_WIDTH != 32 */ - -if (compare_type == vector_compare_match2) - { - /* VREPI */ - instruction[0] = (sljit_u16)(0xe700 | (zero_ind << 4)); - instruction[1] = 0; - instruction[2] = (sljit_u16)((0x8 << 8) | 0x45); - sljit_emit_op_custom(compiler, instruction, 6); - } - -load_from_mem_vector(compiler, TRUE, data_ind, tmp1_reg_ind, 0); -OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, ~15); - -if (compare_type != vector_compare_match2) - { - if (compare_type == vector_compare_match1i) - fast_forward_char_pair_sse2_compare(compiler, compare_type, 0, data_ind, cmp1_ind, cmp2_ind, tmp_ind); - - /* VFEE */ - instruction[0] = (sljit_u16)(0xe700 | (data_ind << 4) | data_ind); - instruction[1] = (sljit_u16)((cmp1_ind << 12) | (1 << 4)); - instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0xe << 8) | 0x80); - sljit_emit_op_custom(compiler, instruction, 6); - } -else - { - for (i = 0; i < 3; i++) - fast_forward_char_pair_sse2_compare(compiler, compare_type, i, data_ind, cmp1_ind, cmp2_ind, tmp_ind); - - /* VFENE */ - instruction[0] = (sljit_u16)(0xe700 | (data_ind << 4) | data_ind); - instruction[1] = (sljit_u16)((zero_ind << 12) | (1 << 4)); - instruction[2] = (sljit_u16)((0xe << 8) | 0x81); - sljit_emit_op_custom(compiler, instruction, 6); - } - -/* VLGVB */ -instruction[0] = (sljit_u16)(0xe700 | (tmp3_reg_ind << 4) | data_ind); -instruction[1] = 7; -instruction[2] = (sljit_u16)((0x4 << 8) | 0x21); -sljit_emit_op_custom(compiler, instruction, 6); - -OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP3, 0); -quit = CMP(SLJIT_LESS, TMP1, 0, TMP2, 0); - -OP2(SLJIT_SUB, TMP1, 0, TMP2, 0, SLJIT_IMM, 16); - -/* Second part (aligned) */ -start = LABEL(); - -OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 16); - -add_jump(compiler, ¬_found, CMP(SLJIT_GREATER_EQUAL, TMP1, 0, STR_END, 0)); - -load_from_mem_vector(compiler, TRUE, data_ind, tmp1_reg_ind, 0); - -if (compare_type != vector_compare_match2) - { - if (compare_type == vector_compare_match1i) - fast_forward_char_pair_sse2_compare(compiler, compare_type, 0, data_ind, cmp1_ind, cmp2_ind, tmp_ind); - - /* VFEE */ - instruction[0] = (sljit_u16)(0xe700 | (data_ind << 4) | data_ind); - instruction[1] = (sljit_u16)((cmp1_ind << 12) | (1 << 4)); - instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0xe << 8) | 0x80); - sljit_emit_op_custom(compiler, instruction, 6); - } -else - { - for (i = 0; i < 3; i++) - fast_forward_char_pair_sse2_compare(compiler, compare_type, i, data_ind, cmp1_ind, cmp2_ind, tmp_ind); - - /* VFENE */ - instruction[0] = (sljit_u16)(0xe700 | (data_ind << 4) | data_ind); - instruction[1] = (sljit_u16)((zero_ind << 12) | (1 << 4)); - instruction[2] = (sljit_u16)((0xe << 8) | 0x81); - sljit_emit_op_custom(compiler, instruction, 6); - } - -sljit_set_current_flags(compiler, SLJIT_SET_OVERFLOW); -JUMPTO(SLJIT_OVERFLOW, start); - -/* VLGVB */ -instruction[0] = (sljit_u16)(0xe700 | (tmp3_reg_ind << 4) | data_ind); -instruction[1] = 7; -instruction[2] = (sljit_u16)((0x4 << 8) | 0x21); -sljit_emit_op_custom(compiler, instruction, 6); - -OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP3, 0); - -JUMPHERE(quit); -add_jump(compiler, ¬_found, CMP(SLJIT_GREATER_EQUAL, TMP1, 0, STR_END, 0)); - -return not_found; -} - -#define JIT_HAS_FAST_FORWARD_CHAR_PAIR_SIMD 1 - -static void fast_forward_char_pair_simd(compiler_common *common, sljit_s32 offs1, - PCRE2_UCHAR char1a, PCRE2_UCHAR char1b, sljit_s32 offs2, PCRE2_UCHAR char2a, PCRE2_UCHAR char2b) -{ -DEFINE_COMPILER; -sljit_u16 instruction[3]; -struct sljit_label *start; -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 -struct sljit_label *restart; -#endif -struct sljit_jump *quit; -struct sljit_jump *jump[2]; -vector_compare_type compare1_type = vector_compare_match1; -vector_compare_type compare2_type = vector_compare_match1; -sljit_u32 bit1 = 0; -sljit_u32 bit2 = 0; -sljit_s32 diff = IN_UCHARS(offs2 - offs1); -sljit_s32 tmp1_reg_ind = sljit_get_register_index(TMP1); -sljit_s32 tmp2_reg_ind = sljit_get_register_index(TMP2); -sljit_s32 str_ptr_reg_ind = sljit_get_register_index(STR_PTR); -sljit_s32 data1_ind = 0; -sljit_s32 data2_ind = 1; -sljit_s32 tmp1_ind = 2; -sljit_s32 tmp2_ind = 3; -sljit_s32 cmp1a_ind = 4; -sljit_s32 cmp1b_ind = 5; -sljit_s32 cmp2a_ind = 6; -sljit_s32 cmp2b_ind = 7; -sljit_s32 zero_ind = 8; -int i; - -SLJIT_ASSERT(common->mode == PCRE2_JIT_COMPLETE && offs1 > offs2); -SLJIT_ASSERT(-diff <= (sljit_s32)IN_UCHARS(max_fast_forward_char_pair_offset())); -SLJIT_ASSERT(tmp1_reg_ind != 0 && tmp2_reg_ind != 0); - -if (char1a != char1b) - { - bit1 = char1a ^ char1b; - compare1_type = vector_compare_match1i; - - if (!is_powerof2(bit1)) - { - bit1 = 0; - compare1_type = vector_compare_match2; - } - } - -if (char2a != char2b) - { - bit2 = char2a ^ char2b; - compare2_type = vector_compare_match1i; - - if (!is_powerof2(bit2)) - { - bit2 = 0; - compare2_type = vector_compare_match2; - } - } - -/* Initialize. */ -if (common->match_end_ptr != 0) - { - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr); - OP1(SLJIT_MOV, TMP3, 0, STR_END, 0); - OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(offs1 + 1)); - - OP2U(SLJIT_SUB | SLJIT_SET_LESS, TMP1, 0, STR_END, 0); - CMOV(SLJIT_LESS, STR_END, TMP1, 0); - } - -OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(offs1)); -add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0)); -OP2(SLJIT_AND, TMP2, 0, STR_PTR, 0, SLJIT_IMM, ~15); - -#if PCRE2_CODE_UNIT_WIDTH != 32 - -OP2(SLJIT_SUB, TMP1, 0, STR_PTR, 0, SLJIT_IMM, -diff); - -/* VREPI */ -instruction[0] = (sljit_u16)(0xe700 | (cmp1a_ind << 4)); -instruction[1] = (sljit_u16)(char1a | bit1); -instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0x8 << 8) | 0x45); -sljit_emit_op_custom(compiler, instruction, 6); - -if (char1a != char1b) - { - /* VREPI */ - instruction[0] = (sljit_u16)(0xe700 | (cmp1b_ind << 4)); - instruction[1] = (sljit_u16)(bit1 != 0 ? bit1 : char1b); - /* instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0x8 << 8) | 0x45); */ - sljit_emit_op_custom(compiler, instruction, 6); - } - -/* VREPI */ -instruction[0] = (sljit_u16)(0xe700 | (cmp2a_ind << 4)); -instruction[1] = (sljit_u16)(char2a | bit2); -/* instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0x8 << 8) | 0x45); */ -sljit_emit_op_custom(compiler, instruction, 6); - -if (char2a != char2b) - { - /* VREPI */ - instruction[0] = (sljit_u16)(0xe700 | (cmp2b_ind << 4)); - instruction[1] = (sljit_u16)(bit2 != 0 ? bit2 : char2b); - /* instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0x8 << 8) | 0x45); */ - sljit_emit_op_custom(compiler, instruction, 6); - } - -#else /* PCRE2_CODE_UNIT_WIDTH == 32 */ - -for (int i = 0; i < 2; i++) - { - replicate_imm_vector(compiler, i, cmp1a_ind, char1a | bit1, TMP1); - - if (char1a != char1b) - replicate_imm_vector(compiler, i, cmp1b_ind, bit1 != 0 ? bit1 : char1b, TMP1); - - replicate_imm_vector(compiler, i, cmp2a_ind, char2a | bit2, TMP1); - - if (char2a != char2b) - replicate_imm_vector(compiler, i, cmp2b_ind, bit2 != 0 ? bit2 : char2b, TMP1); - } - -OP2(SLJIT_SUB, TMP1, 0, STR_PTR, 0, SLJIT_IMM, -diff); - -#endif /* PCRE2_CODE_UNIT_WIDTH != 32 */ - -/* VREPI */ -instruction[0] = (sljit_u16)(0xe700 | (zero_ind << 4)); -instruction[1] = 0; -instruction[2] = (sljit_u16)((0x8 << 8) | 0x45); -sljit_emit_op_custom(compiler, instruction, 6); - -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 -restart = LABEL(); -#endif - -jump[0] = CMP(SLJIT_LESS, TMP1, 0, TMP2, 0); -load_from_mem_vector(compiler, TRUE, data2_ind, tmp1_reg_ind, 0); -jump[1] = JUMP(SLJIT_JUMP); -JUMPHERE(jump[0]); -load_from_mem_vector(compiler, FALSE, data2_ind, tmp1_reg_ind, 0); -JUMPHERE(jump[1]); - -load_from_mem_vector(compiler, TRUE, data1_ind, str_ptr_reg_ind, 0); -OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, SLJIT_IMM, 16); - -for (i = 0; i < 3; i++) - { - fast_forward_char_pair_sse2_compare(compiler, compare1_type, i, data1_ind, cmp1a_ind, cmp1b_ind, tmp1_ind); - fast_forward_char_pair_sse2_compare(compiler, compare2_type, i, data2_ind, cmp2a_ind, cmp2b_ind, tmp2_ind); - } - -/* VN */ -instruction[0] = (sljit_u16)(0xe700 | (data1_ind << 4) | data1_ind); -instruction[1] = (sljit_u16)(data2_ind << 12); -instruction[2] = (sljit_u16)((0xe << 8) | 0x68); -sljit_emit_op_custom(compiler, instruction, 6); - -/* VFENE */ -instruction[0] = (sljit_u16)(0xe700 | (data1_ind << 4) | data1_ind); -instruction[1] = (sljit_u16)((zero_ind << 12) | (1 << 4)); -instruction[2] = (sljit_u16)((0xe << 8) | 0x81); -sljit_emit_op_custom(compiler, instruction, 6); - -/* VLGVB */ -instruction[0] = (sljit_u16)(0xe700 | (tmp1_reg_ind << 4) | data1_ind); -instruction[1] = 7; -instruction[2] = (sljit_u16)((0x4 << 8) | 0x21); -sljit_emit_op_custom(compiler, instruction, 6); - -OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0); -quit = CMP(SLJIT_LESS, STR_PTR, 0, TMP2, 0); - -OP2(SLJIT_SUB, STR_PTR, 0, TMP2, 0, SLJIT_IMM, 16); -OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, diff); - -/* Main loop. */ -start = LABEL(); - -OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 16); -add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0)); - -load_from_mem_vector(compiler, FALSE, data1_ind, str_ptr_reg_ind, 0); -load_from_mem_vector(compiler, FALSE, data2_ind, str_ptr_reg_ind, tmp1_reg_ind); - -for (i = 0; i < 3; i++) - { - fast_forward_char_pair_sse2_compare(compiler, compare1_type, i, data1_ind, cmp1a_ind, cmp1b_ind, tmp1_ind); - fast_forward_char_pair_sse2_compare(compiler, compare2_type, i, data2_ind, cmp2a_ind, cmp2b_ind, tmp2_ind); - } - -/* VN */ -instruction[0] = (sljit_u16)(0xe700 | (data1_ind << 4) | data1_ind); -instruction[1] = (sljit_u16)(data2_ind << 12); -instruction[2] = (sljit_u16)((0xe << 8) | 0x68); -sljit_emit_op_custom(compiler, instruction, 6); - -/* VFENE */ -instruction[0] = (sljit_u16)(0xe700 | (data1_ind << 4) | data1_ind); -instruction[1] = (sljit_u16)((zero_ind << 12) | (1 << 4)); -instruction[2] = (sljit_u16)((0xe << 8) | 0x81); -sljit_emit_op_custom(compiler, instruction, 6); - -sljit_set_current_flags(compiler, SLJIT_SET_OVERFLOW); -JUMPTO(SLJIT_OVERFLOW, start); - -/* VLGVB */ -instruction[0] = (sljit_u16)(0xe700 | (tmp2_reg_ind << 4) | data1_ind); -instruction[1] = 7; -instruction[2] = (sljit_u16)((0x4 << 8) | 0x21); -sljit_emit_op_custom(compiler, instruction, 6); - -OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0); - -JUMPHERE(quit); - -add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0)); - -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 -if (common->utf) - { - SLJIT_ASSERT(common->mode == PCRE2_JIT_COMPLETE); - - OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-offs1)); - - quit = jump_if_utf_char_start(compiler, TMP1); - - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0)); - - /* TMP1 contains diff. */ - OP2(SLJIT_AND, TMP2, 0, STR_PTR, 0, SLJIT_IMM, ~15); - OP2(SLJIT_SUB, TMP1, 0, STR_PTR, 0, SLJIT_IMM, -diff); - JUMPTO(SLJIT_JUMP, restart); - - JUMPHERE(quit); - } -#endif - -OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(offs1)); - -if (common->match_end_ptr != 0) - OP1(SLJIT_MOV, STR_END, 0, TMP3, 0); -} - -#endif /* SLJIT_CONFIG_S390X */ - -#endif /* !SUPPORT_VALGRIND */ diff --git a/modules/regex/pcre2/src/pcre2_maketables.c b/modules/regex/pcre2/src/pcre2_maketables.c deleted file mode 100644 index 56d2494..0000000 --- a/modules/regex/pcre2/src/pcre2_maketables.c +++ /dev/null @@ -1,163 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -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-2020 University of Cambridge - ------------------------------------------------------------------------------ -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 OWNER 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. ------------------------------------------------------------------------------ -*/ - - -/* This module contains the external function pcre2_maketables(), which builds -character tables for PCRE2 in the current locale. The file is compiled on its -own as part of the PCRE2 library. It is also included in the compilation of -pcre2_dftables.c as a freestanding program, in which case the macro -PCRE2_DFTABLES is defined. */ - -#ifndef PCRE2_DFTABLES /* Compiling the library */ -# ifdef HAVE_CONFIG_H -# include "config.h" -# endif -# include "pcre2_internal.h" -#endif - - - -/************************************************* -* Create PCRE2 character tables * -*************************************************/ - -/* This function builds a set of character tables for use by PCRE2 and returns -a pointer to them. They are build using the ctype functions, and consequently -their contents will depend upon the current locale setting. When compiled as -part of the library, the store is obtained via a general context malloc, if -supplied, but when PCRE2_DFTABLES is defined (when compiling the pcre2_dftables -freestanding auxiliary program) malloc() is used, and the function has a -different name so as not to clash with the prototype in pcre2.h. - -Arguments: none when PCRE2_DFTABLES is defined - else a PCRE2 general context or NULL -Returns: pointer to the contiguous block of data - else NULL if memory allocation failed -*/ - -#ifdef PCRE2_DFTABLES /* Included in freestanding pcre2_dftables program */ -static const uint8_t *maketables(void) -{ -uint8_t *yield = (uint8_t *)malloc(TABLES_LENGTH); - -#else /* Not PCRE2_DFTABLES, that is, compiling the library */ -PCRE2_EXP_DEFN const uint8_t * PCRE2_CALL_CONVENTION -pcre2_maketables(pcre2_general_context *gcontext) -{ -uint8_t *yield = (uint8_t *)((gcontext != NULL)? - gcontext->memctl.malloc(TABLES_LENGTH, gcontext->memctl.memory_data) : - malloc(TABLES_LENGTH)); -#endif /* PCRE2_DFTABLES */ - -int i; -uint8_t *p; - -if (yield == NULL) return NULL; -p = yield; - -/* First comes the lower casing table */ - -for (i = 0; i < 256; i++) *p++ = tolower(i); - -/* Next the case-flipping table */ - -for (i = 0; i < 256; i++) *p++ = islower(i)? toupper(i) : tolower(i); - -/* Then the character class tables. Don't try to be clever and save effort on -exclusive ones - in some locales things may be different. - -Note that the table for "space" includes everything "isspace" gives, including -VT in the default locale. This makes it work for the POSIX class [:space:]. -From PCRE1 release 8.34 and for all PCRE2 releases it is also correct for Perl -space, because Perl added VT at release 5.18. - -Note also that it is possible for a character to be alnum or alpha without -being lower or upper, such as "male and female ordinals" (\xAA and \xBA) in the -fr_FR locale (at least under Debian Linux's locales as of 12/2005). So we must -test for alnum specially. */ - -memset(p, 0, cbit_length); -for (i = 0; i < 256; i++) - { - if (isdigit(i)) p[cbit_digit + i/8] |= 1u << (i&7); - if (isupper(i)) p[cbit_upper + i/8] |= 1u << (i&7); - if (islower(i)) p[cbit_lower + i/8] |= 1u << (i&7); - if (isalnum(i)) p[cbit_word + i/8] |= 1u << (i&7); - if (i == '_') p[cbit_word + i/8] |= 1u << (i&7); - if (isspace(i)) p[cbit_space + i/8] |= 1u << (i&7); - if (isxdigit(i)) p[cbit_xdigit + i/8] |= 1u << (i&7); - if (isgraph(i)) p[cbit_graph + i/8] |= 1u << (i&7); - if (isprint(i)) p[cbit_print + i/8] |= 1u << (i&7); - if (ispunct(i)) p[cbit_punct + i/8] |= 1u << (i&7); - if (iscntrl(i)) p[cbit_cntrl + i/8] |= 1u << (i&7); - } -p += cbit_length; - -/* Finally, the character type table. In this, we used to exclude VT from the -white space chars, because Perl didn't recognize it as such for \s and for -comments within regexes. However, Perl changed at release 5.18, so PCRE1 -changed at release 8.34 and it's always been this way for PCRE2. */ - -for (i = 0; i < 256; i++) - { - int x = 0; - if (isspace(i)) x += ctype_space; - if (isalpha(i)) x += ctype_letter; - if (islower(i)) x += ctype_lcletter; - if (isdigit(i)) x += ctype_digit; - if (isalnum(i) || i == '_') x += ctype_word; - *p++ = x; - } - -return yield; -} - -#ifndef PCRE2_DFTABLES /* Compiling the library */ -PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION -pcre2_maketables_free(pcre2_general_context *gcontext, const uint8_t *tables) -{ - if (gcontext) - gcontext->memctl.free((void *)tables, gcontext->memctl.memory_data); - else - free((void *)tables); -} -#endif - -/* End of pcre2_maketables.c */ diff --git a/modules/regex/pcre2/src/pcre2_match.c b/modules/regex/pcre2/src/pcre2_match.c deleted file mode 100644 index 168b9fa..0000000 --- a/modules/regex/pcre2/src/pcre2_match.c +++ /dev/null @@ -1,7544 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -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) 2015-2022 University of Cambridge - ------------------------------------------------------------------------------ -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 OWNER 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. ------------------------------------------------------------------------------ -*/ - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -/* These defines enable debugging code */ - -/* #define DEBUG_FRAMES_DISPLAY */ -/* #define DEBUG_SHOW_OPS */ -/* #define DEBUG_SHOW_RMATCH */ - -#ifdef DEBUG_FRAMES_DISPLAY -#include -#endif - -/* These defines identify the name of the block containing "static" -information, and fields within it. */ - -#define NLBLOCK mb /* Block containing newline information */ -#define PSSTART start_subject /* Field containing processed string start */ -#define PSEND end_subject /* Field containing processed string end */ - -#include "pcre2_internal.h" - -#define RECURSE_UNSET 0xffffffffu /* Bigger than max group number */ - -/* Masks for identifying the public options that are permitted at match time. */ - -#define PUBLIC_MATCH_OPTIONS \ - (PCRE2_ANCHORED|PCRE2_ENDANCHORED|PCRE2_NOTBOL|PCRE2_NOTEOL|PCRE2_NOTEMPTY| \ - PCRE2_NOTEMPTY_ATSTART|PCRE2_NO_UTF_CHECK|PCRE2_PARTIAL_HARD| \ - PCRE2_PARTIAL_SOFT|PCRE2_NO_JIT|PCRE2_COPY_MATCHED_SUBJECT) - -#define PUBLIC_JIT_MATCH_OPTIONS \ - (PCRE2_NO_UTF_CHECK|PCRE2_NOTBOL|PCRE2_NOTEOL|PCRE2_NOTEMPTY|\ - PCRE2_NOTEMPTY_ATSTART|PCRE2_PARTIAL_SOFT|PCRE2_PARTIAL_HARD|\ - PCRE2_COPY_MATCHED_SUBJECT) - -/* Non-error returns from and within the match() function. Error returns are -externally defined PCRE2_ERROR_xxx codes, which are all negative. */ - -#define MATCH_MATCH 1 -#define MATCH_NOMATCH 0 - -/* Special internal returns used in the match() function. Make them -sufficiently negative to avoid the external error codes. */ - -#define MATCH_ACCEPT (-999) -#define MATCH_KETRPOS (-998) -/* The next 5 must be kept together and in sequence so that a test that checks -for any one of them can use a range. */ -#define MATCH_COMMIT (-997) -#define MATCH_PRUNE (-996) -#define MATCH_SKIP (-995) -#define MATCH_SKIP_ARG (-994) -#define MATCH_THEN (-993) -#define MATCH_BACKTRACK_MAX MATCH_THEN -#define MATCH_BACKTRACK_MIN MATCH_COMMIT - -/* Group frame type values. Zero means the frame is not a group frame. The -lower 16 bits are used for data (e.g. the capture number). Group frames are -used for most groups so that information about the start is easily available at -the end without having to scan back through intermediate frames (backtrack -points). */ - -#define GF_CAPTURE 0x00010000u -#define GF_NOCAPTURE 0x00020000u -#define GF_CONDASSERT 0x00030000u -#define GF_RECURSE 0x00040000u - -/* Masks for the identity and data parts of the group frame type. */ - -#define GF_IDMASK(a) ((a) & 0xffff0000u) -#define GF_DATAMASK(a) ((a) & 0x0000ffffu) - -/* Repetition types */ - -enum { REPTYPE_MIN, REPTYPE_MAX, REPTYPE_POS }; - -/* Min and max values for the common repeats; a maximum of UINT32_MAX => -infinity. */ - -static const uint32_t rep_min[] = { - 0, 0, /* * and *? */ - 1, 1, /* + and +? */ - 0, 0, /* ? and ?? */ - 0, 0, /* dummy placefillers for OP_CR[MIN]RANGE */ - 0, 1, 0 }; /* OP_CRPOS{STAR, PLUS, QUERY} */ - -static const uint32_t rep_max[] = { - UINT32_MAX, UINT32_MAX, /* * and *? */ - UINT32_MAX, UINT32_MAX, /* + and +? */ - 1, 1, /* ? and ?? */ - 0, 0, /* dummy placefillers for OP_CR[MIN]RANGE */ - UINT32_MAX, UINT32_MAX, 1 }; /* OP_CRPOS{STAR, PLUS, QUERY} */ - -/* Repetition types - must include OP_CRPOSRANGE (not needed above) */ - -static const uint32_t rep_typ[] = { - REPTYPE_MAX, REPTYPE_MIN, /* * and *? */ - REPTYPE_MAX, REPTYPE_MIN, /* + and +? */ - REPTYPE_MAX, REPTYPE_MIN, /* ? and ?? */ - REPTYPE_MAX, REPTYPE_MIN, /* OP_CRRANGE and OP_CRMINRANGE */ - REPTYPE_POS, REPTYPE_POS, /* OP_CRPOSSTAR, OP_CRPOSPLUS */ - REPTYPE_POS, REPTYPE_POS }; /* OP_CRPOSQUERY, OP_CRPOSRANGE */ - -/* Numbers for RMATCH calls at backtracking points. When these lists are -changed, the code at RETURN_SWITCH below must be updated in sync. */ - -enum { RM1=1, RM2, RM3, RM4, RM5, RM6, RM7, RM8, RM9, RM10, - RM11, RM12, RM13, RM14, RM15, RM16, RM17, RM18, RM19, RM20, - RM21, RM22, RM23, RM24, RM25, RM26, RM27, RM28, RM29, RM30, - RM31, RM32, RM33, RM34, RM35, RM36 }; - -#ifdef SUPPORT_WIDE_CHARS -enum { RM100=100, RM101 }; -#endif - -#ifdef SUPPORT_UNICODE -enum { RM200=200, RM201, RM202, RM203, RM204, RM205, RM206, RM207, - RM208, RM209, RM210, RM211, RM212, RM213, RM214, RM215, - RM216, RM217, RM218, RM219, RM220, RM221, RM222, RM223, - RM224, RM225 }; -#endif - -/* Define short names for general fields in the current backtrack frame, which -is always pointed to by the F variable. Occasional references to fields in -other frames are written out explicitly. There are also some fields in the -current frame whose names start with "temp" that are used for short-term, -localised backtracking memory. These are #defined with Lxxx names at the point -of use and undefined afterwards. */ - -#define Fback_frame F->back_frame -#define Fcapture_last F->capture_last -#define Fcurrent_recurse F->current_recurse -#define Fecode F->ecode -#define Feptr F->eptr -#define Fgroup_frame_type F->group_frame_type -#define Flast_group_offset F->last_group_offset -#define Flength F->length -#define Fmark F->mark -#define Frdepth F->rdepth -#define Fstart_match F->start_match -#define Foffset_top F->offset_top -#define Foccu F->occu -#define Fop F->op -#define Fovector F->ovector -#define Freturn_id F->return_id - - -#ifdef DEBUG_FRAMES_DISPLAY -/************************************************* -* Display current frames and contents * -*************************************************/ - -/* This debugging function displays the current set of frames and their -contents. It is not called automatically from anywhere, the intention being -that calls can be inserted where necessary when debugging frame-related -problems. - -Arguments: - f the file to write to - F the current top frame - P a previous frame of interest - frame_size the frame size - mb points to the match block - match_data points to the match data block - s identification text - -Returns: nothing -*/ - -static void -display_frames(FILE *f, heapframe *F, heapframe *P, PCRE2_SIZE frame_size, - match_block *mb, pcre2_match_data *match_data, const char *s, ...) -{ -uint32_t i; -heapframe *Q; -va_list ap; -va_start(ap, s); - -fprintf(f, "FRAMES "); -vfprintf(f, s, ap); -va_end(ap); - -if (P != NULL) fprintf(f, " P=%lu", - ((char *)P - (char *)(match_data->heapframes))/frame_size); -fprintf(f, "\n"); - -for (i = 0, Q = match_data->heapframes; - Q <= F; - i++, Q = (heapframe *)((char *)Q + frame_size)) - { - fprintf(f, "Frame %d type=%x subj=%lu code=%d back=%lu id=%d", - i, Q->group_frame_type, Q->eptr - mb->start_subject, *(Q->ecode), - Q->back_frame, Q->return_id); - - if (Q->last_group_offset == PCRE2_UNSET) - fprintf(f, " lgoffset=unset\n"); - else - fprintf(f, " lgoffset=%lu\n", Q->last_group_offset/frame_size); - } -} - -#endif - - - -/************************************************* -* Process a callout * -*************************************************/ - -/* This function is called for all callouts, whether "standalone" or at the -start of a conditional group. Feptr will be pointing to either OP_CALLOUT or -OP_CALLOUT_STR. A callout block is allocated in pcre2_match() and initialized -with fixed values. - -Arguments: - F points to the current backtracking frame - mb points to the match block - lengthptr where to return the length of the callout item - -Returns: the return from the callout - or 0 if no callout function exists -*/ - -static int -do_callout(heapframe *F, match_block *mb, PCRE2_SIZE *lengthptr) -{ -int rc; -PCRE2_SIZE save0, save1; -PCRE2_SIZE *callout_ovector; -pcre2_callout_block *cb; - -*lengthptr = (*Fecode == OP_CALLOUT)? - PRIV(OP_lengths)[OP_CALLOUT] : GET(Fecode, 1 + 2*LINK_SIZE); - -if (mb->callout == NULL) return 0; /* No callout function provided */ - -/* The original matching code (pre 10.30) worked directly with the ovector -passed by the user, and this was passed to callouts. Now that the working -ovector is in the backtracking frame, it no longer needs to reserve space for -the overall match offsets (which would waste space in the frame). For backward -compatibility, however, we pass capture_top and offset_vector to the callout as -if for the extended ovector, and we ensure that the first two slots are unset -by preserving and restoring their current contents. Picky compilers complain if -references such as Fovector[-2] are use directly, so we set up a separate -pointer. */ - -callout_ovector = (PCRE2_SIZE *)(Fovector) - 2; - -/* The cb->version, cb->subject, cb->subject_length, and cb->start_match fields -are set externally. The first 3 never change; the last is updated for each -bumpalong. */ - -cb = mb->cb; -cb->capture_top = (uint32_t)Foffset_top/2 + 1; -cb->capture_last = Fcapture_last; -cb->offset_vector = callout_ovector; -cb->mark = mb->nomatch_mark; -cb->current_position = (PCRE2_SIZE)(Feptr - mb->start_subject); -cb->pattern_position = GET(Fecode, 1); -cb->next_item_length = GET(Fecode, 1 + LINK_SIZE); - -if (*Fecode == OP_CALLOUT) /* Numerical callout */ - { - cb->callout_number = Fecode[1 + 2*LINK_SIZE]; - cb->callout_string_offset = 0; - cb->callout_string = NULL; - cb->callout_string_length = 0; - } -else /* String callout */ - { - cb->callout_number = 0; - cb->callout_string_offset = GET(Fecode, 1 + 3*LINK_SIZE); - cb->callout_string = Fecode + (1 + 4*LINK_SIZE) + 1; - cb->callout_string_length = - *lengthptr - (1 + 4*LINK_SIZE) - 2; - } - -save0 = callout_ovector[0]; -save1 = callout_ovector[1]; -callout_ovector[0] = callout_ovector[1] = PCRE2_UNSET; -rc = mb->callout(cb, mb->callout_data); -callout_ovector[0] = save0; -callout_ovector[1] = save1; -cb->callout_flags = 0; -return rc; -} - - - -/************************************************* -* Match a back-reference * -*************************************************/ - -/* This function is called only when it is known that the offset lies within -the offsets that have so far been used in the match. Note that in caseless -UTF-8 mode, the number of subject bytes matched may be different to the number -of reference bytes. (In theory this could also happen in UTF-16 mode, but it -seems unlikely.) - -Arguments: - offset index into the offset vector - caseless TRUE if caseless - F the current backtracking frame pointer - mb points to match block - lengthptr pointer for returning the length matched - -Returns: = 0 sucessful match; number of code units matched is set - < 0 no match - > 0 partial match -*/ - -static int -match_ref(PCRE2_SIZE offset, BOOL caseless, heapframe *F, match_block *mb, - PCRE2_SIZE *lengthptr) -{ -PCRE2_SPTR p; -PCRE2_SIZE length; -PCRE2_SPTR eptr; -PCRE2_SPTR eptr_start; - -/* Deal with an unset group. The default is no match, but there is an option to -match an empty string. */ - -if (offset >= Foffset_top || Fovector[offset] == PCRE2_UNSET) - { - if ((mb->poptions & PCRE2_MATCH_UNSET_BACKREF) != 0) - { - *lengthptr = 0; - return 0; /* Match */ - } - else return -1; /* No match */ - } - -/* Separate the caseless and UTF cases for speed. */ - -eptr = eptr_start = Feptr; -p = mb->start_subject + Fovector[offset]; -length = Fovector[offset+1] - Fovector[offset]; - -if (caseless) - { -#if defined SUPPORT_UNICODE - BOOL utf = (mb->poptions & PCRE2_UTF) != 0; - - if (utf || (mb->poptions & PCRE2_UCP) != 0) - { - PCRE2_SPTR endptr = p + length; - - /* Match characters up to the end of the reference. NOTE: the number of - code units matched may differ, because in UTF-8 there are some characters - whose upper and lower case codes have different numbers of bytes. For - example, U+023A (2 bytes in UTF-8) is the upper case version of U+2C65 (3 - bytes in UTF-8); a sequence of 3 of the former uses 6 bytes, as does a - sequence of two of the latter. It is important, therefore, to check the - length along the reference, not along the subject (earlier code did this - wrong). UCP without uses Unicode properties but without UTF encoding. */ - - while (p < endptr) - { - uint32_t c, d; - const ucd_record *ur; - if (eptr >= mb->end_subject) return 1; /* Partial match */ - - if (utf) - { - GETCHARINC(c, eptr); - GETCHARINC(d, p); - } - else - { - c = *eptr++; - d = *p++; - } - - ur = GET_UCD(d); - if (c != d && c != (uint32_t)((int)d + ur->other_case)) - { - const uint32_t *pp = PRIV(ucd_caseless_sets) + ur->caseset; - for (;;) - { - if (c < *pp) return -1; /* No match */ - if (c == *pp++) break; - } - } - } - } - else -#endif - - /* Not in UTF or UCP mode */ - { - for (; length > 0; length--) - { - uint32_t cc, cp; - if (eptr >= mb->end_subject) return 1; /* Partial match */ - cc = UCHAR21TEST(eptr); - cp = UCHAR21TEST(p); - if (TABLE_GET(cp, mb->lcc, cp) != TABLE_GET(cc, mb->lcc, cc)) - return -1; /* No match */ - p++; - eptr++; - } - } - } - -/* In the caseful case, we can just compare the code units, whether or not we -are in UTF and/or UCP mode. When partial matching, we have to do this unit by -unit. */ - -else - { - if (mb->partial != 0) - { - for (; length > 0; length--) - { - if (eptr >= mb->end_subject) return 1; /* Partial match */ - if (UCHAR21INCTEST(p) != UCHAR21INCTEST(eptr)) return -1; /* No match */ - } - } - - /* Not partial matching */ - - else - { - if ((PCRE2_SIZE)(mb->end_subject - eptr) < length) return 1; /* Partial */ - if (memcmp(p, eptr, CU2BYTES(length)) != 0) return -1; /* No match */ - eptr += length; - } - } - -*lengthptr = eptr - eptr_start; -return 0; /* Match */ -} - - - -/****************************************************************************** -******************************************************************************* - "Recursion" in the match() function - -The original match() function was highly recursive, but this proved to be the -source of a number of problems over the years, mostly because of the relatively -small system stacks that are commonly found. As new features were added to -patterns, various kludges were invented to reduce the amount of stack used, -making the code hard to understand in places. - -A version did exist that used individual frames on the heap instead of calling -match() recursively, but this ran substantially slower. The current version is -a refactoring that uses a vector of frames to remember backtracking points. -This runs no slower, and possibly even a bit faster than the original recursive -implementation. - -At first, an initial vector of size START_FRAMES_SIZE (enough for maybe 50 -frames) was allocated on the system stack. If this was not big enough, the heap -was used for a larger vector. However, it turns out that there are environments -where taking as little as 20KiB from the system stack is an embarrassment. -After another refactoring, the heap is used exclusively, but a pointer the -frames vector and its size are cached in the match_data block, so that there is -no new memory allocation if the same match_data block is used for multiple -matches (unless the frames vector has to be extended). -******************************************************************************* -******************************************************************************/ - - - - -/************************************************* -* Macros for the match() function * -*************************************************/ - -/* These macros pack up tests that are used for partial matching several times -in the code. The second one is used when we already know we are past the end of -the subject. We set the "hit end" flag if the pointer is at the end of the -subject and either (a) the pointer is past the earliest inspected character -(i.e. something has been matched, even if not part of the actual matched -string), or (b) the pattern contains a lookbehind. These are the conditions for -which adding more characters may allow the current match to continue. - -For hard partial matching, we immediately return a partial match. Otherwise, -carrying on means that a complete match on the current subject will be sought. -A partial match is returned only if no complete match can be found. */ - -#define CHECK_PARTIAL()\ - if (Feptr >= mb->end_subject) \ - { \ - SCHECK_PARTIAL(); \ - } - -#define SCHECK_PARTIAL()\ - if (mb->partial != 0 && \ - (Feptr > mb->start_used_ptr || mb->allowemptypartial)) \ - { \ - mb->hitend = TRUE; \ - if (mb->partial > 1) return PCRE2_ERROR_PARTIAL; \ - } - - -/* These macros are used to implement backtracking. They simulate a recursive -call to the match() function by means of a local vector of frames which -remember the backtracking points. */ - -#define RMATCH(ra,rb)\ - {\ - start_ecode = ra;\ - Freturn_id = rb;\ - goto MATCH_RECURSE;\ - L_##rb:;\ - } - -#define RRETURN(ra)\ - {\ - rrc = ra;\ - goto RETURN_SWITCH;\ - } - - - -/************************************************* -* Match from current position * -*************************************************/ - -/* This function is called to run one match attempt at a single starting point -in the subject. - -Performance note: It might be tempting to extract commonly used fields from the -mb structure (e.g. end_subject) into individual variables to improve -performance. Tests using gcc on a SPARC disproved this; in the first case, it -made performance worse. - -Arguments: - start_eptr starting character in subject - start_ecode starting position in compiled code - top_bracket number of capturing parentheses in the pattern - frame_size size of each backtracking frame - match_data pointer to the match_data block - mb pointer to "static" variables block - -Returns: MATCH_MATCH if matched ) these values are >= 0 - MATCH_NOMATCH if failed to match ) - negative MATCH_xxx value for PRUNE, SKIP, etc - negative PCRE2_ERROR_xxx value if aborted by an error condition - (e.g. stopped by repeated call or depth limit) -*/ - -static int -match(PCRE2_SPTR start_eptr, PCRE2_SPTR start_ecode, uint16_t top_bracket, - PCRE2_SIZE frame_size, pcre2_match_data *match_data, match_block *mb) -{ -/* Frame-handling variables */ - -heapframe *F; /* Current frame pointer */ -heapframe *N = NULL; /* Temporary frame pointers */ -heapframe *P = NULL; - -heapframe *frames_top; /* End of frames vector */ -heapframe *assert_accept_frame = NULL; /* For passing back a frame with captures */ -PCRE2_SIZE heapframes_size; /* Usable size of frames vector */ -PCRE2_SIZE frame_copy_size; /* Amount to copy when creating a new frame */ - -/* Local variables that do not need to be preserved over calls to RRMATCH(). */ - -PCRE2_SPTR bracode; /* Temp pointer to start of group */ -PCRE2_SIZE offset; /* Used for group offsets */ -PCRE2_SIZE length; /* Used for various length calculations */ - -int rrc; /* Return from functions & backtracking "recursions" */ -#ifdef SUPPORT_UNICODE -int proptype; /* Type of character property */ -#endif - -uint32_t i; /* Used for local loops */ -uint32_t fc; /* Character values */ -uint32_t number; /* Used for group and other numbers */ -uint32_t reptype = 0; /* Type of repetition (0 to avoid compiler warning) */ -uint32_t group_frame_type; /* Specifies type for new group frames */ - -BOOL condition; /* Used in conditional groups */ -BOOL cur_is_word; /* Used in "word" tests */ -BOOL prev_is_word; /* Used in "word" tests */ - -/* UTF and UCP flags */ - -#ifdef SUPPORT_UNICODE -BOOL utf = (mb->poptions & PCRE2_UTF) != 0; -BOOL ucp = (mb->poptions & PCRE2_UCP) != 0; -#else -BOOL utf = FALSE; /* Required for convenience even when no Unicode support */ -#endif - -/* This is the length of the last part of a backtracking frame that must be -copied when a new frame is created. */ - -frame_copy_size = frame_size - offsetof(heapframe, eptr); - -/* Set up the first frame and the end of the frames vector. We set the local -heapframes_size to the usuable amount of the vector, that is, a whole number of -frames. */ - -F = match_data->heapframes; -heapframes_size = (match_data->heapframes_size / frame_size) * frame_size; -frames_top = (heapframe *)((char *)F + heapframes_size); - -Frdepth = 0; /* "Recursion" depth */ -Fcapture_last = 0; /* Number of most recent capture */ -Fcurrent_recurse = RECURSE_UNSET; /* Not pattern recursing. */ -Fstart_match = Feptr = start_eptr; /* Current data pointer and start match */ -Fmark = NULL; /* Most recent mark */ -Foffset_top = 0; /* End of captures within the frame */ -Flast_group_offset = PCRE2_UNSET; /* Saved frame of most recent group */ -group_frame_type = 0; /* Not a start of group frame */ -goto NEW_FRAME; /* Start processing with this frame */ - -/* Come back here when we want to create a new frame for remembering a -backtracking point. */ - -MATCH_RECURSE: - -/* Set up a new backtracking frame. If the vector is full, get a new one, -doubling the size, but constrained by the heap limit (which is in KiB). */ - -N = (heapframe *)((char *)F + frame_size); -if (N >= frames_top) - { - heapframe *new; - PCRE2_SIZE newsize = match_data->heapframes_size * 2; - - if (newsize > mb->heap_limit) - { - PCRE2_SIZE maxsize = (mb->heap_limit/frame_size) * frame_size; - if (match_data->heapframes_size >= maxsize) return PCRE2_ERROR_HEAPLIMIT; - newsize = maxsize; - } - - new = match_data->memctl.malloc(newsize, match_data->memctl.memory_data); - if (new == NULL) return PCRE2_ERROR_NOMEMORY; - memcpy(new, match_data->heapframes, heapframes_size); - - F = (heapframe *)((char *)new + ((char *)F - (char *)match_data->heapframes)); - N = (heapframe *)((char *)F + frame_size); - - match_data->memctl.free(match_data->heapframes, match_data->memctl.memory_data); - match_data->heapframes = new; - match_data->heapframes_size = newsize; - - heapframes_size = (newsize / frame_size) * frame_size; - frames_top = (heapframe *)((char *)new + heapframes_size); - } - -#ifdef DEBUG_SHOW_RMATCH -fprintf(stderr, "++ RMATCH %2d frame=%d", Freturn_id, Frdepth + 1); -if (group_frame_type != 0) - { - fprintf(stderr, " type=%x ", group_frame_type); - switch (GF_IDMASK(group_frame_type)) - { - case GF_CAPTURE: - fprintf(stderr, "capture=%d", GF_DATAMASK(group_frame_type)); - break; - - case GF_NOCAPTURE: - fprintf(stderr, "nocapture op=%d", GF_DATAMASK(group_frame_type)); - break; - - case GF_CONDASSERT: - fprintf(stderr, "condassert op=%d", GF_DATAMASK(group_frame_type)); - break; - - case GF_RECURSE: - fprintf(stderr, "recurse=%d", GF_DATAMASK(group_frame_type)); - break; - - default: - fprintf(stderr, "*** unknown ***"); - break; - } - } -fprintf(stderr, "\n"); -#endif - -/* Copy those fields that must be copied into the new frame, increase the -"recursion" depth (i.e. the new frame's index) and then make the new frame -current. */ - -memcpy((char *)N + offsetof(heapframe, eptr), - (char *)F + offsetof(heapframe, eptr), - frame_copy_size); - -N->rdepth = Frdepth + 1; -F = N; - -/* Carry on processing with a new frame. */ - -NEW_FRAME: -Fgroup_frame_type = group_frame_type; -Fecode = start_ecode; /* Starting code pointer */ -Fback_frame = frame_size; /* Default is go back one frame */ - -/* If this is a special type of group frame, remember its offset for quick -access at the end of the group. If this is a recursion, set a new current -recursion value. */ - -if (group_frame_type != 0) - { - Flast_group_offset = (char *)F - (char *)match_data->heapframes; - if (GF_IDMASK(group_frame_type) == GF_RECURSE) - Fcurrent_recurse = GF_DATAMASK(group_frame_type); - group_frame_type = 0; - } - - -/* ========================================================================= */ -/* This is the main processing loop. First check that we haven't recorded too -many backtracks (search tree is too large), or that we haven't exceeded the -recursive depth limit (used too many backtracking frames). If not, process the -opcodes. */ - -if (mb->match_call_count++ >= mb->match_limit) return PCRE2_ERROR_MATCHLIMIT; -if (Frdepth >= mb->match_limit_depth) return PCRE2_ERROR_DEPTHLIMIT; - -for (;;) - { -#ifdef DEBUG_SHOW_OPS -fprintf(stderr, "++ op=%d\n", *Fecode); -#endif - - Fop = (uint8_t)(*Fecode); /* Cast needed for 16-bit and 32-bit modes */ - switch(Fop) - { - /* ===================================================================== */ - /* Before OP_ACCEPT there may be any number of OP_CLOSE opcodes, to close - any currently open capturing brackets. Unlike reaching the end of a group, - where we know the starting frame is at the top of the chained frames, in - this case we have to search back for the relevant frame in case other types - of group that use chained frames have intervened. Multiple OP_CLOSEs always - come innermost first, which matches the chain order. We can ignore this in - a recursion, because captures are not passed out of recursions. */ - - case OP_CLOSE: - if (Fcurrent_recurse == RECURSE_UNSET) - { - number = GET2(Fecode, 1); - offset = Flast_group_offset; - for(;;) - { - if (offset == PCRE2_UNSET) return PCRE2_ERROR_INTERNAL; - N = (heapframe *)((char *)match_data->heapframes + offset); - P = (heapframe *)((char *)N - frame_size); - if (N->group_frame_type == (GF_CAPTURE | number)) break; - offset = P->last_group_offset; - } - offset = (number << 1) - 2; - Fcapture_last = number; - Fovector[offset] = P->eptr - mb->start_subject; - Fovector[offset+1] = Feptr - mb->start_subject; - if (offset >= Foffset_top) Foffset_top = offset + 2; - } - Fecode += PRIV(OP_lengths)[*Fecode]; - break; - - - /* ===================================================================== */ - /* Real or forced end of the pattern, assertion, or recursion. In an - assertion ACCEPT, update the last used pointer and remember the current - frame so that the captures and mark can be fished out of it. */ - - case OP_ASSERT_ACCEPT: - if (Feptr > mb->last_used_ptr) mb->last_used_ptr = Feptr; - assert_accept_frame = F; - RRETURN(MATCH_ACCEPT); - - /* If recursing, we have to find the most recent recursion. */ - - case OP_ACCEPT: - case OP_END: - - /* Handle end of a recursion. */ - - if (Fcurrent_recurse != RECURSE_UNSET) - { - offset = Flast_group_offset; - for(;;) - { - if (offset == PCRE2_UNSET) return PCRE2_ERROR_INTERNAL; - N = (heapframe *)((char *)match_data->heapframes + offset); - P = (heapframe *)((char *)N - frame_size); - if (GF_IDMASK(N->group_frame_type) == GF_RECURSE) break; - offset = P->last_group_offset; - } - - /* N is now the frame of the recursion; the previous frame is at the - OP_RECURSE position. Go back there, copying the current subject position - and mark, and the start_match position (\K might have changed it), and - then move on past the OP_RECURSE. */ - - P->eptr = Feptr; - P->mark = Fmark; - P->start_match = Fstart_match; - F = P; - Fecode += 1 + LINK_SIZE; - continue; - } - - /* Not a recursion. Fail for an empty string match if either PCRE2_NOTEMPTY - is set, or if PCRE2_NOTEMPTY_ATSTART is set and we have matched at the - start of the subject. In both cases, backtracking will then try other - alternatives, if any. */ - - if (Feptr == Fstart_match && - ((mb->moptions & PCRE2_NOTEMPTY) != 0 || - ((mb->moptions & PCRE2_NOTEMPTY_ATSTART) != 0 && - Fstart_match == mb->start_subject + mb->start_offset))) - RRETURN(MATCH_NOMATCH); - - /* Also fail if PCRE2_ENDANCHORED is set and the end of the match is not - the end of the subject. After (*ACCEPT) we fail the entire match (at this - position) but backtrack on reaching the end of the pattern. */ - - if (Feptr < mb->end_subject && - ((mb->moptions | mb->poptions) & PCRE2_ENDANCHORED) != 0) - { - if (Fop == OP_END) RRETURN(MATCH_NOMATCH); - return MATCH_NOMATCH; - } - - /* We have a successful match of the whole pattern. Record the result and - then do a direct return from the function. If there is space in the offset - vector, set any pairs that follow the highest-numbered captured string but - are less than the number of capturing groups in the pattern to PCRE2_UNSET. - It is documented that this happens. "Gaps" are set to PCRE2_UNSET - dynamically. It is only those at the end that need setting here. */ - - mb->end_match_ptr = Feptr; /* Record where we ended */ - mb->end_offset_top = Foffset_top; /* and how many extracts were taken */ - mb->mark = Fmark; /* and the last success mark */ - if (Feptr > mb->last_used_ptr) mb->last_used_ptr = Feptr; - - match_data->ovector[0] = Fstart_match - mb->start_subject; - match_data->ovector[1] = Feptr - mb->start_subject; - - /* Set i to the smaller of the sizes of the external and frame ovectors. */ - - i = 2 * ((top_bracket + 1 > match_data->oveccount)? - match_data->oveccount : top_bracket + 1); - memcpy(match_data->ovector + 2, Fovector, (i - 2) * sizeof(PCRE2_SIZE)); - while (--i >= Foffset_top + 2) match_data->ovector[i] = PCRE2_UNSET; - return MATCH_MATCH; /* Note: NOT RRETURN */ - - - /*===================================================================== */ - /* Match any single character type except newline; have to take care with - CRLF newlines and partial matching. */ - - case OP_ANY: - if (IS_NEWLINE(Feptr)) RRETURN(MATCH_NOMATCH); - if (mb->partial != 0 && - Feptr == mb->end_subject - 1 && - NLBLOCK->nltype == NLTYPE_FIXED && - NLBLOCK->nllen == 2 && - UCHAR21TEST(Feptr) == NLBLOCK->nl[0]) - { - mb->hitend = TRUE; - if (mb->partial > 1) return PCRE2_ERROR_PARTIAL; - } - /* Fall through */ - - /* Match any single character whatsoever. */ - - case OP_ALLANY: - if (Feptr >= mb->end_subject) /* DO NOT merge the Feptr++ here; it must */ - { /* not be updated before SCHECK_PARTIAL. */ - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - Feptr++; -#ifdef SUPPORT_UNICODE - if (utf) ACROSSCHAR(Feptr < mb->end_subject, Feptr, Feptr++); -#endif - Fecode++; - break; - - - /* ===================================================================== */ - /* Match a single code unit, even in UTF mode. This opcode really does - match any code unit, even newline. (It really should be called ANYCODEUNIT, - of course - the byte name is from pre-16 bit days.) */ - - case OP_ANYBYTE: - if (Feptr >= mb->end_subject) /* DO NOT merge the Feptr++ here; it must */ - { /* not be updated before SCHECK_PARTIAL. */ - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - Feptr++; - Fecode++; - break; - - - /* ===================================================================== */ - /* Match a single character, casefully */ - - case OP_CHAR: -#ifdef SUPPORT_UNICODE - if (utf) - { - Flength = 1; - Fecode++; - GETCHARLEN(fc, Fecode, Flength); - if (Flength > (PCRE2_SIZE)(mb->end_subject - Feptr)) - { - CHECK_PARTIAL(); /* Not SCHECK_PARTIAL() */ - RRETURN(MATCH_NOMATCH); - } - for (; Flength > 0; Flength--) - { - if (*Fecode++ != UCHAR21INC(Feptr)) RRETURN(MATCH_NOMATCH); - } - } - else -#endif - - /* Not UTF mode */ - { - if (mb->end_subject - Feptr < 1) - { - SCHECK_PARTIAL(); /* This one can use SCHECK_PARTIAL() */ - RRETURN(MATCH_NOMATCH); - } - if (Fecode[1] != *Feptr++) RRETURN(MATCH_NOMATCH); - Fecode += 2; - } - break; - - - /* ===================================================================== */ - /* Match a single character, caselessly. If we are at the end of the - subject, give up immediately. We get here only when the pattern character - has at most one other case. Characters with more than two cases are coded - as OP_PROP with the pseudo-property PT_CLIST. */ - - case OP_CHARI: - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - -#ifdef SUPPORT_UNICODE - if (utf) - { - Flength = 1; - Fecode++; - GETCHARLEN(fc, Fecode, Flength); - - /* If the pattern character's value is < 128, we know that its other case - (if any) is also < 128 (and therefore only one code unit long in all - code-unit widths), so we can use the fast lookup table. We checked above - that there is at least one character left in the subject. */ - - if (fc < 128) - { - uint32_t cc = UCHAR21(Feptr); - if (mb->lcc[fc] != TABLE_GET(cc, mb->lcc, cc)) RRETURN(MATCH_NOMATCH); - Fecode++; - Feptr++; - } - - /* Otherwise we must pick up the subject character and use Unicode - property support to test its other case. Note that we cannot use the - value of "Flength" to check for sufficient bytes left, because the other - case of the character may have more or fewer code units. */ - - else - { - uint32_t dc; - GETCHARINC(dc, Feptr); - Fecode += Flength; - if (dc != fc && dc != UCD_OTHERCASE(fc)) RRETURN(MATCH_NOMATCH); - } - } - - /* If UCP is set without UTF we must do the same as above, but with one - character per code unit. */ - - else if (ucp) - { - uint32_t cc = UCHAR21(Feptr); - fc = Fecode[1]; - if (fc < 128) - { - if (mb->lcc[fc] != TABLE_GET(cc, mb->lcc, cc)) RRETURN(MATCH_NOMATCH); - } - else - { - if (cc != fc && cc != UCD_OTHERCASE(fc)) RRETURN(MATCH_NOMATCH); - } - Feptr++; - Fecode += 2; - } - - else -#endif /* SUPPORT_UNICODE */ - - /* Not UTF or UCP mode; use the table for characters < 256. */ - { - if (TABLE_GET(Fecode[1], mb->lcc, Fecode[1]) - != TABLE_GET(*Feptr, mb->lcc, *Feptr)) RRETURN(MATCH_NOMATCH); - Feptr++; - Fecode += 2; - } - break; - - - /* ===================================================================== */ - /* Match not a single character. */ - - case OP_NOT: - case OP_NOTI: - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - -#ifdef SUPPORT_UNICODE - if (utf) - { - uint32_t ch; - Fecode++; - GETCHARINC(ch, Fecode); - GETCHARINC(fc, Feptr); - if (ch == fc) - { - RRETURN(MATCH_NOMATCH); /* Caseful match */ - } - else if (Fop == OP_NOTI) /* If caseless */ - { - if (ch > 127) - ch = UCD_OTHERCASE(ch); - else - ch = (mb->fcc)[ch]; - if (ch == fc) RRETURN(MATCH_NOMATCH); - } - } - - /* UCP without UTF is as above, but with one character per code unit. */ - - else if (ucp) - { - uint32_t ch; - fc = UCHAR21INC(Feptr); - ch = Fecode[1]; - Fecode += 2; - - if (ch == fc) - { - RRETURN(MATCH_NOMATCH); /* Caseful match */ - } - else if (Fop == OP_NOTI) /* If caseless */ - { - if (ch > 127) - ch = UCD_OTHERCASE(ch); - else - ch = (mb->fcc)[ch]; - if (ch == fc) RRETURN(MATCH_NOMATCH); - } - } - - else -#endif /* SUPPORT_UNICODE */ - - /* Neither UTF nor UCP is set */ - - { - uint32_t ch = Fecode[1]; - fc = UCHAR21INC(Feptr); - if (ch == fc || (Fop == OP_NOTI && TABLE_GET(ch, mb->fcc, ch) == fc)) - RRETURN(MATCH_NOMATCH); - Fecode += 2; - } - break; - - - /* ===================================================================== */ - /* Match a single character repeatedly. */ - -#define Loclength F->temp_size -#define Lstart_eptr F->temp_sptr[0] -#define Lcharptr F->temp_sptr[1] -#define Lmin F->temp_32[0] -#define Lmax F->temp_32[1] -#define Lc F->temp_32[2] -#define Loc F->temp_32[3] - - case OP_EXACT: - case OP_EXACTI: - Lmin = Lmax = GET2(Fecode, 1); - Fecode += 1 + IMM2_SIZE; - goto REPEATCHAR; - - case OP_POSUPTO: - case OP_POSUPTOI: - reptype = REPTYPE_POS; - Lmin = 0; - Lmax = GET2(Fecode, 1); - Fecode += 1 + IMM2_SIZE; - goto REPEATCHAR; - - case OP_UPTO: - case OP_UPTOI: - reptype = REPTYPE_MAX; - Lmin = 0; - Lmax = GET2(Fecode, 1); - Fecode += 1 + IMM2_SIZE; - goto REPEATCHAR; - - case OP_MINUPTO: - case OP_MINUPTOI: - reptype = REPTYPE_MIN; - Lmin = 0; - Lmax = GET2(Fecode, 1); - Fecode += 1 + IMM2_SIZE; - goto REPEATCHAR; - - case OP_POSSTAR: - case OP_POSSTARI: - reptype = REPTYPE_POS; - Lmin = 0; - Lmax = UINT32_MAX; - Fecode++; - goto REPEATCHAR; - - case OP_POSPLUS: - case OP_POSPLUSI: - reptype = REPTYPE_POS; - Lmin = 1; - Lmax = UINT32_MAX; - Fecode++; - goto REPEATCHAR; - - case OP_POSQUERY: - case OP_POSQUERYI: - reptype = REPTYPE_POS; - Lmin = 0; - Lmax = 1; - Fecode++; - goto REPEATCHAR; - - case OP_STAR: - case OP_STARI: - case OP_MINSTAR: - case OP_MINSTARI: - case OP_PLUS: - case OP_PLUSI: - case OP_MINPLUS: - case OP_MINPLUSI: - case OP_QUERY: - case OP_QUERYI: - case OP_MINQUERY: - case OP_MINQUERYI: - fc = *Fecode++ - ((Fop < OP_STARI)? OP_STAR : OP_STARI); - Lmin = rep_min[fc]; - Lmax = rep_max[fc]; - reptype = rep_typ[fc]; - - /* Common code for all repeated single-character matches. We first check - for the minimum number of characters. If the minimum equals the maximum, we - are done. Otherwise, if minimizing, check the rest of the pattern for a - match; if there isn't one, advance up to the maximum, one character at a - time. - - If maximizing, advance up to the maximum number of matching characters, - until Feptr is past the end of the maximum run. If possessive, we are - then done (no backing up). Otherwise, match at this position; anything - other than no match is immediately returned. For nomatch, back up one - character, unless we are matching \R and the last thing matched was - \r\n, in which case, back up two code units until we reach the first - optional character position. - - The various UTF/non-UTF and caseful/caseless cases are handled separately, - for speed. */ - - REPEATCHAR: -#ifdef SUPPORT_UNICODE - if (utf) - { - Flength = 1; - Lcharptr = Fecode; - GETCHARLEN(fc, Fecode, Flength); - Fecode += Flength; - - /* Handle multi-code-unit character matching, caseful and caseless. */ - - if (Flength > 1) - { - uint32_t othercase; - - if (Fop >= OP_STARI && /* Caseless */ - (othercase = UCD_OTHERCASE(fc)) != fc) - Loclength = PRIV(ord2utf)(othercase, Foccu); - else Loclength = 0; - - for (i = 1; i <= Lmin; i++) - { - if (Feptr <= mb->end_subject - Flength && - memcmp(Feptr, Lcharptr, CU2BYTES(Flength)) == 0) Feptr += Flength; - else if (Loclength > 0 && - Feptr <= mb->end_subject - Loclength && - memcmp(Feptr, Foccu, CU2BYTES(Loclength)) == 0) - Feptr += Loclength; - else - { - CHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - } - - if (Lmin == Lmax) continue; - - if (reptype == REPTYPE_MIN) - { - for (;;) - { - RMATCH(Fecode, RM202); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); - if (Feptr <= mb->end_subject - Flength && - memcmp(Feptr, Lcharptr, CU2BYTES(Flength)) == 0) Feptr += Flength; - else if (Loclength > 0 && - Feptr <= mb->end_subject - Loclength && - memcmp(Feptr, Foccu, CU2BYTES(Loclength)) == 0) - Feptr += Loclength; - else - { - CHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - } - /* Control never gets here */ - } - - else /* Maximize */ - { - Lstart_eptr = Feptr; - for (i = Lmin; i < Lmax; i++) - { - if (Feptr <= mb->end_subject - Flength && - memcmp(Feptr, Lcharptr, CU2BYTES(Flength)) == 0) - Feptr += Flength; - else if (Loclength > 0 && - Feptr <= mb->end_subject - Loclength && - memcmp(Feptr, Foccu, CU2BYTES(Loclength)) == 0) - Feptr += Loclength; - else - { - CHECK_PARTIAL(); - break; - } - } - - /* After \C in UTF mode, Lstart_eptr might be in the middle of a - Unicode character. Use <= Lstart_eptr to ensure backtracking doesn't - go too far. */ - - if (reptype != REPTYPE_POS) for(;;) - { - if (Feptr <= Lstart_eptr) break; - RMATCH(Fecode, RM203); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - Feptr--; - BACKCHAR(Feptr); - } - } - break; /* End of repeated wide character handling */ - } - - /* Length of UTF character is 1. Put it into the preserved variable and - fall through to the non-UTF code. */ - - Lc = fc; - } - else -#endif /* SUPPORT_UNICODE */ - - /* When not in UTF mode, load a single-code-unit character. Then proceed as - above, using Unicode casing if either UTF or UCP is set. */ - - Lc = *Fecode++; - - /* Caseless comparison */ - - if (Fop >= OP_STARI) - { -#if PCRE2_CODE_UNIT_WIDTH == 8 -#ifdef SUPPORT_UNICODE - if (ucp && !utf && Lc > 127) Loc = UCD_OTHERCASE(Lc); - else -#endif /* SUPPORT_UNICODE */ - /* Lc will be < 128 in UTF-8 mode. */ - Loc = mb->fcc[Lc]; -#else /* 16-bit & 32-bit */ -#ifdef SUPPORT_UNICODE - if ((utf || ucp) && Lc > 127) Loc = UCD_OTHERCASE(Lc); - else -#endif /* SUPPORT_UNICODE */ - Loc = TABLE_GET(Lc, mb->fcc, Lc); -#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */ - - for (i = 1; i <= Lmin; i++) - { - uint32_t cc; /* Faster than PCRE2_UCHAR */ - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - cc = UCHAR21TEST(Feptr); - if (Lc != cc && Loc != cc) RRETURN(MATCH_NOMATCH); - Feptr++; - } - if (Lmin == Lmax) continue; - - if (reptype == REPTYPE_MIN) - { - for (;;) - { - uint32_t cc; /* Faster than PCRE2_UCHAR */ - RMATCH(Fecode, RM25); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - cc = UCHAR21TEST(Feptr); - if (Lc != cc && Loc != cc) RRETURN(MATCH_NOMATCH); - Feptr++; - } - /* Control never gets here */ - } - - else /* Maximize */ - { - Lstart_eptr = Feptr; - for (i = Lmin; i < Lmax; i++) - { - uint32_t cc; /* Faster than PCRE2_UCHAR */ - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - cc = UCHAR21TEST(Feptr); - if (Lc != cc && Loc != cc) break; - Feptr++; - } - if (reptype != REPTYPE_POS) for (;;) - { - if (Feptr == Lstart_eptr) break; - RMATCH(Fecode, RM26); - Feptr--; - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - } - } - } - - /* Caseful comparisons (includes all multi-byte characters) */ - - else - { - for (i = 1; i <= Lmin; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - if (Lc != UCHAR21INCTEST(Feptr)) RRETURN(MATCH_NOMATCH); - } - - if (Lmin == Lmax) continue; - - if (reptype == REPTYPE_MIN) - { - for (;;) - { - RMATCH(Fecode, RM27); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - if (Lc != UCHAR21INCTEST(Feptr)) RRETURN(MATCH_NOMATCH); - } - /* Control never gets here */ - } - else /* Maximize */ - { - Lstart_eptr = Feptr; - for (i = Lmin; i < Lmax; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - - if (Lc != UCHAR21TEST(Feptr)) break; - Feptr++; - } - - if (reptype != REPTYPE_POS) for (;;) - { - if (Feptr <= Lstart_eptr) break; - RMATCH(Fecode, RM28); - Feptr--; - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - } - } - } - break; - -#undef Loclength -#undef Lstart_eptr -#undef Lcharptr -#undef Lmin -#undef Lmax -#undef Lc -#undef Loc - - - /* ===================================================================== */ - /* Match a negated single one-byte character repeatedly. This is almost a - repeat of the code for a repeated single character, but I haven't found a - nice way of commoning these up that doesn't require a test of the - positive/negative option for each character match. Maybe that wouldn't add - very much to the time taken, but character matching *is* what this is all - about... */ - -#define Lstart_eptr F->temp_sptr[0] -#define Lmin F->temp_32[0] -#define Lmax F->temp_32[1] -#define Lc F->temp_32[2] -#define Loc F->temp_32[3] - - case OP_NOTEXACT: - case OP_NOTEXACTI: - Lmin = Lmax = GET2(Fecode, 1); - Fecode += 1 + IMM2_SIZE; - goto REPEATNOTCHAR; - - case OP_NOTUPTO: - case OP_NOTUPTOI: - Lmin = 0; - Lmax = GET2(Fecode, 1); - reptype = REPTYPE_MAX; - Fecode += 1 + IMM2_SIZE; - goto REPEATNOTCHAR; - - case OP_NOTMINUPTO: - case OP_NOTMINUPTOI: - Lmin = 0; - Lmax = GET2(Fecode, 1); - reptype = REPTYPE_MIN; - Fecode += 1 + IMM2_SIZE; - goto REPEATNOTCHAR; - - case OP_NOTPOSSTAR: - case OP_NOTPOSSTARI: - reptype = REPTYPE_POS; - Lmin = 0; - Lmax = UINT32_MAX; - Fecode++; - goto REPEATNOTCHAR; - - case OP_NOTPOSPLUS: - case OP_NOTPOSPLUSI: - reptype = REPTYPE_POS; - Lmin = 1; - Lmax = UINT32_MAX; - Fecode++; - goto REPEATNOTCHAR; - - case OP_NOTPOSQUERY: - case OP_NOTPOSQUERYI: - reptype = REPTYPE_POS; - Lmin = 0; - Lmax = 1; - Fecode++; - goto REPEATNOTCHAR; - - case OP_NOTPOSUPTO: - case OP_NOTPOSUPTOI: - reptype = REPTYPE_POS; - Lmin = 0; - Lmax = GET2(Fecode, 1); - Fecode += 1 + IMM2_SIZE; - goto REPEATNOTCHAR; - - case OP_NOTSTAR: - case OP_NOTSTARI: - case OP_NOTMINSTAR: - case OP_NOTMINSTARI: - case OP_NOTPLUS: - case OP_NOTPLUSI: - case OP_NOTMINPLUS: - case OP_NOTMINPLUSI: - case OP_NOTQUERY: - case OP_NOTQUERYI: - case OP_NOTMINQUERY: - case OP_NOTMINQUERYI: - fc = *Fecode++ - ((Fop >= OP_NOTSTARI)? OP_NOTSTARI: OP_NOTSTAR); - Lmin = rep_min[fc]; - Lmax = rep_max[fc]; - reptype = rep_typ[fc]; - - /* Common code for all repeated single-character non-matches. */ - - REPEATNOTCHAR: - GETCHARINCTEST(Lc, Fecode); - - /* The code is duplicated for the caseless and caseful cases, for speed, - since matching characters is likely to be quite common. First, ensure the - minimum number of matches are present. If Lmin = Lmax, we are done. - Otherwise, if minimizing, keep trying the rest of the expression and - advancing one matching character if failing, up to the maximum. - Alternatively, if maximizing, find the maximum number of characters and - work backwards. */ - - if (Fop >= OP_NOTSTARI) /* Caseless */ - { -#ifdef SUPPORT_UNICODE - if ((utf || ucp) && Lc > 127) - Loc = UCD_OTHERCASE(Lc); - else -#endif /* SUPPORT_UNICODE */ - - Loc = TABLE_GET(Lc, mb->fcc, Lc); /* Other case from table */ - -#ifdef SUPPORT_UNICODE - if (utf) - { - uint32_t d; - for (i = 1; i <= Lmin; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINC(d, Feptr); - if (Lc == d || Loc == d) RRETURN(MATCH_NOMATCH); - } - } - else -#endif /* SUPPORT_UNICODE */ - - /* Not UTF mode */ - { - for (i = 1; i <= Lmin; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - if (Lc == *Feptr || Loc == *Feptr) RRETURN(MATCH_NOMATCH); - Feptr++; - } - } - - if (Lmin == Lmax) continue; /* Finished for exact count */ - - if (reptype == REPTYPE_MIN) - { -#ifdef SUPPORT_UNICODE - if (utf) - { - uint32_t d; - for (;;) - { - RMATCH(Fecode, RM204); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINC(d, Feptr); - if (Lc == d || Loc == d) RRETURN(MATCH_NOMATCH); - } - } - else -#endif /*SUPPORT_UNICODE */ - - /* Not UTF mode */ - { - for (;;) - { - RMATCH(Fecode, RM29); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - if (Lc == *Feptr || Loc == *Feptr) RRETURN(MATCH_NOMATCH); - Feptr++; - } - } - /* Control never gets here */ - } - - /* Maximize case */ - - else - { - Lstart_eptr = Feptr; - -#ifdef SUPPORT_UNICODE - if (utf) - { - uint32_t d; - for (i = Lmin; i < Lmax; i++) - { - int len = 1; - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - GETCHARLEN(d, Feptr, len); - if (Lc == d || Loc == d) break; - Feptr += len; - } - - /* After \C in UTF mode, Lstart_eptr might be in the middle of a - Unicode character. Use <= Lstart_eptr to ensure backtracking doesn't - go too far. */ - - if (reptype != REPTYPE_POS) for(;;) - { - if (Feptr <= Lstart_eptr) break; - RMATCH(Fecode, RM205); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - Feptr--; - BACKCHAR(Feptr); - } - } - else -#endif /* SUPPORT_UNICODE */ - - /* Not UTF mode */ - { - for (i = Lmin; i < Lmax; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - if (Lc == *Feptr || Loc == *Feptr) break; - Feptr++; - } - if (reptype != REPTYPE_POS) for (;;) - { - if (Feptr == Lstart_eptr) break; - RMATCH(Fecode, RM30); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - Feptr--; - } - } - } - } - - /* Caseful comparisons */ - - else - { -#ifdef SUPPORT_UNICODE - if (utf) - { - uint32_t d; - for (i = 1; i <= Lmin; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINC(d, Feptr); - if (Lc == d) RRETURN(MATCH_NOMATCH); - } - } - else -#endif - /* Not UTF mode */ - { - for (i = 1; i <= Lmin; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - if (Lc == *Feptr++) RRETURN(MATCH_NOMATCH); - } - } - - if (Lmin == Lmax) continue; - - if (reptype == REPTYPE_MIN) - { -#ifdef SUPPORT_UNICODE - if (utf) - { - uint32_t d; - for (;;) - { - RMATCH(Fecode, RM206); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINC(d, Feptr); - if (Lc == d) RRETURN(MATCH_NOMATCH); - } - } - else -#endif - /* Not UTF mode */ - { - for (;;) - { - RMATCH(Fecode, RM31); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - if (Lc == *Feptr++) RRETURN(MATCH_NOMATCH); - } - } - /* Control never gets here */ - } - - /* Maximize case */ - - else - { - Lstart_eptr = Feptr; - -#ifdef SUPPORT_UNICODE - if (utf) - { - uint32_t d; - for (i = Lmin; i < Lmax; i++) - { - int len = 1; - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - GETCHARLEN(d, Feptr, len); - if (Lc == d) break; - Feptr += len; - } - - /* After \C in UTF mode, Lstart_eptr might be in the middle of a - Unicode character. Use <= Lstart_eptr to ensure backtracking doesn't - go too far. */ - - if (reptype != REPTYPE_POS) for(;;) - { - if (Feptr <= Lstart_eptr) break; - RMATCH(Fecode, RM207); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - Feptr--; - BACKCHAR(Feptr); - } - } - else -#endif - /* Not UTF mode */ - { - for (i = Lmin; i < Lmax; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - if (Lc == *Feptr) break; - Feptr++; - } - if (reptype != REPTYPE_POS) for (;;) - { - if (Feptr == Lstart_eptr) break; - RMATCH(Fecode, RM32); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - Feptr--; - } - } - } - } - break; - -#undef Lstart_eptr -#undef Lmin -#undef Lmax -#undef Lc -#undef Loc - - - /* ===================================================================== */ - /* Match a bit-mapped character class, possibly repeatedly. These opcodes - are used when all the characters in the class have values in the range - 0-255, and either the matching is caseful, or the characters are in the - range 0-127 when UTF processing is enabled. The only difference between - OP_CLASS and OP_NCLASS occurs when a data character outside the range is - encountered. */ - -#define Lmin F->temp_32[0] -#define Lmax F->temp_32[1] -#define Lstart_eptr F->temp_sptr[0] -#define Lbyte_map_address F->temp_sptr[1] -#define Lbyte_map ((unsigned char *)Lbyte_map_address) - - case OP_NCLASS: - case OP_CLASS: - { - Lbyte_map_address = Fecode + 1; /* Save for matching */ - Fecode += 1 + (32 / sizeof(PCRE2_UCHAR)); /* Advance past the item */ - - /* Look past the end of the item to see if there is repeat information - following. Then obey similar code to character type repeats. */ - - switch (*Fecode) - { - case OP_CRSTAR: - case OP_CRMINSTAR: - case OP_CRPLUS: - case OP_CRMINPLUS: - case OP_CRQUERY: - case OP_CRMINQUERY: - case OP_CRPOSSTAR: - case OP_CRPOSPLUS: - case OP_CRPOSQUERY: - fc = *Fecode++ - OP_CRSTAR; - Lmin = rep_min[fc]; - Lmax = rep_max[fc]; - reptype = rep_typ[fc]; - break; - - case OP_CRRANGE: - case OP_CRMINRANGE: - case OP_CRPOSRANGE: - Lmin = GET2(Fecode, 1); - Lmax = GET2(Fecode, 1 + IMM2_SIZE); - if (Lmax == 0) Lmax = UINT32_MAX; /* Max 0 => infinity */ - reptype = rep_typ[*Fecode - OP_CRSTAR]; - Fecode += 1 + 2 * IMM2_SIZE; - break; - - default: /* No repeat follows */ - Lmin = Lmax = 1; - break; - } - - /* First, ensure the minimum number of matches are present. */ - -#ifdef SUPPORT_UNICODE - if (utf) - { - for (i = 1; i <= Lmin; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINC(fc, Feptr); - if (fc > 255) - { - if (Fop == OP_CLASS) RRETURN(MATCH_NOMATCH); - } - else - if ((Lbyte_map[fc/8] & (1u << (fc&7))) == 0) RRETURN(MATCH_NOMATCH); - } - } - else -#endif - /* Not UTF mode */ - { - for (i = 1; i <= Lmin; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - fc = *Feptr++; -#if PCRE2_CODE_UNIT_WIDTH != 8 - if (fc > 255) - { - if (Fop == OP_CLASS) RRETURN(MATCH_NOMATCH); - } - else -#endif - if ((Lbyte_map[fc/8] & (1u << (fc&7))) == 0) RRETURN(MATCH_NOMATCH); - } - } - - /* If Lmax == Lmin we are done. Continue with main loop. */ - - if (Lmin == Lmax) continue; - - /* If minimizing, keep testing the rest of the expression and advancing - the pointer while it matches the class. */ - - if (reptype == REPTYPE_MIN) - { -#ifdef SUPPORT_UNICODE - if (utf) - { - for (;;) - { - RMATCH(Fecode, RM200); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINC(fc, Feptr); - if (fc > 255) - { - if (Fop == OP_CLASS) RRETURN(MATCH_NOMATCH); - } - else - if ((Lbyte_map[fc/8] & (1u << (fc&7))) == 0) RRETURN(MATCH_NOMATCH); - } - } - else -#endif - /* Not UTF mode */ - { - for (;;) - { - RMATCH(Fecode, RM23); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - fc = *Feptr++; -#if PCRE2_CODE_UNIT_WIDTH != 8 - if (fc > 255) - { - if (Fop == OP_CLASS) RRETURN(MATCH_NOMATCH); - } - else -#endif - if ((Lbyte_map[fc/8] & (1u << (fc&7))) == 0) RRETURN(MATCH_NOMATCH); - } - } - /* Control never gets here */ - } - - /* If maximizing, find the longest possible run, then work backwards. */ - - else - { - Lstart_eptr = Feptr; - -#ifdef SUPPORT_UNICODE - if (utf) - { - for (i = Lmin; i < Lmax; i++) - { - int len = 1; - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - GETCHARLEN(fc, Feptr, len); - if (fc > 255) - { - if (Fop == OP_CLASS) break; - } - else - if ((Lbyte_map[fc/8] & (1u << (fc&7))) == 0) break; - Feptr += len; - } - - if (reptype == REPTYPE_POS) continue; /* No backtracking */ - - /* After \C in UTF mode, Lstart_eptr might be in the middle of a - Unicode character. Use <= Lstart_eptr to ensure backtracking doesn't - go too far. */ - - for (;;) - { - RMATCH(Fecode, RM201); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (Feptr-- <= Lstart_eptr) break; /* Tried at original position */ - BACKCHAR(Feptr); - } - } - else -#endif - /* Not UTF mode */ - { - for (i = Lmin; i < Lmax; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - fc = *Feptr; -#if PCRE2_CODE_UNIT_WIDTH != 8 - if (fc > 255) - { - if (Fop == OP_CLASS) break; - } - else -#endif - if ((Lbyte_map[fc/8] & (1u << (fc&7))) == 0) break; - Feptr++; - } - - if (reptype == REPTYPE_POS) continue; /* No backtracking */ - - while (Feptr >= Lstart_eptr) - { - RMATCH(Fecode, RM24); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - Feptr--; - } - } - - RRETURN(MATCH_NOMATCH); - } - } - /* Control never gets here */ - -#undef Lbyte_map_address -#undef Lbyte_map -#undef Lstart_eptr -#undef Lmin -#undef Lmax - - - /* ===================================================================== */ - /* Match an extended character class. In the 8-bit library, this opcode is - encountered only when UTF-8 mode mode is supported. In the 16-bit and - 32-bit libraries, codepoints greater than 255 may be encountered even when - UTF is not supported. */ - -#define Lstart_eptr F->temp_sptr[0] -#define Lxclass_data F->temp_sptr[1] -#define Lmin F->temp_32[0] -#define Lmax F->temp_32[1] - -#ifdef SUPPORT_WIDE_CHARS - case OP_XCLASS: - { - Lxclass_data = Fecode + 1 + LINK_SIZE; /* Save for matching */ - Fecode += GET(Fecode, 1); /* Advance past the item */ - - switch (*Fecode) - { - case OP_CRSTAR: - case OP_CRMINSTAR: - case OP_CRPLUS: - case OP_CRMINPLUS: - case OP_CRQUERY: - case OP_CRMINQUERY: - case OP_CRPOSSTAR: - case OP_CRPOSPLUS: - case OP_CRPOSQUERY: - fc = *Fecode++ - OP_CRSTAR; - Lmin = rep_min[fc]; - Lmax = rep_max[fc]; - reptype = rep_typ[fc]; - break; - - case OP_CRRANGE: - case OP_CRMINRANGE: - case OP_CRPOSRANGE: - Lmin = GET2(Fecode, 1); - Lmax = GET2(Fecode, 1 + IMM2_SIZE); - if (Lmax == 0) Lmax = UINT32_MAX; /* Max 0 => infinity */ - reptype = rep_typ[*Fecode - OP_CRSTAR]; - Fecode += 1 + 2 * IMM2_SIZE; - break; - - default: /* No repeat follows */ - Lmin = Lmax = 1; - break; - } - - /* First, ensure the minimum number of matches are present. */ - - for (i = 1; i <= Lmin; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINCTEST(fc, Feptr); - if (!PRIV(xclass)(fc, Lxclass_data, utf)) RRETURN(MATCH_NOMATCH); - } - - /* If Lmax == Lmin we can just continue with the main loop. */ - - if (Lmin == Lmax) continue; - - /* If minimizing, keep testing the rest of the expression and advancing - the pointer while it matches the class. */ - - if (reptype == REPTYPE_MIN) - { - for (;;) - { - RMATCH(Fecode, RM100); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINCTEST(fc, Feptr); - if (!PRIV(xclass)(fc, Lxclass_data, utf)) RRETURN(MATCH_NOMATCH); - } - /* Control never gets here */ - } - - /* If maximizing, find the longest possible run, then work backwards. */ - - else - { - Lstart_eptr = Feptr; - for (i = Lmin; i < Lmax; i++) - { - int len = 1; - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } -#ifdef SUPPORT_UNICODE - GETCHARLENTEST(fc, Feptr, len); -#else - fc = *Feptr; -#endif - if (!PRIV(xclass)(fc, Lxclass_data, utf)) break; - Feptr += len; - } - - if (reptype == REPTYPE_POS) continue; /* No backtracking */ - - /* After \C in UTF mode, Lstart_eptr might be in the middle of a - Unicode character. Use <= Lstart_eptr to ensure backtracking doesn't - go too far. */ - - for(;;) - { - RMATCH(Fecode, RM101); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (Feptr-- <= Lstart_eptr) break; /* Tried at original position */ -#ifdef SUPPORT_UNICODE - if (utf) BACKCHAR(Feptr); -#endif - } - RRETURN(MATCH_NOMATCH); - } - - /* Control never gets here */ - } -#endif /* SUPPORT_WIDE_CHARS: end of XCLASS */ - -#undef Lstart_eptr -#undef Lxclass_data -#undef Lmin -#undef Lmax - - - /* ===================================================================== */ - /* Match various character types when PCRE2_UCP is not set. These opcodes - are not generated when PCRE2_UCP is set - instead appropriate property - tests are compiled. */ - - case OP_NOT_DIGIT: - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINCTEST(fc, Feptr); - if (CHMAX_255(fc) && (mb->ctypes[fc] & ctype_digit) != 0) - RRETURN(MATCH_NOMATCH); - Fecode++; - break; - - case OP_DIGIT: - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINCTEST(fc, Feptr); - if (!CHMAX_255(fc) || (mb->ctypes[fc] & ctype_digit) == 0) - RRETURN(MATCH_NOMATCH); - Fecode++; - break; - - case OP_NOT_WHITESPACE: - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINCTEST(fc, Feptr); - if (CHMAX_255(fc) && (mb->ctypes[fc] & ctype_space) != 0) - RRETURN(MATCH_NOMATCH); - Fecode++; - break; - - case OP_WHITESPACE: - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINCTEST(fc, Feptr); - if (!CHMAX_255(fc) || (mb->ctypes[fc] & ctype_space) == 0) - RRETURN(MATCH_NOMATCH); - Fecode++; - break; - - case OP_NOT_WORDCHAR: - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINCTEST(fc, Feptr); - if (CHMAX_255(fc) && (mb->ctypes[fc] & ctype_word) != 0) - RRETURN(MATCH_NOMATCH); - Fecode++; - break; - - case OP_WORDCHAR: - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINCTEST(fc, Feptr); - if (!CHMAX_255(fc) || (mb->ctypes[fc] & ctype_word) == 0) - RRETURN(MATCH_NOMATCH); - Fecode++; - break; - - case OP_ANYNL: - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINCTEST(fc, Feptr); - switch(fc) - { - default: RRETURN(MATCH_NOMATCH); - - case CHAR_CR: - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - } - else if (UCHAR21TEST(Feptr) == CHAR_LF) Feptr++; - break; - - case CHAR_LF: - break; - - case CHAR_VT: - case CHAR_FF: - case CHAR_NEL: -#ifndef EBCDIC - case 0x2028: - case 0x2029: -#endif /* Not EBCDIC */ - if (mb->bsr_convention == PCRE2_BSR_ANYCRLF) RRETURN(MATCH_NOMATCH); - break; - } - Fecode++; - break; - - case OP_NOT_HSPACE: - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINCTEST(fc, Feptr); - switch(fc) - { - HSPACE_CASES: RRETURN(MATCH_NOMATCH); /* Byte and multibyte cases */ - default: break; - } - Fecode++; - break; - - case OP_HSPACE: - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINCTEST(fc, Feptr); - switch(fc) - { - HSPACE_CASES: break; /* Byte and multibyte cases */ - default: RRETURN(MATCH_NOMATCH); - } - Fecode++; - break; - - case OP_NOT_VSPACE: - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINCTEST(fc, Feptr); - switch(fc) - { - VSPACE_CASES: RRETURN(MATCH_NOMATCH); - default: break; - } - Fecode++; - break; - - case OP_VSPACE: - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINCTEST(fc, Feptr); - switch(fc) - { - VSPACE_CASES: break; - default: RRETURN(MATCH_NOMATCH); - } - Fecode++; - break; - - -#ifdef SUPPORT_UNICODE - - /* ===================================================================== */ - /* Check the next character by Unicode property. We will get here only - if the support is in the binary; otherwise a compile-time error occurs. */ - - case OP_PROP: - case OP_NOTPROP: - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINCTEST(fc, Feptr); - { - const uint32_t *cp; - const ucd_record *prop = GET_UCD(fc); - BOOL notmatch = Fop == OP_NOTPROP; - - switch(Fecode[1]) - { - case PT_ANY: - if (notmatch) RRETURN(MATCH_NOMATCH); - break; - - case PT_LAMP: - if ((prop->chartype == ucp_Lu || - prop->chartype == ucp_Ll || - prop->chartype == ucp_Lt) == notmatch) - RRETURN(MATCH_NOMATCH); - break; - - case PT_GC: - if ((Fecode[2] == PRIV(ucp_gentype)[prop->chartype]) == notmatch) - RRETURN(MATCH_NOMATCH); - break; - - case PT_PC: - if ((Fecode[2] == prop->chartype) == notmatch) - RRETURN(MATCH_NOMATCH); - break; - - case PT_SC: - if ((Fecode[2] == prop->script) == notmatch) - RRETURN(MATCH_NOMATCH); - break; - - case PT_SCX: - { - BOOL ok = (Fecode[2] == prop->script || - MAPBIT(PRIV(ucd_script_sets) + UCD_SCRIPTX_PROP(prop), Fecode[2]) != 0); - if (ok == notmatch) RRETURN(MATCH_NOMATCH); - } - break; - - /* These are specials */ - - case PT_ALNUM: - if ((PRIV(ucp_gentype)[prop->chartype] == ucp_L || - PRIV(ucp_gentype)[prop->chartype] == ucp_N) == notmatch) - RRETURN(MATCH_NOMATCH); - break; - - /* Perl space used to exclude VT, but from Perl 5.18 it is included, - which means that Perl space and POSIX space are now identical. PCRE - was changed at release 8.34. */ - - case PT_SPACE: /* Perl space */ - case PT_PXSPACE: /* POSIX space */ - switch(fc) - { - HSPACE_CASES: - VSPACE_CASES: - if (notmatch) RRETURN(MATCH_NOMATCH); - break; - - default: - if ((PRIV(ucp_gentype)[prop->chartype] == ucp_Z) == notmatch) - RRETURN(MATCH_NOMATCH); - break; - } - break; - - case PT_WORD: - if ((PRIV(ucp_gentype)[prop->chartype] == ucp_L || - PRIV(ucp_gentype)[prop->chartype] == ucp_N || - fc == CHAR_UNDERSCORE) == notmatch) - RRETURN(MATCH_NOMATCH); - break; - - case PT_CLIST: - cp = PRIV(ucd_caseless_sets) + Fecode[2]; - for (;;) - { - if (fc < *cp) - { if (notmatch) break; else { RRETURN(MATCH_NOMATCH); } } - if (fc == *cp++) - { if (notmatch) { RRETURN(MATCH_NOMATCH); } else break; } - } - break; - - case PT_UCNC: - if ((fc == CHAR_DOLLAR_SIGN || fc == CHAR_COMMERCIAL_AT || - fc == CHAR_GRAVE_ACCENT || (fc >= 0xa0 && fc <= 0xd7ff) || - fc >= 0xe000) == notmatch) - RRETURN(MATCH_NOMATCH); - break; - - case PT_BIDICL: - if ((UCD_BIDICLASS_PROP(prop) == Fecode[2]) == notmatch) - RRETURN(MATCH_NOMATCH); - break; - - case PT_BOOL: - { - BOOL ok = MAPBIT(PRIV(ucd_boolprop_sets) + - UCD_BPROPS_PROP(prop), Fecode[2]) != 0; - if (ok == notmatch) RRETURN(MATCH_NOMATCH); - } - break; - - /* This should never occur */ - - default: - return PCRE2_ERROR_INTERNAL; - } - - Fecode += 3; - } - break; - - - /* ===================================================================== */ - /* Match an extended Unicode sequence. We will get here only if the support - is in the binary; otherwise a compile-time error occurs. */ - - case OP_EXTUNI: - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - else - { - GETCHARINCTEST(fc, Feptr); - Feptr = PRIV(extuni)(fc, Feptr, mb->start_subject, mb->end_subject, utf, - NULL); - } - CHECK_PARTIAL(); - Fecode++; - break; - -#endif /* SUPPORT_UNICODE */ - - - /* ===================================================================== */ - /* Match a single character type repeatedly. Note that the property type - does not need to be in a stack frame as it is not used within an RMATCH() - loop. */ - -#define Lstart_eptr F->temp_sptr[0] -#define Lmin F->temp_32[0] -#define Lmax F->temp_32[1] -#define Lctype F->temp_32[2] -#define Lpropvalue F->temp_32[3] - - case OP_TYPEEXACT: - Lmin = Lmax = GET2(Fecode, 1); - Fecode += 1 + IMM2_SIZE; - goto REPEATTYPE; - - case OP_TYPEUPTO: - case OP_TYPEMINUPTO: - Lmin = 0; - Lmax = GET2(Fecode, 1); - reptype = (*Fecode == OP_TYPEMINUPTO)? REPTYPE_MIN : REPTYPE_MAX; - Fecode += 1 + IMM2_SIZE; - goto REPEATTYPE; - - case OP_TYPEPOSSTAR: - reptype = REPTYPE_POS; - Lmin = 0; - Lmax = UINT32_MAX; - Fecode++; - goto REPEATTYPE; - - case OP_TYPEPOSPLUS: - reptype = REPTYPE_POS; - Lmin = 1; - Lmax = UINT32_MAX; - Fecode++; - goto REPEATTYPE; - - case OP_TYPEPOSQUERY: - reptype = REPTYPE_POS; - Lmin = 0; - Lmax = 1; - Fecode++; - goto REPEATTYPE; - - case OP_TYPEPOSUPTO: - reptype = REPTYPE_POS; - Lmin = 0; - Lmax = GET2(Fecode, 1); - Fecode += 1 + IMM2_SIZE; - goto REPEATTYPE; - - case OP_TYPESTAR: - case OP_TYPEMINSTAR: - case OP_TYPEPLUS: - case OP_TYPEMINPLUS: - case OP_TYPEQUERY: - case OP_TYPEMINQUERY: - fc = *Fecode++ - OP_TYPESTAR; - Lmin = rep_min[fc]; - Lmax = rep_max[fc]; - reptype = rep_typ[fc]; - - /* Common code for all repeated character type matches. */ - - REPEATTYPE: - Lctype = *Fecode++; /* Code for the character type */ - -#ifdef SUPPORT_UNICODE - if (Lctype == OP_PROP || Lctype == OP_NOTPROP) - { - proptype = *Fecode++; - Lpropvalue = *Fecode++; - } - else proptype = -1; -#endif - - /* First, ensure the minimum number of matches are present. Use inline - code for maximizing the speed, and do the type test once at the start - (i.e. keep it out of the loops). As there are no calls to RMATCH in the - loops, we can use an ordinary variable for "notmatch". The code for UTF - mode is separated out for tidiness, except for Unicode property tests. */ - - if (Lmin > 0) - { -#ifdef SUPPORT_UNICODE - if (proptype >= 0) /* Property tests in all modes */ - { - BOOL notmatch = Lctype == OP_NOTPROP; - switch(proptype) - { - case PT_ANY: - if (notmatch) RRETURN(MATCH_NOMATCH); - for (i = 1; i <= Lmin; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINCTEST(fc, Feptr); - } - break; - - case PT_LAMP: - for (i = 1; i <= Lmin; i++) - { - int chartype; - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINCTEST(fc, Feptr); - chartype = UCD_CHARTYPE(fc); - if ((chartype == ucp_Lu || - chartype == ucp_Ll || - chartype == ucp_Lt) == notmatch) - RRETURN(MATCH_NOMATCH); - } - break; - - case PT_GC: - for (i = 1; i <= Lmin; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINCTEST(fc, Feptr); - if ((UCD_CATEGORY(fc) == Lpropvalue) == notmatch) - RRETURN(MATCH_NOMATCH); - } - break; - - case PT_PC: - for (i = 1; i <= Lmin; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINCTEST(fc, Feptr); - if ((UCD_CHARTYPE(fc) == Lpropvalue) == notmatch) - RRETURN(MATCH_NOMATCH); - } - break; - - case PT_SC: - for (i = 1; i <= Lmin; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINCTEST(fc, Feptr); - if ((UCD_SCRIPT(fc) == Lpropvalue) == notmatch) - RRETURN(MATCH_NOMATCH); - } - break; - - case PT_SCX: - for (i = 1; i <= Lmin; i++) - { - BOOL ok; - const ucd_record *prop; - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINCTEST(fc, Feptr); - prop = GET_UCD(fc); - ok = (prop->script == Lpropvalue || - MAPBIT(PRIV(ucd_script_sets) + UCD_SCRIPTX_PROP(prop), Lpropvalue) != 0); - if (ok == notmatch) - RRETURN(MATCH_NOMATCH); - } - break; - - case PT_ALNUM: - for (i = 1; i <= Lmin; i++) - { - int category; - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINCTEST(fc, Feptr); - category = UCD_CATEGORY(fc); - if ((category == ucp_L || category == ucp_N) == notmatch) - RRETURN(MATCH_NOMATCH); - } - break; - - /* Perl space used to exclude VT, but from Perl 5.18 it is included, - which means that Perl space and POSIX space are now identical. PCRE - was changed at release 8.34. */ - - case PT_SPACE: /* Perl space */ - case PT_PXSPACE: /* POSIX space */ - for (i = 1; i <= Lmin; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINCTEST(fc, Feptr); - switch(fc) - { - HSPACE_CASES: - VSPACE_CASES: - if (notmatch) RRETURN(MATCH_NOMATCH); - break; - - default: - if ((UCD_CATEGORY(fc) == ucp_Z) == notmatch) - RRETURN(MATCH_NOMATCH); - break; - } - } - break; - - case PT_WORD: - for (i = 1; i <= Lmin; i++) - { - int category; - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINCTEST(fc, Feptr); - category = UCD_CATEGORY(fc); - if ((category == ucp_L || category == ucp_N || - fc == CHAR_UNDERSCORE) == notmatch) - RRETURN(MATCH_NOMATCH); - } - break; - - case PT_CLIST: - for (i = 1; i <= Lmin; i++) - { - const uint32_t *cp; - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINCTEST(fc, Feptr); - cp = PRIV(ucd_caseless_sets) + Lpropvalue; - for (;;) - { - if (fc < *cp) - { - if (notmatch) break; - RRETURN(MATCH_NOMATCH); - } - if (fc == *cp++) - { - if (notmatch) RRETURN(MATCH_NOMATCH); - break; - } - } - } - break; - - case PT_UCNC: - for (i = 1; i <= Lmin; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINCTEST(fc, Feptr); - if ((fc == CHAR_DOLLAR_SIGN || fc == CHAR_COMMERCIAL_AT || - fc == CHAR_GRAVE_ACCENT || (fc >= 0xa0 && fc <= 0xd7ff) || - fc >= 0xe000) == notmatch) - RRETURN(MATCH_NOMATCH); - } - break; - - case PT_BIDICL: - for (i = 1; i <= Lmin; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINCTEST(fc, Feptr); - if ((UCD_BIDICLASS(fc) == Lpropvalue) == notmatch) - RRETURN(MATCH_NOMATCH); - } - break; - - case PT_BOOL: - for (i = 1; i <= Lmin; i++) - { - BOOL ok; - const ucd_record *prop; - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINCTEST(fc, Feptr); - prop = GET_UCD(fc); - ok = MAPBIT(PRIV(ucd_boolprop_sets) + - UCD_BPROPS_PROP(prop), Lpropvalue) != 0; - if (ok == notmatch) - RRETURN(MATCH_NOMATCH); - } - break; - - /* This should not occur */ - - default: - return PCRE2_ERROR_INTERNAL; - } - } - - /* Match extended Unicode sequences. We will get here only if the - support is in the binary; otherwise a compile-time error occurs. */ - - else if (Lctype == OP_EXTUNI) - { - for (i = 1; i <= Lmin; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - else - { - GETCHARINCTEST(fc, Feptr); - Feptr = PRIV(extuni)(fc, Feptr, mb->start_subject, - mb->end_subject, utf, NULL); - } - CHECK_PARTIAL(); - } - } - else -#endif /* SUPPORT_UNICODE */ - -/* Handle all other cases in UTF mode */ - -#ifdef SUPPORT_UNICODE - if (utf) switch(Lctype) - { - case OP_ANY: - for (i = 1; i <= Lmin; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - if (IS_NEWLINE(Feptr)) RRETURN(MATCH_NOMATCH); - if (mb->partial != 0 && - Feptr + 1 >= mb->end_subject && - NLBLOCK->nltype == NLTYPE_FIXED && - NLBLOCK->nllen == 2 && - UCHAR21(Feptr) == NLBLOCK->nl[0]) - { - mb->hitend = TRUE; - if (mb->partial > 1) return PCRE2_ERROR_PARTIAL; - } - Feptr++; - ACROSSCHAR(Feptr < mb->end_subject, Feptr, Feptr++); - } - break; - - case OP_ALLANY: - for (i = 1; i <= Lmin; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - Feptr++; - ACROSSCHAR(Feptr < mb->end_subject, Feptr, Feptr++); - } - break; - - case OP_ANYBYTE: - if (Feptr > mb->end_subject - Lmin) RRETURN(MATCH_NOMATCH); - Feptr += Lmin; - break; - - case OP_ANYNL: - for (i = 1; i <= Lmin; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINC(fc, Feptr); - switch(fc) - { - default: RRETURN(MATCH_NOMATCH); - - case CHAR_CR: - if (Feptr < mb->end_subject && UCHAR21(Feptr) == CHAR_LF) Feptr++; - break; - - case CHAR_LF: - break; - - case CHAR_VT: - case CHAR_FF: - case CHAR_NEL: -#ifndef EBCDIC - case 0x2028: - case 0x2029: -#endif /* Not EBCDIC */ - if (mb->bsr_convention == PCRE2_BSR_ANYCRLF) RRETURN(MATCH_NOMATCH); - break; - } - } - break; - - case OP_NOT_HSPACE: - for (i = 1; i <= Lmin; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINC(fc, Feptr); - switch(fc) - { - HSPACE_CASES: RRETURN(MATCH_NOMATCH); - default: break; - } - } - break; - - case OP_HSPACE: - for (i = 1; i <= Lmin; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINC(fc, Feptr); - switch(fc) - { - HSPACE_CASES: break; - default: RRETURN(MATCH_NOMATCH); - } - } - break; - - case OP_NOT_VSPACE: - for (i = 1; i <= Lmin; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINC(fc, Feptr); - switch(fc) - { - VSPACE_CASES: RRETURN(MATCH_NOMATCH); - default: break; - } - } - break; - - case OP_VSPACE: - for (i = 1; i <= Lmin; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINC(fc, Feptr); - switch(fc) - { - VSPACE_CASES: break; - default: RRETURN(MATCH_NOMATCH); - } - } - break; - - case OP_NOT_DIGIT: - for (i = 1; i <= Lmin; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINC(fc, Feptr); - if (fc < 128 && (mb->ctypes[fc] & ctype_digit) != 0) - RRETURN(MATCH_NOMATCH); - } - break; - - case OP_DIGIT: - for (i = 1; i <= Lmin; i++) - { - uint32_t cc; - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - cc = UCHAR21(Feptr); - if (cc >= 128 || (mb->ctypes[cc] & ctype_digit) == 0) - RRETURN(MATCH_NOMATCH); - Feptr++; - /* No need to skip more code units - we know it has only one. */ - } - break; - - case OP_NOT_WHITESPACE: - for (i = 1; i <= Lmin; i++) - { - uint32_t cc; - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - cc = UCHAR21(Feptr); - if (cc < 128 && (mb->ctypes[cc] & ctype_space) != 0) - RRETURN(MATCH_NOMATCH); - Feptr++; - ACROSSCHAR(Feptr < mb->end_subject, Feptr, Feptr++); - } - break; - - case OP_WHITESPACE: - for (i = 1; i <= Lmin; i++) - { - uint32_t cc; - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - cc = UCHAR21(Feptr); - if (cc >= 128 || (mb->ctypes[cc] & ctype_space) == 0) - RRETURN(MATCH_NOMATCH); - Feptr++; - /* No need to skip more code units - we know it has only one. */ - } - break; - - case OP_NOT_WORDCHAR: - for (i = 1; i <= Lmin; i++) - { - uint32_t cc; - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - cc = UCHAR21(Feptr); - if (cc < 128 && (mb->ctypes[cc] & ctype_word) != 0) - RRETURN(MATCH_NOMATCH); - Feptr++; - ACROSSCHAR(Feptr < mb->end_subject, Feptr, Feptr++); - } - break; - - case OP_WORDCHAR: - for (i = 1; i <= Lmin; i++) - { - uint32_t cc; - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - cc = UCHAR21(Feptr); - if (cc >= 128 || (mb->ctypes[cc] & ctype_word) == 0) - RRETURN(MATCH_NOMATCH); - Feptr++; - /* No need to skip more code units - we know it has only one. */ - } - break; - - default: - return PCRE2_ERROR_INTERNAL; - } /* End switch(Lctype) */ - - else -#endif /* SUPPORT_UNICODE */ - - /* Code for the non-UTF case for minimum matching of operators other - than OP_PROP and OP_NOTPROP. */ - - switch(Lctype) - { - case OP_ANY: - for (i = 1; i <= Lmin; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - if (IS_NEWLINE(Feptr)) RRETURN(MATCH_NOMATCH); - if (mb->partial != 0 && - Feptr + 1 >= mb->end_subject && - NLBLOCK->nltype == NLTYPE_FIXED && - NLBLOCK->nllen == 2 && - *Feptr == NLBLOCK->nl[0]) - { - mb->hitend = TRUE; - if (mb->partial > 1) return PCRE2_ERROR_PARTIAL; - } - Feptr++; - } - break; - - case OP_ALLANY: - if (Feptr > mb->end_subject - Lmin) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - Feptr += Lmin; - break; - - /* This OP_ANYBYTE case will never be reached because \C gets turned - into OP_ALLANY in non-UTF mode. Cut out the code so that coverage - reports don't complain about it's never being used. */ - -/* case OP_ANYBYTE: -* if (Feptr > mb->end_subject - Lmin) -* { -* SCHECK_PARTIAL(); -* RRETURN(MATCH_NOMATCH); -* } -* Feptr += Lmin; -* break; -*/ - case OP_ANYNL: - for (i = 1; i <= Lmin; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - switch(*Feptr++) - { - default: RRETURN(MATCH_NOMATCH); - - case CHAR_CR: - if (Feptr < mb->end_subject && *Feptr == CHAR_LF) Feptr++; - break; - - case CHAR_LF: - break; - - case CHAR_VT: - case CHAR_FF: - case CHAR_NEL: -#if PCRE2_CODE_UNIT_WIDTH != 8 - case 0x2028: - case 0x2029: -#endif - if (mb->bsr_convention == PCRE2_BSR_ANYCRLF) RRETURN(MATCH_NOMATCH); - break; - } - } - break; - - case OP_NOT_HSPACE: - for (i = 1; i <= Lmin; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - switch(*Feptr++) - { - default: break; - HSPACE_BYTE_CASES: -#if PCRE2_CODE_UNIT_WIDTH != 8 - HSPACE_MULTIBYTE_CASES: -#endif - RRETURN(MATCH_NOMATCH); - } - } - break; - - case OP_HSPACE: - for (i = 1; i <= Lmin; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - switch(*Feptr++) - { - default: RRETURN(MATCH_NOMATCH); - HSPACE_BYTE_CASES: -#if PCRE2_CODE_UNIT_WIDTH != 8 - HSPACE_MULTIBYTE_CASES: -#endif - break; - } - } - break; - - case OP_NOT_VSPACE: - for (i = 1; i <= Lmin; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - switch(*Feptr++) - { - VSPACE_BYTE_CASES: -#if PCRE2_CODE_UNIT_WIDTH != 8 - VSPACE_MULTIBYTE_CASES: -#endif - RRETURN(MATCH_NOMATCH); - default: break; - } - } - break; - - case OP_VSPACE: - for (i = 1; i <= Lmin; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - switch(*Feptr++) - { - default: RRETURN(MATCH_NOMATCH); - VSPACE_BYTE_CASES: -#if PCRE2_CODE_UNIT_WIDTH != 8 - VSPACE_MULTIBYTE_CASES: -#endif - break; - } - } - break; - - case OP_NOT_DIGIT: - for (i = 1; i <= Lmin; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - if (MAX_255(*Feptr) && (mb->ctypes[*Feptr] & ctype_digit) != 0) - RRETURN(MATCH_NOMATCH); - Feptr++; - } - break; - - case OP_DIGIT: - for (i = 1; i <= Lmin; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - if (!MAX_255(*Feptr) || (mb->ctypes[*Feptr] & ctype_digit) == 0) - RRETURN(MATCH_NOMATCH); - Feptr++; - } - break; - - case OP_NOT_WHITESPACE: - for (i = 1; i <= Lmin; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - if (MAX_255(*Feptr) && (mb->ctypes[*Feptr] & ctype_space) != 0) - RRETURN(MATCH_NOMATCH); - Feptr++; - } - break; - - case OP_WHITESPACE: - for (i = 1; i <= Lmin; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - if (!MAX_255(*Feptr) || (mb->ctypes[*Feptr] & ctype_space) == 0) - RRETURN(MATCH_NOMATCH); - Feptr++; - } - break; - - case OP_NOT_WORDCHAR: - for (i = 1; i <= Lmin; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - if (MAX_255(*Feptr) && (mb->ctypes[*Feptr] & ctype_word) != 0) - RRETURN(MATCH_NOMATCH); - Feptr++; - } - break; - - case OP_WORDCHAR: - for (i = 1; i <= Lmin; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - if (!MAX_255(*Feptr) || (mb->ctypes[*Feptr] & ctype_word) == 0) - RRETURN(MATCH_NOMATCH); - Feptr++; - } - break; - - default: - return PCRE2_ERROR_INTERNAL; - } - } - - /* If Lmin = Lmax we are done. Continue with the main loop. */ - - if (Lmin == Lmax) continue; - - /* If minimizing, we have to test the rest of the pattern before each - subsequent match. This means we cannot use a local "notmatch" variable as - in the other cases. As all 4 temporary 32-bit values in the frame are - already in use, just test the type each time. */ - - if (reptype == REPTYPE_MIN) - { -#ifdef SUPPORT_UNICODE - if (proptype >= 0) - { - switch(proptype) - { - case PT_ANY: - for (;;) - { - RMATCH(Fecode, RM208); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINCTEST(fc, Feptr); - if (Lctype == OP_NOTPROP) RRETURN(MATCH_NOMATCH); - } - /* Control never gets here */ - - case PT_LAMP: - for (;;) - { - int chartype; - RMATCH(Fecode, RM209); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINCTEST(fc, Feptr); - chartype = UCD_CHARTYPE(fc); - if ((chartype == ucp_Lu || - chartype == ucp_Ll || - chartype == ucp_Lt) == (Lctype == OP_NOTPROP)) - RRETURN(MATCH_NOMATCH); - } - /* Control never gets here */ - - case PT_GC: - for (;;) - { - RMATCH(Fecode, RM210); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINCTEST(fc, Feptr); - if ((UCD_CATEGORY(fc) == Lpropvalue) == (Lctype == OP_NOTPROP)) - RRETURN(MATCH_NOMATCH); - } - /* Control never gets here */ - - case PT_PC: - for (;;) - { - RMATCH(Fecode, RM211); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINCTEST(fc, Feptr); - if ((UCD_CHARTYPE(fc) == Lpropvalue) == (Lctype == OP_NOTPROP)) - RRETURN(MATCH_NOMATCH); - } - /* Control never gets here */ - - case PT_SC: - for (;;) - { - RMATCH(Fecode, RM212); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINCTEST(fc, Feptr); - if ((UCD_SCRIPT(fc) == Lpropvalue) == (Lctype == OP_NOTPROP)) - RRETURN(MATCH_NOMATCH); - } - /* Control never gets here */ - - case PT_SCX: - for (;;) - { - BOOL ok; - const ucd_record *prop; - RMATCH(Fecode, RM225); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINCTEST(fc, Feptr); - prop = GET_UCD(fc); - ok = (prop->script == Lpropvalue - || MAPBIT(PRIV(ucd_script_sets) + UCD_SCRIPTX_PROP(prop), Lpropvalue) != 0); - if (ok == (Lctype == OP_NOTPROP)) - RRETURN(MATCH_NOMATCH); - } - /* Control never gets here */ - - case PT_ALNUM: - for (;;) - { - int category; - RMATCH(Fecode, RM213); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINCTEST(fc, Feptr); - category = UCD_CATEGORY(fc); - if ((category == ucp_L || category == ucp_N) == (Lctype == OP_NOTPROP)) - RRETURN(MATCH_NOMATCH); - } - /* Control never gets here */ - - /* Perl space used to exclude VT, but from Perl 5.18 it is included, - which means that Perl space and POSIX space are now identical. PCRE - was changed at release 8.34. */ - - case PT_SPACE: /* Perl space */ - case PT_PXSPACE: /* POSIX space */ - for (;;) - { - RMATCH(Fecode, RM214); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINCTEST(fc, Feptr); - switch(fc) - { - HSPACE_CASES: - VSPACE_CASES: - if (Lctype == OP_NOTPROP) RRETURN(MATCH_NOMATCH); - break; - - default: - if ((UCD_CATEGORY(fc) == ucp_Z) == (Lctype == OP_NOTPROP)) - RRETURN(MATCH_NOMATCH); - break; - } - } - /* Control never gets here */ - - case PT_WORD: - for (;;) - { - int category; - RMATCH(Fecode, RM215); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINCTEST(fc, Feptr); - category = UCD_CATEGORY(fc); - if ((category == ucp_L || - category == ucp_N || - fc == CHAR_UNDERSCORE) == (Lctype == OP_NOTPROP)) - RRETURN(MATCH_NOMATCH); - } - /* Control never gets here */ - - case PT_CLIST: - for (;;) - { - const uint32_t *cp; - RMATCH(Fecode, RM216); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINCTEST(fc, Feptr); - cp = PRIV(ucd_caseless_sets) + Lpropvalue; - for (;;) - { - if (fc < *cp) - { - if (Lctype == OP_NOTPROP) break; - RRETURN(MATCH_NOMATCH); - } - if (fc == *cp++) - { - if (Lctype == OP_NOTPROP) RRETURN(MATCH_NOMATCH); - break; - } - } - } - /* Control never gets here */ - - case PT_UCNC: - for (;;) - { - RMATCH(Fecode, RM217); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINCTEST(fc, Feptr); - if ((fc == CHAR_DOLLAR_SIGN || fc == CHAR_COMMERCIAL_AT || - fc == CHAR_GRAVE_ACCENT || (fc >= 0xa0 && fc <= 0xd7ff) || - fc >= 0xe000) == (Lctype == OP_NOTPROP)) - RRETURN(MATCH_NOMATCH); - } - /* Control never gets here */ - - case PT_BIDICL: - for (;;) - { - RMATCH(Fecode, RM224); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINCTEST(fc, Feptr); - if ((UCD_BIDICLASS(fc) == Lpropvalue) == (Lctype == OP_NOTPROP)) - RRETURN(MATCH_NOMATCH); - } - /* Control never gets here */ - - case PT_BOOL: - for (;;) - { - BOOL ok; - const ucd_record *prop; - RMATCH(Fecode, RM223); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINCTEST(fc, Feptr); - prop = GET_UCD(fc); - ok = MAPBIT(PRIV(ucd_boolprop_sets) + - UCD_BPROPS_PROP(prop), Lpropvalue) != 0; - if (ok == (Lctype == OP_NOTPROP)) - RRETURN(MATCH_NOMATCH); - } - /* Control never gets here */ - - /* This should never occur */ - default: - return PCRE2_ERROR_INTERNAL; - } - } - - /* Match extended Unicode sequences. We will get here only if the - support is in the binary; otherwise a compile-time error occurs. */ - - else if (Lctype == OP_EXTUNI) - { - for (;;) - { - RMATCH(Fecode, RM218); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - else - { - GETCHARINCTEST(fc, Feptr); - Feptr = PRIV(extuni)(fc, Feptr, mb->start_subject, mb->end_subject, - utf, NULL); - } - CHECK_PARTIAL(); - } - } - else -#endif /* SUPPORT_UNICODE */ - - /* UTF mode for non-property testing character types. */ - -#ifdef SUPPORT_UNICODE - if (utf) - { - for (;;) - { - RMATCH(Fecode, RM219); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - if (Lctype == OP_ANY && IS_NEWLINE(Feptr)) RRETURN(MATCH_NOMATCH); - GETCHARINC(fc, Feptr); - switch(Lctype) - { - case OP_ANY: /* This is the non-NL case */ - if (mb->partial != 0 && /* Take care with CRLF partial */ - Feptr >= mb->end_subject && - NLBLOCK->nltype == NLTYPE_FIXED && - NLBLOCK->nllen == 2 && - fc == NLBLOCK->nl[0]) - { - mb->hitend = TRUE; - if (mb->partial > 1) return PCRE2_ERROR_PARTIAL; - } - break; - - case OP_ALLANY: - case OP_ANYBYTE: - break; - - case OP_ANYNL: - switch(fc) - { - default: RRETURN(MATCH_NOMATCH); - - case CHAR_CR: - if (Feptr < mb->end_subject && UCHAR21(Feptr) == CHAR_LF) Feptr++; - break; - - case CHAR_LF: - break; - - case CHAR_VT: - case CHAR_FF: - case CHAR_NEL: -#ifndef EBCDIC - case 0x2028: - case 0x2029: -#endif /* Not EBCDIC */ - if (mb->bsr_convention == PCRE2_BSR_ANYCRLF) - RRETURN(MATCH_NOMATCH); - break; - } - break; - - case OP_NOT_HSPACE: - switch(fc) - { - HSPACE_CASES: RRETURN(MATCH_NOMATCH); - default: break; - } - break; - - case OP_HSPACE: - switch(fc) - { - HSPACE_CASES: break; - default: RRETURN(MATCH_NOMATCH); - } - break; - - case OP_NOT_VSPACE: - switch(fc) - { - VSPACE_CASES: RRETURN(MATCH_NOMATCH); - default: break; - } - break; - - case OP_VSPACE: - switch(fc) - { - VSPACE_CASES: break; - default: RRETURN(MATCH_NOMATCH); - } - break; - - case OP_NOT_DIGIT: - if (fc < 256 && (mb->ctypes[fc] & ctype_digit) != 0) - RRETURN(MATCH_NOMATCH); - break; - - case OP_DIGIT: - if (fc >= 256 || (mb->ctypes[fc] & ctype_digit) == 0) - RRETURN(MATCH_NOMATCH); - break; - - case OP_NOT_WHITESPACE: - if (fc < 256 && (mb->ctypes[fc] & ctype_space) != 0) - RRETURN(MATCH_NOMATCH); - break; - - case OP_WHITESPACE: - if (fc >= 256 || (mb->ctypes[fc] & ctype_space) == 0) - RRETURN(MATCH_NOMATCH); - break; - - case OP_NOT_WORDCHAR: - if (fc < 256 && (mb->ctypes[fc] & ctype_word) != 0) - RRETURN(MATCH_NOMATCH); - break; - - case OP_WORDCHAR: - if (fc >= 256 || (mb->ctypes[fc] & ctype_word) == 0) - RRETURN(MATCH_NOMATCH); - break; - - default: - return PCRE2_ERROR_INTERNAL; - } - } - } - else -#endif /* SUPPORT_UNICODE */ - - /* Not UTF mode */ - { - for (;;) - { - RMATCH(Fecode, RM33); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - if (Lctype == OP_ANY && IS_NEWLINE(Feptr)) - RRETURN(MATCH_NOMATCH); - fc = *Feptr++; - switch(Lctype) - { - case OP_ANY: /* This is the non-NL case */ - if (mb->partial != 0 && /* Take care with CRLF partial */ - Feptr >= mb->end_subject && - NLBLOCK->nltype == NLTYPE_FIXED && - NLBLOCK->nllen == 2 && - fc == NLBLOCK->nl[0]) - { - mb->hitend = TRUE; - if (mb->partial > 1) return PCRE2_ERROR_PARTIAL; - } - break; - - case OP_ALLANY: - case OP_ANYBYTE: - break; - - case OP_ANYNL: - switch(fc) - { - default: RRETURN(MATCH_NOMATCH); - - case CHAR_CR: - if (Feptr < mb->end_subject && *Feptr == CHAR_LF) Feptr++; - break; - - case CHAR_LF: - break; - - case CHAR_VT: - case CHAR_FF: - case CHAR_NEL: -#if PCRE2_CODE_UNIT_WIDTH != 8 - case 0x2028: - case 0x2029: -#endif - if (mb->bsr_convention == PCRE2_BSR_ANYCRLF) - RRETURN(MATCH_NOMATCH); - break; - } - break; - - case OP_NOT_HSPACE: - switch(fc) - { - default: break; - HSPACE_BYTE_CASES: -#if PCRE2_CODE_UNIT_WIDTH != 8 - HSPACE_MULTIBYTE_CASES: -#endif - RRETURN(MATCH_NOMATCH); - } - break; - - case OP_HSPACE: - switch(fc) - { - default: RRETURN(MATCH_NOMATCH); - HSPACE_BYTE_CASES: -#if PCRE2_CODE_UNIT_WIDTH != 8 - HSPACE_MULTIBYTE_CASES: -#endif - break; - } - break; - - case OP_NOT_VSPACE: - switch(fc) - { - default: break; - VSPACE_BYTE_CASES: -#if PCRE2_CODE_UNIT_WIDTH != 8 - VSPACE_MULTIBYTE_CASES: -#endif - RRETURN(MATCH_NOMATCH); - } - break; - - case OP_VSPACE: - switch(fc) - { - default: RRETURN(MATCH_NOMATCH); - VSPACE_BYTE_CASES: -#if PCRE2_CODE_UNIT_WIDTH != 8 - VSPACE_MULTIBYTE_CASES: -#endif - break; - } - break; - - case OP_NOT_DIGIT: - if (MAX_255(fc) && (mb->ctypes[fc] & ctype_digit) != 0) - RRETURN(MATCH_NOMATCH); - break; - - case OP_DIGIT: - if (!MAX_255(fc) || (mb->ctypes[fc] & ctype_digit) == 0) - RRETURN(MATCH_NOMATCH); - break; - - case OP_NOT_WHITESPACE: - if (MAX_255(fc) && (mb->ctypes[fc] & ctype_space) != 0) - RRETURN(MATCH_NOMATCH); - break; - - case OP_WHITESPACE: - if (!MAX_255(fc) || (mb->ctypes[fc] & ctype_space) == 0) - RRETURN(MATCH_NOMATCH); - break; - - case OP_NOT_WORDCHAR: - if (MAX_255(fc) && (mb->ctypes[fc] & ctype_word) != 0) - RRETURN(MATCH_NOMATCH); - break; - - case OP_WORDCHAR: - if (!MAX_255(fc) || (mb->ctypes[fc] & ctype_word) == 0) - RRETURN(MATCH_NOMATCH); - break; - - default: - return PCRE2_ERROR_INTERNAL; - } - } - } - /* Control never gets here */ - } - - /* If maximizing, it is worth using inline code for speed, doing the type - test once at the start (i.e. keep it out of the loops). Once again, - "notmatch" can be an ordinary local variable because the loops do not call - RMATCH. */ - - else - { - Lstart_eptr = Feptr; /* Remember where we started */ - -#ifdef SUPPORT_UNICODE - if (proptype >= 0) - { - BOOL notmatch = Lctype == OP_NOTPROP; - switch(proptype) - { - case PT_ANY: - for (i = Lmin; i < Lmax; i++) - { - int len = 1; - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - GETCHARLENTEST(fc, Feptr, len); - if (notmatch) break; - Feptr+= len; - } - break; - - case PT_LAMP: - for (i = Lmin; i < Lmax; i++) - { - int chartype; - int len = 1; - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - GETCHARLENTEST(fc, Feptr, len); - chartype = UCD_CHARTYPE(fc); - if ((chartype == ucp_Lu || - chartype == ucp_Ll || - chartype == ucp_Lt) == notmatch) - break; - Feptr+= len; - } - break; - - case PT_GC: - for (i = Lmin; i < Lmax; i++) - { - int len = 1; - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - GETCHARLENTEST(fc, Feptr, len); - if ((UCD_CATEGORY(fc) == Lpropvalue) == notmatch) break; - Feptr+= len; - } - break; - - case PT_PC: - for (i = Lmin; i < Lmax; i++) - { - int len = 1; - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - GETCHARLENTEST(fc, Feptr, len); - if ((UCD_CHARTYPE(fc) == Lpropvalue) == notmatch) break; - Feptr+= len; - } - break; - - case PT_SC: - for (i = Lmin; i < Lmax; i++) - { - int len = 1; - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - GETCHARLENTEST(fc, Feptr, len); - if ((UCD_SCRIPT(fc) == Lpropvalue) == notmatch) break; - Feptr+= len; - } - break; - - case PT_SCX: - for (i = Lmin; i < Lmax; i++) - { - BOOL ok; - const ucd_record *prop; - int len = 1; - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - GETCHARLENTEST(fc, Feptr, len); - prop = GET_UCD(fc); - ok = (prop->script == Lpropvalue || - MAPBIT(PRIV(ucd_script_sets) + UCD_SCRIPTX_PROP(prop), Lpropvalue) != 0); - if (ok == notmatch) break; - Feptr+= len; - } - break; - - case PT_ALNUM: - for (i = Lmin; i < Lmax; i++) - { - int category; - int len = 1; - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - GETCHARLENTEST(fc, Feptr, len); - category = UCD_CATEGORY(fc); - if ((category == ucp_L || category == ucp_N) == notmatch) - break; - Feptr+= len; - } - break; - - /* Perl space used to exclude VT, but from Perl 5.18 it is included, - which means that Perl space and POSIX space are now identical. PCRE - was changed at release 8.34. */ - - case PT_SPACE: /* Perl space */ - case PT_PXSPACE: /* POSIX space */ - for (i = Lmin; i < Lmax; i++) - { - int len = 1; - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - GETCHARLENTEST(fc, Feptr, len); - switch(fc) - { - HSPACE_CASES: - VSPACE_CASES: - if (notmatch) goto ENDLOOP99; /* Break the loop */ - break; - - default: - if ((UCD_CATEGORY(fc) == ucp_Z) == notmatch) - goto ENDLOOP99; /* Break the loop */ - break; - } - Feptr+= len; - } - ENDLOOP99: - break; - - case PT_WORD: - for (i = Lmin; i < Lmax; i++) - { - int category; - int len = 1; - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - GETCHARLENTEST(fc, Feptr, len); - category = UCD_CATEGORY(fc); - if ((category == ucp_L || category == ucp_N || - fc == CHAR_UNDERSCORE) == notmatch) - break; - Feptr+= len; - } - break; - - case PT_CLIST: - for (i = Lmin; i < Lmax; i++) - { - const uint32_t *cp; - int len = 1; - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - GETCHARLENTEST(fc, Feptr, len); - cp = PRIV(ucd_caseless_sets) + Lpropvalue; - for (;;) - { - if (fc < *cp) - { if (notmatch) break; else goto GOT_MAX; } - if (fc == *cp++) - { if (notmatch) goto GOT_MAX; else break; } - } - Feptr += len; - } - GOT_MAX: - break; - - case PT_UCNC: - for (i = Lmin; i < Lmax; i++) - { - int len = 1; - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - GETCHARLENTEST(fc, Feptr, len); - if ((fc == CHAR_DOLLAR_SIGN || fc == CHAR_COMMERCIAL_AT || - fc == CHAR_GRAVE_ACCENT || (fc >= 0xa0 && fc <= 0xd7ff) || - fc >= 0xe000) == notmatch) - break; - Feptr += len; - } - break; - - case PT_BIDICL: - for (i = Lmin; i < Lmax; i++) - { - int len = 1; - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - GETCHARLENTEST(fc, Feptr, len); - if ((UCD_BIDICLASS(fc) == Lpropvalue) == notmatch) break; - Feptr+= len; - } - break; - - case PT_BOOL: - for (i = Lmin; i < Lmax; i++) - { - BOOL ok; - const ucd_record *prop; - int len = 1; - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - GETCHARLENTEST(fc, Feptr, len); - prop = GET_UCD(fc); - ok = MAPBIT(PRIV(ucd_boolprop_sets) + - UCD_BPROPS_PROP(prop), Lpropvalue) != 0; - if (ok == notmatch) break; - Feptr+= len; - } - break; - - default: - return PCRE2_ERROR_INTERNAL; - } - - /* Feptr is now past the end of the maximum run */ - - if (reptype == REPTYPE_POS) continue; /* No backtracking */ - - /* After \C in UTF mode, Lstart_eptr might be in the middle of a - Unicode character. Use <= Lstart_eptr to ensure backtracking doesn't - go too far. */ - - for(;;) - { - if (Feptr <= Lstart_eptr) break; - RMATCH(Fecode, RM222); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - Feptr--; - if (utf) BACKCHAR(Feptr); - } - } - - /* Match extended Unicode grapheme clusters. We will get here only if the - support is in the binary; otherwise a compile-time error occurs. */ - - else if (Lctype == OP_EXTUNI) - { - for (i = Lmin; i < Lmax; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - else - { - GETCHARINCTEST(fc, Feptr); - Feptr = PRIV(extuni)(fc, Feptr, mb->start_subject, mb->end_subject, - utf, NULL); - } - CHECK_PARTIAL(); - } - - /* Feptr is now past the end of the maximum run */ - - if (reptype == REPTYPE_POS) continue; /* No backtracking */ - - /* We use <= Lstart_eptr rather than == Lstart_eptr to detect the start - of the run while backtracking because the use of \C in UTF mode can - cause BACKCHAR to move back past Lstart_eptr. This is just palliative; - the use of \C in UTF mode is fraught with danger. */ - - for(;;) - { - int lgb, rgb; - PCRE2_SPTR fptr; - - if (Feptr <= Lstart_eptr) break; /* At start of char run */ - RMATCH(Fecode, RM220); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - - /* Backtracking over an extended grapheme cluster involves inspecting - the previous two characters (if present) to see if a break is - permitted between them. */ - - Feptr--; - if (!utf) fc = *Feptr; else - { - BACKCHAR(Feptr); - GETCHAR(fc, Feptr); - } - rgb = UCD_GRAPHBREAK(fc); - - for (;;) - { - if (Feptr <= Lstart_eptr) break; /* At start of char run */ - fptr = Feptr - 1; - if (!utf) fc = *fptr; else - { - BACKCHAR(fptr); - GETCHAR(fc, fptr); - } - lgb = UCD_GRAPHBREAK(fc); - if ((PRIV(ucp_gbtable)[lgb] & (1u << rgb)) == 0) break; - Feptr = fptr; - rgb = lgb; - } - } - } - - else -#endif /* SUPPORT_UNICODE */ - -#ifdef SUPPORT_UNICODE - if (utf) - { - switch(Lctype) - { - case OP_ANY: - for (i = Lmin; i < Lmax; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - if (IS_NEWLINE(Feptr)) break; - if (mb->partial != 0 && /* Take care with CRLF partial */ - Feptr + 1 >= mb->end_subject && - NLBLOCK->nltype == NLTYPE_FIXED && - NLBLOCK->nllen == 2 && - UCHAR21(Feptr) == NLBLOCK->nl[0]) - { - mb->hitend = TRUE; - if (mb->partial > 1) return PCRE2_ERROR_PARTIAL; - } - Feptr++; - ACROSSCHAR(Feptr < mb->end_subject, Feptr, Feptr++); - } - break; - - case OP_ALLANY: - if (Lmax < UINT32_MAX) - { - for (i = Lmin; i < Lmax; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - Feptr++; - ACROSSCHAR(Feptr < mb->end_subject, Feptr, Feptr++); - } - } - else - { - Feptr = mb->end_subject; /* Unlimited UTF-8 repeat */ - SCHECK_PARTIAL(); - } - break; - - /* The "byte" (i.e. "code unit") case is the same as non-UTF */ - - case OP_ANYBYTE: - fc = Lmax - Lmin; - if (fc > (uint32_t)(mb->end_subject - Feptr)) - { - Feptr = mb->end_subject; - SCHECK_PARTIAL(); - } - else Feptr += fc; - break; - - case OP_ANYNL: - for (i = Lmin; i < Lmax; i++) - { - int len = 1; - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - GETCHARLEN(fc, Feptr, len); - if (fc == CHAR_CR) - { - if (++Feptr >= mb->end_subject) break; - if (UCHAR21(Feptr) == CHAR_LF) Feptr++; - } - else - { - if (fc != CHAR_LF && - (mb->bsr_convention == PCRE2_BSR_ANYCRLF || - (fc != CHAR_VT && fc != CHAR_FF && fc != CHAR_NEL -#ifndef EBCDIC - && fc != 0x2028 && fc != 0x2029 -#endif /* Not EBCDIC */ - ))) - break; - Feptr += len; - } - } - break; - - case OP_NOT_HSPACE: - case OP_HSPACE: - for (i = Lmin; i < Lmax; i++) - { - BOOL gotspace; - int len = 1; - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - GETCHARLEN(fc, Feptr, len); - switch(fc) - { - HSPACE_CASES: gotspace = TRUE; break; - default: gotspace = FALSE; break; - } - if (gotspace == (Lctype == OP_NOT_HSPACE)) break; - Feptr += len; - } - break; - - case OP_NOT_VSPACE: - case OP_VSPACE: - for (i = Lmin; i < Lmax; i++) - { - BOOL gotspace; - int len = 1; - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - GETCHARLEN(fc, Feptr, len); - switch(fc) - { - VSPACE_CASES: gotspace = TRUE; break; - default: gotspace = FALSE; break; - } - if (gotspace == (Lctype == OP_NOT_VSPACE)) break; - Feptr += len; - } - break; - - case OP_NOT_DIGIT: - for (i = Lmin; i < Lmax; i++) - { - int len = 1; - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - GETCHARLEN(fc, Feptr, len); - if (fc < 256 && (mb->ctypes[fc] & ctype_digit) != 0) break; - Feptr+= len; - } - break; - - case OP_DIGIT: - for (i = Lmin; i < Lmax; i++) - { - int len = 1; - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - GETCHARLEN(fc, Feptr, len); - if (fc >= 256 ||(mb->ctypes[fc] & ctype_digit) == 0) break; - Feptr+= len; - } - break; - - case OP_NOT_WHITESPACE: - for (i = Lmin; i < Lmax; i++) - { - int len = 1; - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - GETCHARLEN(fc, Feptr, len); - if (fc < 256 && (mb->ctypes[fc] & ctype_space) != 0) break; - Feptr+= len; - } - break; - - case OP_WHITESPACE: - for (i = Lmin; i < Lmax; i++) - { - int len = 1; - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - GETCHARLEN(fc, Feptr, len); - if (fc >= 256 ||(mb->ctypes[fc] & ctype_space) == 0) break; - Feptr+= len; - } - break; - - case OP_NOT_WORDCHAR: - for (i = Lmin; i < Lmax; i++) - { - int len = 1; - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - GETCHARLEN(fc, Feptr, len); - if (fc < 256 && (mb->ctypes[fc] & ctype_word) != 0) break; - Feptr+= len; - } - break; - - case OP_WORDCHAR: - for (i = Lmin; i < Lmax; i++) - { - int len = 1; - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - GETCHARLEN(fc, Feptr, len); - if (fc >= 256 || (mb->ctypes[fc] & ctype_word) == 0) break; - Feptr+= len; - } - break; - - default: - return PCRE2_ERROR_INTERNAL; - } - - if (reptype == REPTYPE_POS) continue; /* No backtracking */ - - /* After \C in UTF mode, Lstart_eptr might be in the middle of a - Unicode character. Use <= Lstart_eptr to ensure backtracking doesn't go - too far. */ - - for(;;) - { - if (Feptr <= Lstart_eptr) break; - RMATCH(Fecode, RM221); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - Feptr--; - BACKCHAR(Feptr); - if (Lctype == OP_ANYNL && Feptr > Lstart_eptr && - UCHAR21(Feptr) == CHAR_NL && UCHAR21(Feptr - 1) == CHAR_CR) - Feptr--; - } - } - else -#endif /* SUPPORT_UNICODE */ - - /* Not UTF mode */ - { - switch(Lctype) - { - case OP_ANY: - for (i = Lmin; i < Lmax; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - if (IS_NEWLINE(Feptr)) break; - if (mb->partial != 0 && /* Take care with CRLF partial */ - Feptr + 1 >= mb->end_subject && - NLBLOCK->nltype == NLTYPE_FIXED && - NLBLOCK->nllen == 2 && - *Feptr == NLBLOCK->nl[0]) - { - mb->hitend = TRUE; - if (mb->partial > 1) return PCRE2_ERROR_PARTIAL; - } - Feptr++; - } - break; - - case OP_ALLANY: - case OP_ANYBYTE: - fc = Lmax - Lmin; - if (fc > (uint32_t)(mb->end_subject - Feptr)) - { - Feptr = mb->end_subject; - SCHECK_PARTIAL(); - } - else Feptr += fc; - break; - - case OP_ANYNL: - for (i = Lmin; i < Lmax; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - fc = *Feptr; - if (fc == CHAR_CR) - { - if (++Feptr >= mb->end_subject) break; - if (*Feptr == CHAR_LF) Feptr++; - } - else - { - if (fc != CHAR_LF && (mb->bsr_convention == PCRE2_BSR_ANYCRLF || - (fc != CHAR_VT && fc != CHAR_FF && fc != CHAR_NEL -#if PCRE2_CODE_UNIT_WIDTH != 8 - && fc != 0x2028 && fc != 0x2029 -#endif - ))) break; - Feptr++; - } - } - break; - - case OP_NOT_HSPACE: - for (i = Lmin; i < Lmax; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - switch(*Feptr) - { - default: Feptr++; break; - HSPACE_BYTE_CASES: -#if PCRE2_CODE_UNIT_WIDTH != 8 - HSPACE_MULTIBYTE_CASES: -#endif - goto ENDLOOP00; - } - } - ENDLOOP00: - break; - - case OP_HSPACE: - for (i = Lmin; i < Lmax; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - switch(*Feptr) - { - default: goto ENDLOOP01; - HSPACE_BYTE_CASES: -#if PCRE2_CODE_UNIT_WIDTH != 8 - HSPACE_MULTIBYTE_CASES: -#endif - Feptr++; break; - } - } - ENDLOOP01: - break; - - case OP_NOT_VSPACE: - for (i = Lmin; i < Lmax; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - switch(*Feptr) - { - default: Feptr++; break; - VSPACE_BYTE_CASES: -#if PCRE2_CODE_UNIT_WIDTH != 8 - VSPACE_MULTIBYTE_CASES: -#endif - goto ENDLOOP02; - } - } - ENDLOOP02: - break; - - case OP_VSPACE: - for (i = Lmin; i < Lmax; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - switch(*Feptr) - { - default: goto ENDLOOP03; - VSPACE_BYTE_CASES: -#if PCRE2_CODE_UNIT_WIDTH != 8 - VSPACE_MULTIBYTE_CASES: -#endif - Feptr++; break; - } - } - ENDLOOP03: - break; - - case OP_NOT_DIGIT: - for (i = Lmin; i < Lmax; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - if (MAX_255(*Feptr) && (mb->ctypes[*Feptr] & ctype_digit) != 0) - break; - Feptr++; - } - break; - - case OP_DIGIT: - for (i = Lmin; i < Lmax; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - if (!MAX_255(*Feptr) || (mb->ctypes[*Feptr] & ctype_digit) == 0) - break; - Feptr++; - } - break; - - case OP_NOT_WHITESPACE: - for (i = Lmin; i < Lmax; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - if (MAX_255(*Feptr) && (mb->ctypes[*Feptr] & ctype_space) != 0) - break; - Feptr++; - } - break; - - case OP_WHITESPACE: - for (i = Lmin; i < Lmax; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - if (!MAX_255(*Feptr) || (mb->ctypes[*Feptr] & ctype_space) == 0) - break; - Feptr++; - } - break; - - case OP_NOT_WORDCHAR: - for (i = Lmin; i < Lmax; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - if (MAX_255(*Feptr) && (mb->ctypes[*Feptr] & ctype_word) != 0) - break; - Feptr++; - } - break; - - case OP_WORDCHAR: - for (i = Lmin; i < Lmax; i++) - { - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - break; - } - if (!MAX_255(*Feptr) || (mb->ctypes[*Feptr] & ctype_word) == 0) - break; - Feptr++; - } - break; - - default: - return PCRE2_ERROR_INTERNAL; - } - - if (reptype == REPTYPE_POS) continue; /* No backtracking */ - - for (;;) - { - if (Feptr == Lstart_eptr) break; - RMATCH(Fecode, RM34); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - Feptr--; - if (Lctype == OP_ANYNL && Feptr > Lstart_eptr && *Feptr == CHAR_LF && - Feptr[-1] == CHAR_CR) Feptr--; - } - } - } - break; /* End of repeat character type processing */ - -#undef Lstart_eptr -#undef Lmin -#undef Lmax -#undef Lctype -#undef Lpropvalue - - - /* ===================================================================== */ - /* Match a back reference, possibly repeatedly. Look past the end of the - item to see if there is repeat information following. The OP_REF and - OP_REFI opcodes are used for a reference to a numbered group or to a - non-duplicated named group. For a duplicated named group, OP_DNREF and - OP_DNREFI are used. In this case we must scan the list of groups to which - the name refers, and use the first one that is set. */ - -#define Lmin F->temp_32[0] -#define Lmax F->temp_32[1] -#define Lcaseless F->temp_32[2] -#define Lstart F->temp_sptr[0] -#define Loffset F->temp_size - - case OP_DNREF: - case OP_DNREFI: - Lcaseless = (Fop == OP_DNREFI); - { - int count = GET2(Fecode, 1+IMM2_SIZE); - PCRE2_SPTR slot = mb->name_table + GET2(Fecode, 1) * mb->name_entry_size; - Fecode += 1 + 2*IMM2_SIZE; - - while (count-- > 0) - { - Loffset = (GET2(slot, 0) << 1) - 2; - if (Loffset < Foffset_top && Fovector[Loffset] != PCRE2_UNSET) break; - slot += mb->name_entry_size; - } - } - goto REF_REPEAT; - - case OP_REF: - case OP_REFI: - Lcaseless = (Fop == OP_REFI); - Loffset = (GET2(Fecode, 1) << 1) - 2; - Fecode += 1 + IMM2_SIZE; - - /* Set up for repetition, or handle the non-repeated case. The maximum and - minimum must be in the heap frame, but as they are short-term values, we - use temporary fields. */ - - REF_REPEAT: - switch (*Fecode) - { - case OP_CRSTAR: - case OP_CRMINSTAR: - case OP_CRPLUS: - case OP_CRMINPLUS: - case OP_CRQUERY: - case OP_CRMINQUERY: - fc = *Fecode++ - OP_CRSTAR; - Lmin = rep_min[fc]; - Lmax = rep_max[fc]; - reptype = rep_typ[fc]; - break; - - case OP_CRRANGE: - case OP_CRMINRANGE: - Lmin = GET2(Fecode, 1); - Lmax = GET2(Fecode, 1 + IMM2_SIZE); - reptype = rep_typ[*Fecode - OP_CRSTAR]; - if (Lmax == 0) Lmax = UINT32_MAX; /* Max 0 => infinity */ - Fecode += 1 + 2 * IMM2_SIZE; - break; - - default: /* No repeat follows */ - { - rrc = match_ref(Loffset, Lcaseless, F, mb, &length); - if (rrc != 0) - { - if (rrc > 0) Feptr = mb->end_subject; /* Partial match */ - CHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - } - Feptr += length; - continue; /* With the main loop */ - } - - /* Handle repeated back references. If a set group has length zero, just - continue with the main loop, because it matches however many times. For an - unset reference, if the minimum is zero, we can also just continue. We can - also continue if PCRE2_MATCH_UNSET_BACKREF is set, because this makes unset - group behave as a zero-length group. For any other unset cases, carrying - on will result in NOMATCH. */ - - if (Loffset < Foffset_top && Fovector[Loffset] != PCRE2_UNSET) - { - if (Fovector[Loffset] == Fovector[Loffset + 1]) continue; - } - else /* Group is not set */ - { - if (Lmin == 0 || (mb->poptions & PCRE2_MATCH_UNSET_BACKREF) != 0) - continue; - } - - /* First, ensure the minimum number of matches are present. */ - - for (i = 1; i <= Lmin; i++) - { - PCRE2_SIZE slength; - rrc = match_ref(Loffset, Lcaseless, F, mb, &slength); - if (rrc != 0) - { - if (rrc > 0) Feptr = mb->end_subject; /* Partial match */ - CHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - Feptr += slength; - } - - /* If min = max, we are done. They are not both allowed to be zero. */ - - if (Lmin == Lmax) continue; - - /* If minimizing, keep trying and advancing the pointer. */ - - if (reptype == REPTYPE_MIN) - { - for (;;) - { - PCRE2_SIZE slength; - RMATCH(Fecode, RM20); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH); - rrc = match_ref(Loffset, Lcaseless, F, mb, &slength); - if (rrc != 0) - { - if (rrc > 0) Feptr = mb->end_subject; /* Partial match */ - CHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - Feptr += slength; - } - /* Control never gets here */ - } - - /* If maximizing, find the longest string and work backwards, as long as - the matched lengths for each iteration are the same. */ - - else - { - BOOL samelengths = TRUE; - Lstart = Feptr; /* Starting position */ - Flength = Fovector[Loffset+1] - Fovector[Loffset]; - - for (i = Lmin; i < Lmax; i++) - { - PCRE2_SIZE slength; - rrc = match_ref(Loffset, Lcaseless, F, mb, &slength); - if (rrc != 0) - { - /* Can't use CHECK_PARTIAL because we don't want to update Feptr in - the soft partial matching case. */ - - if (rrc > 0 && mb->partial != 0 && - mb->end_subject > mb->start_used_ptr) - { - mb->hitend = TRUE; - if (mb->partial > 1) return PCRE2_ERROR_PARTIAL; - } - break; - } - - if (slength != Flength) samelengths = FALSE; - Feptr += slength; - } - - /* If the length matched for each repetition is the same as the length of - the captured group, we can easily work backwards. This is the normal - case. However, in caseless UTF-8 mode there are pairs of case-equivalent - characters whose lengths (in terms of code units) differ. However, this - is very rare, so we handle it by re-matching fewer and fewer times. */ - - if (samelengths) - { - while (Feptr >= Lstart) - { - RMATCH(Fecode, RM21); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - Feptr -= Flength; - } - } - - /* The rare case of non-matching lengths. Re-scan the repetition for each - iteration. We know that match_ref() will succeed every time. */ - - else - { - Lmax = i; - for (;;) - { - RMATCH(Fecode, RM22); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (Feptr == Lstart) break; /* Failed after minimal repetition */ - Feptr = Lstart; - Lmax--; - for (i = Lmin; i < Lmax; i++) - { - PCRE2_SIZE slength; - (void)match_ref(Loffset, Lcaseless, F, mb, &slength); - Feptr += slength; - } - } - } - - RRETURN(MATCH_NOMATCH); - } - /* Control never gets here */ - -#undef Lcaseless -#undef Lmin -#undef Lmax -#undef Lstart -#undef Loffset - - - -/* ========================================================================= */ -/* Opcodes for the start of various parenthesized items */ -/* ========================================================================= */ - - /* In all cases, if the result of RMATCH() is MATCH_THEN, check whether the - (*THEN) is within the current branch by comparing the address of OP_THEN - that is passed back with the end of the branch. If (*THEN) is within the - current branch, and the branch is one of two or more alternatives (it - either starts or ends with OP_ALT), we have reached the limit of THEN's - action, so convert the return code to NOMATCH, which will cause normal - backtracking to happen from now on. Otherwise, THEN is passed back to an - outer alternative. This implements Perl's treatment of parenthesized - groups, where a group not containing | does not affect the current - alternative, that is, (X) is NOT the same as (X|(*F)). */ - - - /* ===================================================================== */ - /* BRAZERO, BRAMINZERO and SKIPZERO occur just before a non-possessive - bracket group, indicating that it may occur zero times. It may repeat - infinitely, or not at all - i.e. it could be ()* or ()? or even (){0} in - the pattern. Brackets with fixed upper repeat limits are compiled as a - number of copies, with the optional ones preceded by BRAZERO or BRAMINZERO. - Possessive groups with possible zero repeats are preceded by BRAPOSZERO. */ - -#define Lnext_ecode F->temp_sptr[0] - - case OP_BRAZERO: - Lnext_ecode = Fecode + 1; - RMATCH(Lnext_ecode, RM9); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - do Lnext_ecode += GET(Lnext_ecode, 1); while (*Lnext_ecode == OP_ALT); - Fecode = Lnext_ecode + 1 + LINK_SIZE; - break; - - case OP_BRAMINZERO: - Lnext_ecode = Fecode + 1; - do Lnext_ecode += GET(Lnext_ecode, 1); while (*Lnext_ecode == OP_ALT); - RMATCH(Lnext_ecode + 1 + LINK_SIZE, RM10); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - Fecode++; - break; - -#undef Lnext_ecode - - case OP_SKIPZERO: - Fecode++; - do Fecode += GET(Fecode,1); while (*Fecode == OP_ALT); - Fecode += 1 + LINK_SIZE; - break; - - - /* ===================================================================== */ - /* Handle possessive brackets with an unlimited repeat. The end of these - brackets will always be OP_KETRPOS, which returns MATCH_KETRPOS without - going further in the pattern. */ - -#define Lframe_type F->temp_32[0] -#define Lmatched_once F->temp_32[1] -#define Lzero_allowed F->temp_32[2] -#define Lstart_eptr F->temp_sptr[0] -#define Lstart_group F->temp_sptr[1] - - case OP_BRAPOSZERO: - Lzero_allowed = TRUE; /* Zero repeat is allowed */ - Fecode += 1; - if (*Fecode == OP_CBRAPOS || *Fecode == OP_SCBRAPOS) - goto POSSESSIVE_CAPTURE; - goto POSSESSIVE_NON_CAPTURE; - - case OP_BRAPOS: - case OP_SBRAPOS: - Lzero_allowed = FALSE; /* Zero repeat not allowed */ - - POSSESSIVE_NON_CAPTURE: - Lframe_type = GF_NOCAPTURE; /* Remembered frame type */ - goto POSSESSIVE_GROUP; - - case OP_CBRAPOS: - case OP_SCBRAPOS: - Lzero_allowed = FALSE; /* Zero repeat not allowed */ - - POSSESSIVE_CAPTURE: - number = GET2(Fecode, 1+LINK_SIZE); - Lframe_type = GF_CAPTURE | number; /* Remembered frame type */ - - POSSESSIVE_GROUP: - Lmatched_once = FALSE; /* Never matched */ - Lstart_group = Fecode; /* Start of this group */ - - for (;;) - { - Lstart_eptr = Feptr; /* Position at group start */ - group_frame_type = Lframe_type; - RMATCH(Fecode + PRIV(OP_lengths)[*Fecode], RM8); - if (rrc == MATCH_KETRPOS) - { - Lmatched_once = TRUE; /* Matched at least once */ - if (Feptr == Lstart_eptr) /* Empty match; skip to end */ - { - do Fecode += GET(Fecode, 1); while (*Fecode == OP_ALT); - break; - } - - Fecode = Lstart_group; - continue; - } - - /* See comment above about handling THEN. */ - - if (rrc == MATCH_THEN) - { - PCRE2_SPTR next_ecode = Fecode + GET(Fecode,1); - if (mb->verb_ecode_ptr < next_ecode && - (*Fecode == OP_ALT || *next_ecode == OP_ALT)) - rrc = MATCH_NOMATCH; - } - - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - Fecode += GET(Fecode, 1); - if (*Fecode != OP_ALT) break; - } - - /* Success if matched something or zero repeat allowed */ - - if (Lmatched_once || Lzero_allowed) - { - Fecode += 1 + LINK_SIZE; - break; - } - - RRETURN(MATCH_NOMATCH); - -#undef Lmatched_once -#undef Lzero_allowed -#undef Lframe_type -#undef Lstart_eptr -#undef Lstart_group - - - /* ===================================================================== */ - /* Handle non-capturing brackets that cannot match an empty string. When we - get to the final alternative within the brackets, as long as there are no - THEN's in the pattern, we can optimize by not recording a new backtracking - point. (Ideally we should test for a THEN within this group, but we don't - have that information.) Don't do this if we are at the very top level, - however, because that would make handling assertions and once-only brackets - messier when there is nothing to go back to. */ - -#define Lframe_type F->temp_32[0] /* Set for all that use GROUPLOOP */ -#define Lnext_branch F->temp_sptr[0] /* Used only in OP_BRA handling */ - - case OP_BRA: - if (mb->hasthen || Frdepth == 0) - { - Lframe_type = 0; - goto GROUPLOOP; - } - - for (;;) - { - Lnext_branch = Fecode + GET(Fecode, 1); - if (*Lnext_branch != OP_ALT) break; - - /* This is never the final branch. We do not need to test for MATCH_THEN - here because this code is not used when there is a THEN in the pattern. */ - - RMATCH(Fecode + PRIV(OP_lengths)[*Fecode], RM1); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - Fecode = Lnext_branch; - } - - /* Hit the start of the final branch. Continue at this level. */ - - Fecode += PRIV(OP_lengths)[*Fecode]; - break; - -#undef Lnext_branch - - - /* ===================================================================== */ - /* Handle a capturing bracket, other than those that are possessive with an - unlimited repeat. */ - - case OP_CBRA: - case OP_SCBRA: - Lframe_type = GF_CAPTURE | GET2(Fecode, 1+LINK_SIZE); - goto GROUPLOOP; - - - /* ===================================================================== */ - /* Atomic groups and non-capturing brackets that can match an empty string - must record a backtracking point and also set up a chained frame. */ - - case OP_ONCE: - case OP_SCRIPT_RUN: - case OP_SBRA: - Lframe_type = GF_NOCAPTURE | Fop; - - GROUPLOOP: - for (;;) - { - group_frame_type = Lframe_type; - RMATCH(Fecode + PRIV(OP_lengths)[*Fecode], RM2); - if (rrc == MATCH_THEN) - { - PCRE2_SPTR next_ecode = Fecode + GET(Fecode,1); - if (mb->verb_ecode_ptr < next_ecode && - (*Fecode == OP_ALT || *next_ecode == OP_ALT)) - rrc = MATCH_NOMATCH; - } - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - Fecode += GET(Fecode, 1); - if (*Fecode != OP_ALT) RRETURN(MATCH_NOMATCH); - } - /* Control never reaches here. */ - -#undef Lframe_type - - - /* ===================================================================== */ - /* Recursion either matches the current regex, or some subexpression. The - offset data is the offset to the starting bracket from the start of the - whole pattern. (This is so that it works from duplicated subpatterns.) */ - -#define Lframe_type F->temp_32[0] -#define Lstart_branch F->temp_sptr[0] - - case OP_RECURSE: - bracode = mb->start_code + GET(Fecode, 1); - number = (bracode == mb->start_code)? 0 : GET2(bracode, 1 + LINK_SIZE); - - /* If we are already in a recursion, check for repeating the same one - without advancing the subject pointer. This should catch convoluted mutual - recursions. (Some simple cases are caught at compile time.) */ - - if (Fcurrent_recurse != RECURSE_UNSET) - { - offset = Flast_group_offset; - while (offset != PCRE2_UNSET) - { - N = (heapframe *)((char *)match_data->heapframes + offset); - P = (heapframe *)((char *)N - frame_size); - if (N->group_frame_type == (GF_RECURSE | number)) - { - if (Feptr == P->eptr) return PCRE2_ERROR_RECURSELOOP; - break; - } - offset = P->last_group_offset; - } - } - - /* Now run the recursion, branch by branch. */ - - Lstart_branch = bracode; - Lframe_type = GF_RECURSE | number; - - for (;;) - { - PCRE2_SPTR next_ecode; - - group_frame_type = Lframe_type; - RMATCH(Lstart_branch + PRIV(OP_lengths)[*Lstart_branch], RM11); - next_ecode = Lstart_branch + GET(Lstart_branch,1); - - /* Handle backtracking verbs, which are defined in a range that can - easily be tested for. PCRE does not allow THEN, SKIP, PRUNE or COMMIT to - escape beyond a recursion; they cause a NOMATCH for the entire recursion. - - When one of these verbs triggers, the current recursion group number is - recorded. If it matches the recursion we are processing, the verb - happened within the recursion and we must deal with it. Otherwise it must - have happened after the recursion completed, and so has to be passed - back. See comment above about handling THEN. */ - - if (rrc >= MATCH_BACKTRACK_MIN && rrc <= MATCH_BACKTRACK_MAX && - mb->verb_current_recurse == (Lframe_type ^ GF_RECURSE)) - { - if (rrc == MATCH_THEN && mb->verb_ecode_ptr < next_ecode && - (*Lstart_branch == OP_ALT || *next_ecode == OP_ALT)) - rrc = MATCH_NOMATCH; - else RRETURN(MATCH_NOMATCH); - } - - /* Note that carrying on after (*ACCEPT) in a recursion is handled in the - OP_ACCEPT code. Nothing needs to be done here. */ - - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - Lstart_branch = next_ecode; - if (*Lstart_branch != OP_ALT) RRETURN(MATCH_NOMATCH); - } - /* Control never reaches here. */ - -#undef Lframe_type -#undef Lstart_branch - - - /* ===================================================================== */ - /* Positive assertions are like other groups except that PCRE doesn't allow - the effect of (*THEN) to escape beyond an assertion; it is therefore - treated as NOMATCH. (*ACCEPT) is treated as successful assertion, with its - captures and mark retained. Any other return is an error. */ - -#define Lframe_type F->temp_32[0] - - case OP_ASSERT: - case OP_ASSERTBACK: - case OP_ASSERT_NA: - case OP_ASSERTBACK_NA: - Lframe_type = GF_NOCAPTURE | Fop; - for (;;) - { - group_frame_type = Lframe_type; - RMATCH(Fecode + PRIV(OP_lengths)[*Fecode], RM3); - if (rrc == MATCH_ACCEPT) - { - memcpy(Fovector, - (char *)assert_accept_frame + offsetof(heapframe, ovector), - assert_accept_frame->offset_top * sizeof(PCRE2_SIZE)); - Foffset_top = assert_accept_frame->offset_top; - Fmark = assert_accept_frame->mark; - break; - } - if (rrc != MATCH_NOMATCH && rrc != MATCH_THEN) RRETURN(rrc); - Fecode += GET(Fecode, 1); - if (*Fecode != OP_ALT) RRETURN(MATCH_NOMATCH); - } - - do Fecode += GET(Fecode, 1); while (*Fecode == OP_ALT); - Fecode += 1 + LINK_SIZE; - break; - -#undef Lframe_type - - - /* ===================================================================== */ - /* Handle negative assertions. Loop for each non-matching branch as for - positive assertions. */ - -#define Lframe_type F->temp_32[0] - - case OP_ASSERT_NOT: - case OP_ASSERTBACK_NOT: - Lframe_type = GF_NOCAPTURE | Fop; - - for (;;) - { - group_frame_type = Lframe_type; - RMATCH(Fecode + PRIV(OP_lengths)[*Fecode], RM4); - switch(rrc) - { - case MATCH_ACCEPT: /* Assertion matched, therefore it fails. */ - case MATCH_MATCH: - RRETURN (MATCH_NOMATCH); - - case MATCH_NOMATCH: /* Branch failed, try next if present. */ - case MATCH_THEN: - Fecode += GET(Fecode, 1); - if (*Fecode != OP_ALT) goto ASSERT_NOT_FAILED; - break; - - case MATCH_COMMIT: /* Assertion forced to fail, therefore continue. */ - case MATCH_SKIP: - case MATCH_PRUNE: - do Fecode += GET(Fecode, 1); while (*Fecode == OP_ALT); - goto ASSERT_NOT_FAILED; - - default: /* Pass back any other return */ - RRETURN(rrc); - } - } - - /* None of the branches have matched or there was a backtrack to (*COMMIT), - (*SKIP), (*PRUNE), or (*THEN) in the last branch. This is success for a - negative assertion, so carry on. */ - - ASSERT_NOT_FAILED: - Fecode += 1 + LINK_SIZE; - break; - -#undef Lframe_type - - - /* ===================================================================== */ - /* The callout item calls an external function, if one is provided, passing - details of the match so far. This is mainly for debugging, though the - function is able to force a failure. */ - - case OP_CALLOUT: - case OP_CALLOUT_STR: - rrc = do_callout(F, mb, &length); - if (rrc > 0) RRETURN(MATCH_NOMATCH); - if (rrc < 0) RRETURN(rrc); - Fecode += length; - break; - - - /* ===================================================================== */ - /* Conditional group: compilation checked that there are no more than two - branches. If the condition is false, skipping the first branch takes us - past the end of the item if there is only one branch, but that's exactly - what we want. */ - - case OP_COND: - case OP_SCOND: - - /* The variable Flength will be added to Fecode when the condition is - false, to get to the second branch. Setting it to the offset to the ALT or - KET, then incrementing Fecode achieves this effect. However, if the second - branch is non-existent, we must point to the KET so that the end of the - group is correctly processed. We now have Fecode pointing to the condition - or callout. */ - - Flength = GET(Fecode, 1); /* Offset to the second branch */ - if (Fecode[Flength] != OP_ALT) Flength -= 1 + LINK_SIZE; - Fecode += 1 + LINK_SIZE; /* From this opcode */ - - /* Because of the way auto-callout works during compile, a callout item is - inserted between OP_COND and an assertion condition. Such a callout can - also be inserted manually. */ - - if (*Fecode == OP_CALLOUT || *Fecode == OP_CALLOUT_STR) - { - rrc = do_callout(F, mb, &length); - if (rrc > 0) RRETURN(MATCH_NOMATCH); - if (rrc < 0) RRETURN(rrc); - - /* Advance Fecode past the callout, so it now points to the condition. We - must adjust Flength so that the value of Fecode+Flength is unchanged. */ - - Fecode += length; - Flength -= length; - } - - /* Test the various possible conditions */ - - condition = FALSE; - switch(*Fecode) - { - case OP_RREF: /* Group recursion test */ - if (Fcurrent_recurse != RECURSE_UNSET) - { - number = GET2(Fecode, 1); - condition = (number == RREF_ANY || number == Fcurrent_recurse); - } - break; - - case OP_DNRREF: /* Duplicate named group recursion test */ - if (Fcurrent_recurse != RECURSE_UNSET) - { - int count = GET2(Fecode, 1 + IMM2_SIZE); - PCRE2_SPTR slot = mb->name_table + GET2(Fecode, 1) * mb->name_entry_size; - while (count-- > 0) - { - number = GET2(slot, 0); - condition = number == Fcurrent_recurse; - if (condition) break; - slot += mb->name_entry_size; - } - } - break; - - case OP_CREF: /* Numbered group used test */ - offset = (GET2(Fecode, 1) << 1) - 2; /* Doubled ref number */ - condition = offset < Foffset_top && Fovector[offset] != PCRE2_UNSET; - break; - - case OP_DNCREF: /* Duplicate named group used test */ - { - int count = GET2(Fecode, 1 + IMM2_SIZE); - PCRE2_SPTR slot = mb->name_table + GET2(Fecode, 1) * mb->name_entry_size; - while (count-- > 0) - { - offset = (GET2(slot, 0) << 1) - 2; - condition = offset < Foffset_top && Fovector[offset] != PCRE2_UNSET; - if (condition) break; - slot += mb->name_entry_size; - } - } - break; - - case OP_FALSE: - case OP_FAIL: /* The assertion (?!) becomes OP_FAIL */ - break; - - case OP_TRUE: - condition = TRUE; - break; - - /* The condition is an assertion. Run code similar to the assertion code - above. */ - -#define Lpositive F->temp_32[0] -#define Lstart_branch F->temp_sptr[0] - - default: - Lpositive = (*Fecode == OP_ASSERT || *Fecode == OP_ASSERTBACK); - Lstart_branch = Fecode; - - for (;;) - { - group_frame_type = GF_CONDASSERT | *Fecode; - RMATCH(Lstart_branch + PRIV(OP_lengths)[*Lstart_branch], RM5); - - switch(rrc) - { - case MATCH_ACCEPT: /* Save captures */ - memcpy(Fovector, - (char *)assert_accept_frame + offsetof(heapframe, ovector), - assert_accept_frame->offset_top * sizeof(PCRE2_SIZE)); - Foffset_top = assert_accept_frame->offset_top; - - /* Fall through */ - /* In the case of a match, the captures have already been put into - the current frame. */ - - case MATCH_MATCH: - condition = Lpositive; /* TRUE for positive assertion */ - break; - - /* PCRE doesn't allow the effect of (*THEN) to escape beyond an - assertion; it is therefore always treated as NOMATCH. */ - - case MATCH_NOMATCH: - case MATCH_THEN: - Lstart_branch += GET(Lstart_branch, 1); - if (*Lstart_branch == OP_ALT) continue; /* Try next branch */ - condition = !Lpositive; /* TRUE for negative assertion */ - break; - - /* These force no match without checking other branches. */ - - case MATCH_COMMIT: - case MATCH_SKIP: - case MATCH_PRUNE: - condition = !Lpositive; - break; - - default: - RRETURN(rrc); - } - break; /* Out of the branch loop */ - } - - /* If the condition is true, find the end of the assertion so that - advancing past it gets us to the start of the first branch. */ - - if (condition) - { - do Fecode += GET(Fecode, 1); while (*Fecode == OP_ALT); - } - break; /* End of assertion condition */ - } - -#undef Lpositive -#undef Lstart_branch - - /* Choose branch according to the condition. */ - - Fecode += condition? PRIV(OP_lengths)[*Fecode] : Flength; - - /* If the opcode is OP_SCOND it means we are at a repeated conditional - group that might match an empty string. We must therefore descend a level - so that the start is remembered for checking. For OP_COND we can just - continue at this level. */ - - if (Fop == OP_SCOND) - { - group_frame_type = GF_NOCAPTURE | Fop; - RMATCH(Fecode, RM35); - RRETURN(rrc); - } - break; - - - -/* ========================================================================= */ -/* End of start of parenthesis opcodes */ -/* ========================================================================= */ - - - /* ===================================================================== */ - /* Move the subject pointer back. This occurs only at the start of each - branch of a lookbehind assertion. If we are too close to the start to move - back, fail. When working with UTF-8 we move back a number of characters, - not bytes. */ - - case OP_REVERSE: - number = GET(Fecode, 1); -#ifdef SUPPORT_UNICODE - if (utf) - { - while (number-- > 0) - { - if (Feptr <= mb->check_subject) RRETURN(MATCH_NOMATCH); - Feptr--; - BACKCHAR(Feptr); - } - } - else -#endif - - /* No UTF-8 support, or not in UTF-8 mode: count is code unit count */ - - { - if ((ptrdiff_t)number > Feptr - mb->start_subject) RRETURN(MATCH_NOMATCH); - Feptr -= number; - } - - /* Save the earliest consulted character, then skip to next opcode */ - - if (Feptr < mb->start_used_ptr) mb->start_used_ptr = Feptr; - Fecode += 1 + LINK_SIZE; - break; - - - /* ===================================================================== */ - /* An alternation is the end of a branch; scan along to find the end of the - bracketed group. */ - - case OP_ALT: - do Fecode += GET(Fecode,1); while (*Fecode == OP_ALT); - break; - - - /* ===================================================================== */ - /* The end of a parenthesized group. For all but OP_BRA and OP_COND, the - starting frame was added to the chained frames in order to remember the - starting subject position for the group. */ - - case OP_KET: - case OP_KETRMIN: - case OP_KETRMAX: - case OP_KETRPOS: - - bracode = Fecode - GET(Fecode, 1); - - /* Point N to the frame at the start of the most recent group. - Remember the subject pointer at the start of the group. */ - - if (*bracode != OP_BRA && *bracode != OP_COND) - { - N = (heapframe *)((char *)match_data->heapframes + Flast_group_offset); - P = (heapframe *)((char *)N - frame_size); - Flast_group_offset = P->last_group_offset; - -#ifdef DEBUG_SHOW_RMATCH - fprintf(stderr, "++ KET for frame=%d type=%x prev char offset=%lu\n", - N->rdepth, N->group_frame_type, - (char *)P->eptr - (char *)mb->start_subject); -#endif - - /* If we are at the end of an assertion that is a condition, return a - match, discarding any intermediate backtracking points. Copy back the - mark setting and the captures into the frame before N so that they are - set on return. Doing this for all assertions, both positive and negative, - seems to match what Perl does. */ - - if (GF_IDMASK(N->group_frame_type) == GF_CONDASSERT) - { - memcpy((char *)P + offsetof(heapframe, ovector), Fovector, - Foffset_top * sizeof(PCRE2_SIZE)); - P->offset_top = Foffset_top; - P->mark = Fmark; - Fback_frame = (char *)F - (char *)P; - RRETURN(MATCH_MATCH); - } - } - else P = NULL; /* Indicates starting frame not recorded */ - - /* The group was not a conditional assertion. */ - - switch (*bracode) - { - case OP_BRA: /* No need to do anything for these */ - case OP_COND: - case OP_SCOND: - break; - - /* Non-atomic positive assertions are like OP_BRA, except that the - subject pointer must be put back to where it was at the start of the - assertion. */ - - case OP_ASSERT_NA: - case OP_ASSERTBACK_NA: - if (Feptr > mb->last_used_ptr) mb->last_used_ptr = Feptr; - Feptr = P->eptr; - break; - - /* Atomic positive assertions are like OP_ONCE, except that in addition - the subject pointer must be put back to where it was at the start of the - assertion. */ - - case OP_ASSERT: - case OP_ASSERTBACK: - if (Feptr > mb->last_used_ptr) mb->last_used_ptr = Feptr; - Feptr = P->eptr; - /* Fall through */ - - /* For an atomic group, discard internal backtracking points. We must - also ensure that any remaining branches within the top-level of the group - are not tried. Do this by adjusting the code pointer within the backtrack - frame so that it points to the final branch. */ - - case OP_ONCE: - Fback_frame = ((char *)F - (char *)P); - for (;;) - { - uint32_t y = GET(P->ecode,1); - if ((P->ecode)[y] != OP_ALT) break; - P->ecode += y; - } - break; - - /* A matching negative assertion returns MATCH, which is turned into - NOMATCH at the assertion level. */ - - case OP_ASSERT_NOT: - case OP_ASSERTBACK_NOT: - RRETURN(MATCH_MATCH); - - /* At the end of a script run, apply the script-checking rules. This code - will never by exercised if Unicode support it not compiled, because in - that environment script runs cause an error at compile time. */ - - case OP_SCRIPT_RUN: - if (!PRIV(script_run)(P->eptr, Feptr, utf)) RRETURN(MATCH_NOMATCH); - break; - - /* Whole-pattern recursion is coded as a recurse into group 0, so it - won't be picked up here. Instead, we catch it when the OP_END is reached. - Other recursion is handled here. */ - - case OP_CBRA: - case OP_CBRAPOS: - case OP_SCBRA: - case OP_SCBRAPOS: - number = GET2(bracode, 1+LINK_SIZE); - - /* Handle a recursively called group. We reinstate the previous set of - captures and then carry on after the recursion call. */ - - if (Fcurrent_recurse == number) - { - P = (heapframe *)((char *)N - frame_size); - memcpy((char *)F + offsetof(heapframe, ovector), P->ovector, - P->offset_top * sizeof(PCRE2_SIZE)); - Foffset_top = P->offset_top; - Fcapture_last = P->capture_last; - Fcurrent_recurse = P->current_recurse; - Fecode = P->ecode + 1 + LINK_SIZE; - continue; /* With next opcode */ - } - - /* Deal with actual capturing. */ - - offset = (number << 1) - 2; - Fcapture_last = number; - Fovector[offset] = P->eptr - mb->start_subject; - Fovector[offset+1] = Feptr - mb->start_subject; - if (offset >= Foffset_top) Foffset_top = offset + 2; - break; - } /* End actions relating to the starting opcode */ - - /* OP_KETRPOS is a possessive repeating ket. Remember the current position, - and return the MATCH_KETRPOS. This makes it possible to do the repeats one - at a time from the outer level. This must precede the empty string test - - in this case that test is done at the outer level. */ - - if (*Fecode == OP_KETRPOS) - { - memcpy((char *)P + offsetof(heapframe, eptr), - (char *)F + offsetof(heapframe, eptr), - frame_copy_size); - RRETURN(MATCH_KETRPOS); - } - - /* Handle the different kinds of closing brackets. A non-repeating ket - needs no special action, just continuing at this level. This also happens - for the repeating kets if the group matched no characters, in order to - forcibly break infinite loops. Otherwise, the repeating kets try the rest - of the pattern or restart from the preceding bracket, in the appropriate - order. */ - - if (Fop != OP_KET && (P == NULL || Feptr != P->eptr)) - { - if (Fop == OP_KETRMIN) - { - RMATCH(Fecode + 1 + LINK_SIZE, RM6); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - Fecode -= GET(Fecode, 1); - break; /* End of ket processing */ - } - - /* Repeat the maximum number of times (KETRMAX) */ - - RMATCH(bracode, RM7); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - } - - /* Carry on at this level for a non-repeating ket, or after matching an - empty string, or after repeating for a maximum number of times. */ - - Fecode += 1 + LINK_SIZE; - break; - - - /* ===================================================================== */ - /* Start and end of line assertions, not multiline mode. */ - - case OP_CIRC: /* Start of line, unless PCRE2_NOTBOL is set. */ - if (Feptr != mb->start_subject || (mb->moptions & PCRE2_NOTBOL) != 0) - RRETURN(MATCH_NOMATCH); - Fecode++; - break; - - case OP_SOD: /* Unconditional start of subject */ - if (Feptr != mb->start_subject) RRETURN(MATCH_NOMATCH); - Fecode++; - break; - - /* When PCRE2_NOTEOL is unset, assert before the subject end, or a - terminating newline unless PCRE2_DOLLAR_ENDONLY is set. */ - - case OP_DOLL: - if ((mb->moptions & PCRE2_NOTEOL) != 0) RRETURN(MATCH_NOMATCH); - if ((mb->poptions & PCRE2_DOLLAR_ENDONLY) == 0) goto ASSERT_NL_OR_EOS; - - /* Fall through */ - /* Unconditional end of subject assertion (\z) */ - - case OP_EOD: - if (Feptr < mb->end_subject) RRETURN(MATCH_NOMATCH); - if (mb->partial != 0) - { - mb->hitend = TRUE; - if (mb->partial > 1) return PCRE2_ERROR_PARTIAL; - } - Fecode++; - break; - - /* End of subject or ending \n assertion (\Z) */ - - case OP_EODN: - ASSERT_NL_OR_EOS: - if (Feptr < mb->end_subject && - (!IS_NEWLINE(Feptr) || Feptr != mb->end_subject - mb->nllen)) - { - if (mb->partial != 0 && - Feptr + 1 >= mb->end_subject && - NLBLOCK->nltype == NLTYPE_FIXED && - NLBLOCK->nllen == 2 && - UCHAR21TEST(Feptr) == NLBLOCK->nl[0]) - { - mb->hitend = TRUE; - if (mb->partial > 1) return PCRE2_ERROR_PARTIAL; - } - RRETURN(MATCH_NOMATCH); - } - - /* Either at end of string or \n before end. */ - - if (mb->partial != 0) - { - mb->hitend = TRUE; - if (mb->partial > 1) return PCRE2_ERROR_PARTIAL; - } - Fecode++; - break; - - - /* ===================================================================== */ - /* Start and end of line assertions, multiline mode. */ - - /* Start of subject unless notbol, or after any newline except for one at - the very end, unless PCRE2_ALT_CIRCUMFLEX is set. */ - - case OP_CIRCM: - if ((mb->moptions & PCRE2_NOTBOL) != 0 && Feptr == mb->start_subject) - RRETURN(MATCH_NOMATCH); - if (Feptr != mb->start_subject && - ((Feptr == mb->end_subject && - (mb->poptions & PCRE2_ALT_CIRCUMFLEX) == 0) || - !WAS_NEWLINE(Feptr))) - RRETURN(MATCH_NOMATCH); - Fecode++; - break; - - /* Assert before any newline, or before end of subject unless noteol is - set. */ - - case OP_DOLLM: - if (Feptr < mb->end_subject) - { - if (!IS_NEWLINE(Feptr)) - { - if (mb->partial != 0 && - Feptr + 1 >= mb->end_subject && - NLBLOCK->nltype == NLTYPE_FIXED && - NLBLOCK->nllen == 2 && - UCHAR21TEST(Feptr) == NLBLOCK->nl[0]) - { - mb->hitend = TRUE; - if (mb->partial > 1) return PCRE2_ERROR_PARTIAL; - } - RRETURN(MATCH_NOMATCH); - } - } - else - { - if ((mb->moptions & PCRE2_NOTEOL) != 0) RRETURN(MATCH_NOMATCH); - SCHECK_PARTIAL(); - } - Fecode++; - break; - - - /* ===================================================================== */ - /* Start of match assertion */ - - case OP_SOM: - if (Feptr != mb->start_subject + mb->start_offset) RRETURN(MATCH_NOMATCH); - Fecode++; - break; - - - /* ===================================================================== */ - /* Reset the start of match point */ - - case OP_SET_SOM: - Fstart_match = Feptr; - Fecode++; - break; - - - /* ===================================================================== */ - /* Word boundary assertions. Find out if the previous and current - characters are "word" characters. It takes a bit more work in UTF mode. - Characters > 255 are assumed to be "non-word" characters when PCRE2_UCP is - not set. When it is set, use Unicode properties if available, even when not - in UTF mode. Remember the earliest and latest consulted characters. */ - - case OP_NOT_WORD_BOUNDARY: - case OP_WORD_BOUNDARY: - if (Feptr == mb->check_subject) prev_is_word = FALSE; else - { - PCRE2_SPTR lastptr = Feptr - 1; -#ifdef SUPPORT_UNICODE - if (utf) - { - BACKCHAR(lastptr); - GETCHAR(fc, lastptr); - } - else -#endif /* SUPPORT_UNICODE */ - fc = *lastptr; - if (lastptr < mb->start_used_ptr) mb->start_used_ptr = lastptr; -#ifdef SUPPORT_UNICODE - if ((mb->poptions & PCRE2_UCP) != 0) - { - if (fc == '_') prev_is_word = TRUE; else - { - int cat = UCD_CATEGORY(fc); - prev_is_word = (cat == ucp_L || cat == ucp_N); - } - } - else -#endif /* SUPPORT_UNICODE */ - prev_is_word = CHMAX_255(fc) && (mb->ctypes[fc] & ctype_word) != 0; - } - - /* Get status of next character */ - - if (Feptr >= mb->end_subject) - { - SCHECK_PARTIAL(); - cur_is_word = FALSE; - } - else - { - PCRE2_SPTR nextptr = Feptr + 1; -#ifdef SUPPORT_UNICODE - if (utf) - { - FORWARDCHARTEST(nextptr, mb->end_subject); - GETCHAR(fc, Feptr); - } - else -#endif /* SUPPORT_UNICODE */ - fc = *Feptr; - if (nextptr > mb->last_used_ptr) mb->last_used_ptr = nextptr; -#ifdef SUPPORT_UNICODE - if ((mb->poptions & PCRE2_UCP) != 0) - { - if (fc == '_') cur_is_word = TRUE; else - { - int cat = UCD_CATEGORY(fc); - cur_is_word = (cat == ucp_L || cat == ucp_N); - } - } - else -#endif /* SUPPORT_UNICODE */ - cur_is_word = CHMAX_255(fc) && (mb->ctypes[fc] & ctype_word) != 0; - } - - /* Now see if the situation is what we want */ - - if ((*Fecode++ == OP_WORD_BOUNDARY)? - cur_is_word == prev_is_word : cur_is_word != prev_is_word) - RRETURN(MATCH_NOMATCH); - break; - - - /* ===================================================================== */ - /* Backtracking (*VERB)s, with and without arguments. Note that if the - pattern is successfully matched, we do not come back from RMATCH. */ - - case OP_MARK: - Fmark = mb->nomatch_mark = Fecode + 2; - RMATCH(Fecode + PRIV(OP_lengths)[*Fecode] + Fecode[1], RM12); - - /* A return of MATCH_SKIP_ARG means that matching failed at SKIP with an - argument, and we must check whether that argument matches this MARK's - argument. It is passed back in mb->verb_skip_ptr. If it does match, we - return MATCH_SKIP with mb->verb_skip_ptr now pointing to the subject - position that corresponds to this mark. Otherwise, pass back the return - code unaltered. */ - - if (rrc == MATCH_SKIP_ARG && - PRIV(strcmp)(Fecode + 2, mb->verb_skip_ptr) == 0) - { - mb->verb_skip_ptr = Feptr; /* Pass back current position */ - RRETURN(MATCH_SKIP); - } - RRETURN(rrc); - - case OP_FAIL: - RRETURN(MATCH_NOMATCH); - - /* Record the current recursing group number in mb->verb_current_recurse - when a backtracking return such as MATCH_COMMIT is given. This enables the - recurse processing to catch verbs from within the recursion. */ - - case OP_COMMIT: - RMATCH(Fecode + PRIV(OP_lengths)[*Fecode], RM13); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - mb->verb_current_recurse = Fcurrent_recurse; - RRETURN(MATCH_COMMIT); - - case OP_COMMIT_ARG: - Fmark = mb->nomatch_mark = Fecode + 2; - RMATCH(Fecode + PRIV(OP_lengths)[*Fecode] + Fecode[1], RM36); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - mb->verb_current_recurse = Fcurrent_recurse; - RRETURN(MATCH_COMMIT); - - case OP_PRUNE: - RMATCH(Fecode + PRIV(OP_lengths)[*Fecode], RM14); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - mb->verb_current_recurse = Fcurrent_recurse; - RRETURN(MATCH_PRUNE); - - case OP_PRUNE_ARG: - Fmark = mb->nomatch_mark = Fecode + 2; - RMATCH(Fecode + PRIV(OP_lengths)[*Fecode] + Fecode[1], RM15); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - mb->verb_current_recurse = Fcurrent_recurse; - RRETURN(MATCH_PRUNE); - - case OP_SKIP: - RMATCH(Fecode + PRIV(OP_lengths)[*Fecode], RM16); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - mb->verb_skip_ptr = Feptr; /* Pass back current position */ - mb->verb_current_recurse = Fcurrent_recurse; - RRETURN(MATCH_SKIP); - - /* Note that, for Perl compatibility, SKIP with an argument does NOT set - nomatch_mark. When a pattern match ends with a SKIP_ARG for which there was - not a matching mark, we have to re-run the match, ignoring the SKIP_ARG - that failed and any that precede it (either they also failed, or were not - triggered). To do this, we maintain a count of executed SKIP_ARGs. If a - SKIP_ARG gets to top level, the match is re-run with mb->ignore_skip_arg - set to the count of the one that failed. */ - - case OP_SKIP_ARG: - mb->skip_arg_count++; - if (mb->skip_arg_count <= mb->ignore_skip_arg) - { - Fecode += PRIV(OP_lengths)[*Fecode] + Fecode[1]; - break; - } - RMATCH(Fecode + PRIV(OP_lengths)[*Fecode] + Fecode[1], RM17); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - - /* Pass back the current skip name and return the special MATCH_SKIP_ARG - return code. This will either be caught by a matching MARK, or get to the - top, where it causes a rematch with mb->ignore_skip_arg set to the value of - mb->skip_arg_count. */ - - mb->verb_skip_ptr = Fecode + 2; - mb->verb_current_recurse = Fcurrent_recurse; - RRETURN(MATCH_SKIP_ARG); - - /* For THEN (and THEN_ARG) we pass back the address of the opcode, so that - the branch in which it occurs can be determined. */ - - case OP_THEN: - RMATCH(Fecode + PRIV(OP_lengths)[*Fecode], RM18); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - mb->verb_ecode_ptr = Fecode; - mb->verb_current_recurse = Fcurrent_recurse; - RRETURN(MATCH_THEN); - - case OP_THEN_ARG: - Fmark = mb->nomatch_mark = Fecode + 2; - RMATCH(Fecode + PRIV(OP_lengths)[*Fecode] + Fecode[1], RM19); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - mb->verb_ecode_ptr = Fecode; - mb->verb_current_recurse = Fcurrent_recurse; - RRETURN(MATCH_THEN); - - - /* ===================================================================== */ - /* There's been some horrible disaster. Arrival here can only mean there is - something seriously wrong in the code above or the OP_xxx definitions. */ - - default: - return PCRE2_ERROR_INTERNAL; - } - - /* Do not insert any code in here without much thought; it is assumed - that "continue" in the code above comes out to here to repeat the main - loop. */ - - } /* End of main loop */ -/* Control never reaches here */ - - -/* ========================================================================= */ -/* The RRETURN() macro jumps here. The number that is saved in Freturn_id -indicates which label we actually want to return to. The value in Frdepth is -the index number of the frame in the vector. The return value has been placed -in rrc. */ - -#define LBL(val) case val: goto L_RM##val; - -RETURN_SWITCH: -if (Feptr > mb->last_used_ptr) mb->last_used_ptr = Feptr; -if (Frdepth == 0) return rrc; /* Exit from the top level */ -F = (heapframe *)((char *)F - Fback_frame); /* Backtrack */ -mb->cb->callout_flags |= PCRE2_CALLOUT_BACKTRACK; /* Note for callouts */ - -#ifdef DEBUG_SHOW_RMATCH -fprintf(stderr, "++ RETURN %d to %d\n", rrc, Freturn_id); -#endif - -switch (Freturn_id) - { - LBL( 1) LBL( 2) LBL( 3) LBL( 4) LBL( 5) LBL( 6) LBL( 7) LBL( 8) - LBL( 9) LBL(10) LBL(11) LBL(12) LBL(13) LBL(14) LBL(15) LBL(16) - LBL(17) LBL(18) LBL(19) LBL(20) LBL(21) LBL(22) LBL(23) LBL(24) - LBL(25) LBL(26) LBL(27) LBL(28) LBL(29) LBL(30) LBL(31) LBL(32) - LBL(33) LBL(34) LBL(35) LBL(36) - -#ifdef SUPPORT_WIDE_CHARS - LBL(100) LBL(101) -#endif - -#ifdef SUPPORT_UNICODE - LBL(200) LBL(201) LBL(202) LBL(203) LBL(204) LBL(205) LBL(206) - LBL(207) LBL(208) LBL(209) LBL(210) LBL(211) LBL(212) LBL(213) - LBL(214) LBL(215) LBL(216) LBL(217) LBL(218) LBL(219) LBL(220) - LBL(221) LBL(222) LBL(223) LBL(224) LBL(225) -#endif - - default: - return PCRE2_ERROR_INTERNAL; - } -#undef LBL -} - - -/************************************************* -* Match a Regular Expression * -*************************************************/ - -/* This function applies a compiled pattern to a subject string and picks out -portions of the string if it matches. Two elements in the vector are set for -each substring: the offsets to the start and end of the substring. - -Arguments: - code points to the compiled expression - subject points to the subject string - length length of subject string (may contain binary zeros) - start_offset where to start in the subject string - options option bits - match_data points to a match_data block - mcontext points a PCRE2 context - -Returns: > 0 => success; value is the number of ovector pairs filled - = 0 => success, but ovector is not big enough - = -1 => failed to match (PCRE2_ERROR_NOMATCH) - = -2 => partial match (PCRE2_ERROR_PARTIAL) - < -2 => some kind of unexpected problem -*/ - -PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION -pcre2_match(const pcre2_code *code, PCRE2_SPTR subject, PCRE2_SIZE length, - PCRE2_SIZE start_offset, uint32_t options, pcre2_match_data *match_data, - pcre2_match_context *mcontext) -{ -int rc; -int was_zero_terminated = 0; -const uint8_t *start_bits = NULL; -const pcre2_real_code *re = (const pcre2_real_code *)code; - -BOOL anchored; -BOOL firstline; -BOOL has_first_cu = FALSE; -BOOL has_req_cu = FALSE; -BOOL startline; - -#if PCRE2_CODE_UNIT_WIDTH == 8 -PCRE2_SPTR memchr_found_first_cu; -PCRE2_SPTR memchr_found_first_cu2; -#endif - -PCRE2_UCHAR first_cu = 0; -PCRE2_UCHAR first_cu2 = 0; -PCRE2_UCHAR req_cu = 0; -PCRE2_UCHAR req_cu2 = 0; - -PCRE2_SPTR bumpalong_limit; -PCRE2_SPTR end_subject; -PCRE2_SPTR true_end_subject; -PCRE2_SPTR start_match; -PCRE2_SPTR req_cu_ptr; -PCRE2_SPTR start_partial; -PCRE2_SPTR match_partial; - -#ifdef SUPPORT_JIT -BOOL use_jit; -#endif - -/* This flag is needed even when Unicode is not supported for convenience -(it is used by the IS_NEWLINE macro). */ - -BOOL utf = FALSE; - -#ifdef SUPPORT_UNICODE -BOOL ucp = FALSE; -BOOL allow_invalid; -uint32_t fragment_options = 0; -#ifdef SUPPORT_JIT -BOOL jit_checked_utf = FALSE; -#endif -#endif /* SUPPORT_UNICODE */ - -PCRE2_SIZE frame_size; -PCRE2_SIZE heapframes_size; - -/* We need to have mb as a pointer to a match block, because the IS_NEWLINE -macro is used below, and it expects NLBLOCK to be defined as a pointer. */ - -pcre2_callout_block cb; -match_block actual_match_block; -match_block *mb = &actual_match_block; - -/* Recognize NULL, length 0 as an empty string. */ - -if (subject == NULL && length == 0) subject = (PCRE2_SPTR)""; - -/* Plausibility checks */ - -if ((options & ~PUBLIC_MATCH_OPTIONS) != 0) return PCRE2_ERROR_BADOPTION; -if (code == NULL || subject == NULL || match_data == NULL) - return PCRE2_ERROR_NULL; - -start_match = subject + start_offset; -req_cu_ptr = start_match - 1; -if (length == PCRE2_ZERO_TERMINATED) - { - length = PRIV(strlen)(subject); - was_zero_terminated = 1; - } -true_end_subject = end_subject = subject + length; - -if (start_offset > length) return PCRE2_ERROR_BADOFFSET; - -/* Check that the first field in the block is the magic number. */ - -if (re->magic_number != MAGIC_NUMBER) return PCRE2_ERROR_BADMAGIC; - -/* Check the code unit width. */ - -if ((re->flags & PCRE2_MODE_MASK) != PCRE2_CODE_UNIT_WIDTH/8) - return PCRE2_ERROR_BADMODE; - -/* PCRE2_NOTEMPTY and PCRE2_NOTEMPTY_ATSTART are match-time flags in the -options variable for this function. Users of PCRE2 who are not calling the -function directly would like to have a way of setting these flags, in the same -way that they can set pcre2_compile() flags like PCRE2_NO_AUTOPOSSESS with -constructions like (*NO_AUTOPOSSESS). To enable this, (*NOTEMPTY) and -(*NOTEMPTY_ATSTART) set bits in the pattern's "flag" function which we now -transfer to the options for this function. The bits are guaranteed to be -adjacent, but do not have the same values. This bit of Boolean trickery assumes -that the match-time bits are not more significant than the flag bits. If by -accident this is not the case, a compile-time division by zero error will -occur. */ - -#define FF (PCRE2_NOTEMPTY_SET|PCRE2_NE_ATST_SET) -#define OO (PCRE2_NOTEMPTY|PCRE2_NOTEMPTY_ATSTART) -options |= (re->flags & FF) / ((FF & (~FF+1)) / (OO & (~OO+1))); -#undef FF -#undef OO - -/* If the pattern was successfully studied with JIT support, we will run the -JIT executable instead of the rest of this function. Most options must be set -at compile time for the JIT code to be usable. */ - -#ifdef SUPPORT_JIT -use_jit = (re->executable_jit != NULL && - (options & ~PUBLIC_JIT_MATCH_OPTIONS) == 0); -#endif - -/* Initialize UTF/UCP parameters. */ - -#ifdef SUPPORT_UNICODE -utf = (re->overall_options & PCRE2_UTF) != 0; -allow_invalid = (re->overall_options & PCRE2_MATCH_INVALID_UTF) != 0; -ucp = (re->overall_options & PCRE2_UCP) != 0; -#endif /* SUPPORT_UNICODE */ - -/* Convert the partial matching flags into an integer. */ - -mb->partial = ((options & PCRE2_PARTIAL_HARD) != 0)? 2 : - ((options & PCRE2_PARTIAL_SOFT) != 0)? 1 : 0; - -/* Partial matching and PCRE2_ENDANCHORED are currently not allowed at the same -time. */ - -if (mb->partial != 0 && - ((re->overall_options | options) & PCRE2_ENDANCHORED) != 0) - return PCRE2_ERROR_BADOPTION; - -/* It is an error to set an offset limit without setting the flag at compile -time. */ - -if (mcontext != NULL && mcontext->offset_limit != PCRE2_UNSET && - (re->overall_options & PCRE2_USE_OFFSET_LIMIT) == 0) - return PCRE2_ERROR_BADOFFSETLIMIT; - -/* If the match data block was previously used with PCRE2_COPY_MATCHED_SUBJECT, -free the memory that was obtained. Set the field to NULL for no match cases. */ - -if ((match_data->flags & PCRE2_MD_COPIED_SUBJECT) != 0) - { - match_data->memctl.free((void *)match_data->subject, - match_data->memctl.memory_data); - match_data->flags &= ~PCRE2_MD_COPIED_SUBJECT; - } -match_data->subject = NULL; - -/* Zero the error offset in case the first code unit is invalid UTF. */ - -match_data->startchar = 0; - - -/* ============================= JIT matching ============================== */ - -/* Prepare for JIT matching. Check a UTF string for validity unless no check is -requested or invalid UTF can be handled. We check only the portion of the -subject that might be be inspected during matching - from the offset minus the -maximum lookbehind to the given length. This saves time when a small part of a -large subject is being matched by the use of a starting offset. Note that the -maximum lookbehind is a number of characters, not code units. */ - -#ifdef SUPPORT_JIT -if (use_jit) - { -#ifdef SUPPORT_UNICODE - if (utf && (options & PCRE2_NO_UTF_CHECK) == 0 && !allow_invalid) - { -#if PCRE2_CODE_UNIT_WIDTH != 32 - unsigned int i; -#endif - - /* For 8-bit and 16-bit UTF, check that the first code unit is a valid - character start. */ - -#if PCRE2_CODE_UNIT_WIDTH != 32 - if (start_match < end_subject && NOT_FIRSTCU(*start_match)) - { - if (start_offset > 0) return PCRE2_ERROR_BADUTFOFFSET; -#if PCRE2_CODE_UNIT_WIDTH == 8 - return PCRE2_ERROR_UTF8_ERR20; /* Isolated 0x80 byte */ -#else - return PCRE2_ERROR_UTF16_ERR3; /* Isolated low surrogate */ -#endif - } -#endif /* WIDTH != 32 */ - - /* Move back by the maximum lookbehind, just in case it happens at the very - start of matching. */ - -#if PCRE2_CODE_UNIT_WIDTH != 32 - for (i = re->max_lookbehind; i > 0 && start_match > subject; i--) - { - start_match--; - while (start_match > subject && -#if PCRE2_CODE_UNIT_WIDTH == 8 - (*start_match & 0xc0) == 0x80) -#else /* 16-bit */ - (*start_match & 0xfc00) == 0xdc00) -#endif - start_match--; - } -#else /* PCRE2_CODE_UNIT_WIDTH != 32 */ - - /* In the 32-bit library, one code unit equals one character. However, - we cannot just subtract the lookbehind and then compare pointers, because - a very large lookbehind could create an invalid pointer. */ - - if (start_offset >= re->max_lookbehind) - start_match -= re->max_lookbehind; - else - start_match = subject; -#endif /* PCRE2_CODE_UNIT_WIDTH != 32 */ - - /* Validate the relevant portion of the subject. Adjust the offset of an - invalid code point to be an absolute offset in the whole string. */ - - match_data->rc = PRIV(valid_utf)(start_match, - length - (start_match - subject), &(match_data->startchar)); - if (match_data->rc != 0) - { - match_data->startchar += start_match - subject; - return match_data->rc; - } - jit_checked_utf = TRUE; - } -#endif /* SUPPORT_UNICODE */ - - /* If JIT returns BADOPTION, which means that the selected complete or - partial matching mode was not compiled, fall through to the interpreter. */ - - rc = pcre2_jit_match(code, subject, length, start_offset, options, - match_data, mcontext); - if (rc != PCRE2_ERROR_JIT_BADOPTION) - { - if (rc >= 0 && (options & PCRE2_COPY_MATCHED_SUBJECT) != 0) - { - length = CU2BYTES(length + was_zero_terminated); - match_data->subject = match_data->memctl.malloc(length, - match_data->memctl.memory_data); - if (match_data->subject == NULL) return PCRE2_ERROR_NOMEMORY; - memcpy((void *)match_data->subject, subject, length); - match_data->flags |= PCRE2_MD_COPIED_SUBJECT; - } - return rc; - } - } -#endif /* SUPPORT_JIT */ - -/* ========================= End of JIT matching ========================== */ - - -/* Proceed with non-JIT matching. The default is to allow lookbehinds to the -start of the subject. A UTF check when there is a non-zero offset may change -this. */ - -mb->check_subject = subject; - -/* If a UTF subject string was not checked for validity in the JIT code above, -check it here, and handle support for invalid UTF strings. The check above -happens only when invalid UTF is not supported and PCRE2_NO_CHECK_UTF is unset. -If we get here in those circumstances, it means the subject string is valid, -but for some reason JIT matching was not successful. There is no need to check -the subject again. - -We check only the portion of the subject that might be be inspected during -matching - from the offset minus the maximum lookbehind to the given length. -This saves time when a small part of a large subject is being matched by the -use of a starting offset. Note that the maximum lookbehind is a number of -characters, not code units. - -Note also that support for invalid UTF forces a check, overriding the setting -of PCRE2_NO_CHECK_UTF. */ - -#ifdef SUPPORT_UNICODE -if (utf && -#ifdef SUPPORT_JIT - !jit_checked_utf && -#endif - ((options & PCRE2_NO_UTF_CHECK) == 0 || allow_invalid)) - { -#if PCRE2_CODE_UNIT_WIDTH != 32 - BOOL skipped_bad_start = FALSE; -#endif - - /* For 8-bit and 16-bit UTF, check that the first code unit is a valid - character start. If we are handling invalid UTF, just skip over such code - units. Otherwise, give an appropriate error. */ - -#if PCRE2_CODE_UNIT_WIDTH != 32 - if (allow_invalid) - { - while (start_match < end_subject && NOT_FIRSTCU(*start_match)) - { - start_match++; - skipped_bad_start = TRUE; - } - } - else if (start_match < end_subject && NOT_FIRSTCU(*start_match)) - { - if (start_offset > 0) return PCRE2_ERROR_BADUTFOFFSET; -#if PCRE2_CODE_UNIT_WIDTH == 8 - return PCRE2_ERROR_UTF8_ERR20; /* Isolated 0x80 byte */ -#else - return PCRE2_ERROR_UTF16_ERR3; /* Isolated low surrogate */ -#endif - } -#endif /* WIDTH != 32 */ - - /* The mb->check_subject field points to the start of UTF checking; - lookbehinds can go back no further than this. */ - - mb->check_subject = start_match; - - /* Move back by the maximum lookbehind, just in case it happens at the very - start of matching, but don't do this if we skipped bad 8-bit or 16-bit code - units above. */ - -#if PCRE2_CODE_UNIT_WIDTH != 32 - if (!skipped_bad_start) - { - unsigned int i; - for (i = re->max_lookbehind; i > 0 && mb->check_subject > subject; i--) - { - mb->check_subject--; - while (mb->check_subject > subject && -#if PCRE2_CODE_UNIT_WIDTH == 8 - (*mb->check_subject & 0xc0) == 0x80) -#else /* 16-bit */ - (*mb->check_subject & 0xfc00) == 0xdc00) -#endif - mb->check_subject--; - } - } -#else /* PCRE2_CODE_UNIT_WIDTH != 32 */ - - /* In the 32-bit library, one code unit equals one character. However, - we cannot just subtract the lookbehind and then compare pointers, because - a very large lookbehind could create an invalid pointer. */ - - if (start_offset >= re->max_lookbehind) - mb->check_subject -= re->max_lookbehind; - else - mb->check_subject = subject; -#endif /* PCRE2_CODE_UNIT_WIDTH != 32 */ - - /* Validate the relevant portion of the subject. There's a loop in case we - encounter bad UTF in the characters preceding start_match which we are - scanning because of a lookbehind. */ - - for (;;) - { - match_data->rc = PRIV(valid_utf)(mb->check_subject, - length - (mb->check_subject - subject), &(match_data->startchar)); - - if (match_data->rc == 0) break; /* Valid UTF string */ - - /* Invalid UTF string. Adjust the offset to be an absolute offset in the - whole string. If we are handling invalid UTF strings, set end_subject to - stop before the bad code unit, and set the options to "not end of line". - Otherwise return the error. */ - - match_data->startchar += mb->check_subject - subject; - if (!allow_invalid || match_data->rc > 0) return match_data->rc; - end_subject = subject + match_data->startchar; - - /* If the end precedes start_match, it means there is invalid UTF in the - extra code units we reversed over because of a lookbehind. Advance past the - first bad code unit, and then skip invalid character starting code units in - 8-bit and 16-bit modes, and try again with the original end point. */ - - if (end_subject < start_match) - { - mb->check_subject = end_subject + 1; -#if PCRE2_CODE_UNIT_WIDTH != 32 - while (mb->check_subject < start_match && NOT_FIRSTCU(*mb->check_subject)) - mb->check_subject++; -#endif - end_subject = true_end_subject; - } - - /* Otherwise, set the not end of line option, and do the match. */ - - else - { - fragment_options = PCRE2_NOTEOL; - break; - } - } - } -#endif /* SUPPORT_UNICODE */ - -/* A NULL match context means "use a default context", but we take the memory -control functions from the pattern. */ - -if (mcontext == NULL) - { - mcontext = (pcre2_match_context *)(&PRIV(default_match_context)); - mb->memctl = re->memctl; - } -else mb->memctl = mcontext->memctl; - -anchored = ((re->overall_options | options) & PCRE2_ANCHORED) != 0; -firstline = (re->overall_options & PCRE2_FIRSTLINE) != 0; -startline = (re->flags & PCRE2_STARTLINE) != 0; -bumpalong_limit = (mcontext->offset_limit == PCRE2_UNSET)? - true_end_subject : subject + mcontext->offset_limit; - -/* Initialize and set up the fixed fields in the callout block, with a pointer -in the match block. */ - -mb->cb = &cb; -cb.version = 2; -cb.subject = subject; -cb.subject_length = (PCRE2_SIZE)(end_subject - subject); -cb.callout_flags = 0; - -/* Fill in the remaining fields in the match block, except for moptions, which -gets set later. */ - -mb->callout = mcontext->callout; -mb->callout_data = mcontext->callout_data; - -mb->start_subject = subject; -mb->start_offset = start_offset; -mb->end_subject = end_subject; -mb->hasthen = (re->flags & PCRE2_HASTHEN) != 0; -mb->allowemptypartial = (re->max_lookbehind > 0) || - (re->flags & PCRE2_MATCH_EMPTY) != 0; -mb->poptions = re->overall_options; /* Pattern options */ -mb->ignore_skip_arg = 0; -mb->mark = mb->nomatch_mark = NULL; /* In case never set */ - -/* The name table is needed for finding all the numbers associated with a -given name, for condition testing. The code follows the name table. */ - -mb->name_table = (PCRE2_UCHAR *)((uint8_t *)re + sizeof(pcre2_real_code)); -mb->name_count = re->name_count; -mb->name_entry_size = re->name_entry_size; -mb->start_code = mb->name_table + re->name_count * re->name_entry_size; - -/* Process the \R and newline settings. */ - -mb->bsr_convention = re->bsr_convention; -mb->nltype = NLTYPE_FIXED; -switch(re->newline_convention) - { - case PCRE2_NEWLINE_CR: - mb->nllen = 1; - mb->nl[0] = CHAR_CR; - break; - - case PCRE2_NEWLINE_LF: - mb->nllen = 1; - mb->nl[0] = CHAR_NL; - break; - - case PCRE2_NEWLINE_NUL: - mb->nllen = 1; - mb->nl[0] = CHAR_NUL; - break; - - case PCRE2_NEWLINE_CRLF: - mb->nllen = 2; - mb->nl[0] = CHAR_CR; - mb->nl[1] = CHAR_NL; - break; - - case PCRE2_NEWLINE_ANY: - mb->nltype = NLTYPE_ANY; - break; - - case PCRE2_NEWLINE_ANYCRLF: - mb->nltype = NLTYPE_ANYCRLF; - break; - - default: return PCRE2_ERROR_INTERNAL; - } - -/* The backtracking frames have fixed data at the front, and a PCRE2_SIZE -vector at the end, whose size depends on the number of capturing parentheses in -the pattern. It is not used at all if there are no capturing parentheses. - - frame_size is the total size of each frame - match_data->heapframes is the pointer to the frames vector - match_data->heapframes_size is the total size of the vector - -We must pad the frame_size for alignment to ensure subsequent frames are as -aligned as heapframe. Whilst ovector is word-aligned due to being a PCRE2_SIZE -array, that does not guarantee it is suitably aligned for pointers, as some -architectures have pointers that are larger than a size_t. */ - -frame_size = (offsetof(heapframe, ovector) + - re->top_bracket * 2 * sizeof(PCRE2_SIZE) + HEAPFRAME_ALIGNMENT - 1) & - ~(HEAPFRAME_ALIGNMENT - 1); - -/* Limits set in the pattern override the match context only if they are -smaller. */ - -mb->heap_limit = ((mcontext->heap_limit < re->limit_heap)? - mcontext->heap_limit : re->limit_heap) * 1024; - -mb->match_limit = (mcontext->match_limit < re->limit_match)? - mcontext->match_limit : re->limit_match; - -mb->match_limit_depth = (mcontext->depth_limit < re->limit_depth)? - mcontext->depth_limit : re->limit_depth; - -/* If a pattern has very many capturing parentheses, the frame size may be very -large. Set the initial frame vector size to ensure that there are at least 10 -available frames, but enforce a minimum of START_FRAMES_SIZE. If this is -greater than the heap limit, get as large a vector as possible. Always round -the size to a multiple of the frame size. */ - -heapframes_size = frame_size * 10; -if (heapframes_size < START_FRAMES_SIZE) heapframes_size = START_FRAMES_SIZE; -if (heapframes_size > mb->heap_limit) - { - if (frame_size > mb->heap_limit ) return PCRE2_ERROR_HEAPLIMIT; - heapframes_size = mb->heap_limit; - } - -/* If an existing frame vector in the match_data block is large enough, we can -use it.Otherwise, free any pre-existing vector and get a new one. */ - -if (match_data->heapframes_size < heapframes_size) - { - match_data->memctl.free(match_data->heapframes, - match_data->memctl.memory_data); - match_data->heapframes = match_data->memctl.malloc(heapframes_size, - match_data->memctl.memory_data); - if (match_data->heapframes == NULL) - { - match_data->heapframes_size = 0; - return PCRE2_ERROR_NOMEMORY; - } - match_data->heapframes_size = heapframes_size; - } - -/* Write to the ovector within the first frame to mark every capture unset and -to avoid uninitialized memory read errors when it is copied to a new frame. */ - -memset((char *)(match_data->heapframes) + offsetof(heapframe, ovector), 0xff, - frame_size - offsetof(heapframe, ovector)); - -/* Pointers to the individual character tables */ - -mb->lcc = re->tables + lcc_offset; -mb->fcc = re->tables + fcc_offset; -mb->ctypes = re->tables + ctypes_offset; - -/* Set up the first code unit to match, if available. If there's no first code -unit there may be a bitmap of possible first characters. */ - -if ((re->flags & PCRE2_FIRSTSET) != 0) - { - has_first_cu = TRUE; - first_cu = first_cu2 = (PCRE2_UCHAR)(re->first_codeunit); - if ((re->flags & PCRE2_FIRSTCASELESS) != 0) - { - first_cu2 = TABLE_GET(first_cu, mb->fcc, first_cu); -#ifdef SUPPORT_UNICODE -#if PCRE2_CODE_UNIT_WIDTH == 8 - if (first_cu > 127 && ucp && !utf) first_cu2 = UCD_OTHERCASE(first_cu); -#else - if (first_cu > 127 && (utf || ucp)) first_cu2 = UCD_OTHERCASE(first_cu); -#endif -#endif /* SUPPORT_UNICODE */ - } - } -else - if (!startline && (re->flags & PCRE2_FIRSTMAPSET) != 0) - start_bits = re->start_bitmap; - -/* There may also be a "last known required character" set. */ - -if ((re->flags & PCRE2_LASTSET) != 0) - { - has_req_cu = TRUE; - req_cu = req_cu2 = (PCRE2_UCHAR)(re->last_codeunit); - if ((re->flags & PCRE2_LASTCASELESS) != 0) - { - req_cu2 = TABLE_GET(req_cu, mb->fcc, req_cu); -#ifdef SUPPORT_UNICODE -#if PCRE2_CODE_UNIT_WIDTH == 8 - if (req_cu > 127 && ucp && !utf) req_cu2 = UCD_OTHERCASE(req_cu); -#else - if (req_cu > 127 && (utf || ucp)) req_cu2 = UCD_OTHERCASE(req_cu); -#endif -#endif /* SUPPORT_UNICODE */ - } - } - - -/* ==========================================================================*/ - -/* Loop for handling unanchored repeated matching attempts; for anchored regexs -the loop runs just once. */ - -#ifdef SUPPORT_UNICODE -FRAGMENT_RESTART: -#endif - -start_partial = match_partial = NULL; -mb->hitend = FALSE; - -#if PCRE2_CODE_UNIT_WIDTH == 8 -memchr_found_first_cu = NULL; -memchr_found_first_cu2 = NULL; -#endif - -for(;;) - { - PCRE2_SPTR new_start_match; - - /* ----------------- Start of match optimizations ---------------- */ - - /* There are some optimizations that avoid running the match if a known - starting point is not found, or if a known later code unit is not present. - However, there is an option (settable at compile time) that disables these, - for testing and for ensuring that all callouts do actually occur. */ - - if ((re->overall_options & PCRE2_NO_START_OPTIMIZE) == 0) - { - /* If firstline is TRUE, the start of the match is constrained to the first - line of a multiline string. That is, the match must be before or at the - first newline following the start of matching. Temporarily adjust - end_subject so that we stop the scans for a first code unit at a newline. - If the match fails at the newline, later code breaks the loop. */ - - if (firstline) - { - PCRE2_SPTR t = start_match; -#ifdef SUPPORT_UNICODE - if (utf) - { - while (t < end_subject && !IS_NEWLINE(t)) - { - t++; - ACROSSCHAR(t < end_subject, t, t++); - } - } - else -#endif - while (t < end_subject && !IS_NEWLINE(t)) t++; - end_subject = t; - } - - /* Anchored: check the first code unit if one is recorded. This may seem - pointless but it can help in detecting a no match case without scanning for - the required code unit. */ - - if (anchored) - { - if (has_first_cu || start_bits != NULL) - { - BOOL ok = start_match < end_subject; - if (ok) - { - PCRE2_UCHAR c = UCHAR21TEST(start_match); - ok = has_first_cu && (c == first_cu || c == first_cu2); - if (!ok && start_bits != NULL) - { -#if PCRE2_CODE_UNIT_WIDTH != 8 - if (c > 255) c = 255; -#endif - ok = (start_bits[c/8] & (1u << (c&7))) != 0; - } - } - if (!ok) - { - rc = MATCH_NOMATCH; - break; - } - } - } - - /* Not anchored. Advance to a unique first code unit if there is one. */ - - else - { - if (has_first_cu) - { - if (first_cu != first_cu2) /* Caseless */ - { - /* In 16-bit and 32_bit modes we have to do our own search, so can - look for both cases at once. */ - -#if PCRE2_CODE_UNIT_WIDTH != 8 - PCRE2_UCHAR smc; - while (start_match < end_subject && - (smc = UCHAR21TEST(start_match)) != first_cu && - smc != first_cu2) - start_match++; -#else - /* In 8-bit mode, the use of memchr() gives a big speed up, even - though we have to call it twice in order to find the earliest - occurrence of the code unit in either of its cases. Caching is used - to remember the positions of previously found code units. This can - make a huge difference when the strings are very long and only one - case is actually present. */ - - PCRE2_SPTR pp1 = NULL; - PCRE2_SPTR pp2 = NULL; - PCRE2_SIZE searchlength = end_subject - start_match; - - /* If we haven't got a previously found position for first_cu, or if - the current starting position is later, we need to do a search. If - the code unit is not found, set it to the end. */ - - if (memchr_found_first_cu == NULL || - start_match > memchr_found_first_cu) - { - pp1 = memchr(start_match, first_cu, searchlength); - memchr_found_first_cu = (pp1 == NULL)? end_subject : pp1; - } - - /* If the start is before a previously found position, use the - previous position, or NULL if a previous search failed. */ - - else pp1 = (memchr_found_first_cu == end_subject)? NULL : - memchr_found_first_cu; - - /* Do the same thing for the other case. */ - - if (memchr_found_first_cu2 == NULL || - start_match > memchr_found_first_cu2) - { - pp2 = memchr(start_match, first_cu2, searchlength); - memchr_found_first_cu2 = (pp2 == NULL)? end_subject : pp2; - } - - else pp2 = (memchr_found_first_cu2 == end_subject)? NULL : - memchr_found_first_cu2; - - /* Set the start to the end of the subject if neither case was found. - Otherwise, use the earlier found point. */ - - if (pp1 == NULL) - start_match = (pp2 == NULL)? end_subject : pp2; - else - start_match = (pp2 == NULL || pp1 < pp2)? pp1 : pp2; - -#endif /* 8-bit handling */ - } - - /* The caseful case is much simpler. */ - - else - { -#if PCRE2_CODE_UNIT_WIDTH != 8 - while (start_match < end_subject && UCHAR21TEST(start_match) != - first_cu) - start_match++; -#else - start_match = memchr(start_match, first_cu, end_subject - start_match); - if (start_match == NULL) start_match = end_subject; -#endif - } - - /* If we can't find the required first code unit, having reached the - true end of the subject, break the bumpalong loop, to force a match - failure, except when doing partial matching, when we let the next cycle - run at the end of the subject. To see why, consider the pattern - /(?<=abc)def/, which partially matches "abc", even though the string - does not contain the starting character "d". If we have not reached the - true end of the subject (PCRE2_FIRSTLINE caused end_subject to be - temporarily modified) we also let the cycle run, because the matching - string is legitimately allowed to start with the first code unit of a - newline. */ - - if (mb->partial == 0 && start_match >= mb->end_subject) - { - rc = MATCH_NOMATCH; - break; - } - } - - /* If there's no first code unit, advance to just after a linebreak for a - multiline match if required. */ - - else if (startline) - { - if (start_match > mb->start_subject + start_offset) - { -#ifdef SUPPORT_UNICODE - if (utf) - { - while (start_match < end_subject && !WAS_NEWLINE(start_match)) - { - start_match++; - ACROSSCHAR(start_match < end_subject, start_match, start_match++); - } - } - else -#endif - while (start_match < end_subject && !WAS_NEWLINE(start_match)) - start_match++; - - /* If we have just passed a CR and the newline option is ANY or - ANYCRLF, and we are now at a LF, advance the match position by one - more code unit. */ - - if (start_match[-1] == CHAR_CR && - (mb->nltype == NLTYPE_ANY || mb->nltype == NLTYPE_ANYCRLF) && - start_match < end_subject && - UCHAR21TEST(start_match) == CHAR_NL) - start_match++; - } - } - - /* If there's no first code unit or a requirement for a multiline line - start, advance to a non-unique first code unit if any have been - identified. The bitmap contains only 256 bits. When code units are 16 or - 32 bits wide, all code units greater than 254 set the 255 bit. */ - - else if (start_bits != NULL) - { - while (start_match < end_subject) - { - uint32_t c = UCHAR21TEST(start_match); -#if PCRE2_CODE_UNIT_WIDTH != 8 - if (c > 255) c = 255; -#endif - if ((start_bits[c/8] & (1u << (c&7))) != 0) break; - start_match++; - } - - /* See comment above in first_cu checking about the next few lines. */ - - if (mb->partial == 0 && start_match >= mb->end_subject) - { - rc = MATCH_NOMATCH; - break; - } - } - } /* End first code unit handling */ - - /* Restore fudged end_subject */ - - end_subject = mb->end_subject; - - /* The following two optimizations must be disabled for partial matching. */ - - if (mb->partial == 0) - { - PCRE2_SPTR p; - - /* The minimum matching length is a lower bound; no string of that length - may actually match the pattern. Although the value is, strictly, in - characters, we treat it as code units to avoid spending too much time in - this optimization. */ - - if (end_subject - start_match < re->minlength) - { - rc = MATCH_NOMATCH; - break; - } - - /* If req_cu is set, we know that that code unit must appear in the - subject for the (non-partial) match to succeed. If the first code unit is - set, req_cu must be later in the subject; otherwise the test starts at - the match point. This optimization can save a huge amount of backtracking - in patterns with nested unlimited repeats that aren't going to match. - Writing separate code for caseful/caseless versions makes it go faster, - as does using an autoincrement and backing off on a match. As in the case - of the first code unit, using memchr() in the 8-bit library gives a big - speed up. Unlike the first_cu check above, we do not need to call - memchr() twice in the caseless case because we only need to check for the - presence of the character in either case, not find the first occurrence. - - The search can be skipped if the code unit was found later than the - current starting point in a previous iteration of the bumpalong loop. - - HOWEVER: when the subject string is very, very long, searching to its end - can take a long time, and give bad performance on quite ordinary - anchored patterns. This showed up when somebody was matching something - like /^\d+C/ on a 32-megabyte string... so we don't do this when the - string is sufficiently long, but it's worth searching a lot more for - unanchored patterns. */ - - p = start_match + (has_first_cu? 1:0); - if (has_req_cu && p > req_cu_ptr) - { - PCRE2_SIZE check_length = end_subject - start_match; - - if (check_length < REQ_CU_MAX || - (!anchored && check_length < REQ_CU_MAX * 1000)) - { - if (req_cu != req_cu2) /* Caseless */ - { -#if PCRE2_CODE_UNIT_WIDTH != 8 - while (p < end_subject) - { - uint32_t pp = UCHAR21INCTEST(p); - if (pp == req_cu || pp == req_cu2) { p--; break; } - } -#else /* 8-bit code units */ - PCRE2_SPTR pp = p; - p = memchr(pp, req_cu, end_subject - pp); - if (p == NULL) - { - p = memchr(pp, req_cu2, end_subject - pp); - if (p == NULL) p = end_subject; - } -#endif /* PCRE2_CODE_UNIT_WIDTH != 8 */ - } - - /* The caseful case */ - - else - { -#if PCRE2_CODE_UNIT_WIDTH != 8 - while (p < end_subject) - { - if (UCHAR21INCTEST(p) == req_cu) { p--; break; } - } - -#else /* 8-bit code units */ - p = memchr(p, req_cu, end_subject - p); - if (p == NULL) p = end_subject; -#endif - } - - /* If we can't find the required code unit, break the bumpalong loop, - forcing a match failure. */ - - if (p >= end_subject) - { - rc = MATCH_NOMATCH; - break; - } - - /* If we have found the required code unit, save the point where we - found it, so that we don't search again next time round the bumpalong - loop if the start hasn't yet passed this code unit. */ - - req_cu_ptr = p; - } - } - } - } - - /* ------------ End of start of match optimizations ------------ */ - - /* Give no match if we have passed the bumpalong limit. */ - - if (start_match > bumpalong_limit) - { - rc = MATCH_NOMATCH; - break; - } - - /* OK, we can now run the match. If "hitend" is set afterwards, remember the - first starting point for which a partial match was found. */ - - cb.start_match = (PCRE2_SIZE)(start_match - subject); - cb.callout_flags |= PCRE2_CALLOUT_STARTMATCH; - - mb->start_used_ptr = start_match; - mb->last_used_ptr = start_match; -#ifdef SUPPORT_UNICODE - mb->moptions = options | fragment_options; -#else - mb->moptions = options; -#endif - mb->match_call_count = 0; - mb->end_offset_top = 0; - mb->skip_arg_count = 0; - - rc = match(start_match, mb->start_code, re->top_bracket, frame_size, - match_data, mb); - - if (mb->hitend && start_partial == NULL) - { - start_partial = mb->start_used_ptr; - match_partial = start_match; - } - - switch(rc) - { - /* If MATCH_SKIP_ARG reaches this level it means that a MARK that matched - the SKIP's arg was not found. In this circumstance, Perl ignores the SKIP - entirely. The only way we can do that is to re-do the match at the same - point, with a flag to force SKIP with an argument to be ignored. Just - treating this case as NOMATCH does not work because it does not check other - alternatives in patterns such as A(*SKIP:A)B|AC when the subject is AC. */ - - case MATCH_SKIP_ARG: - new_start_match = start_match; - mb->ignore_skip_arg = mb->skip_arg_count; - break; - - /* SKIP passes back the next starting point explicitly, but if it is no - greater than the match we have just done, treat it as NOMATCH. */ - - case MATCH_SKIP: - if (mb->verb_skip_ptr > start_match) - { - new_start_match = mb->verb_skip_ptr; - break; - } - /* Fall through */ - - /* NOMATCH and PRUNE advance by one character. THEN at this level acts - exactly like PRUNE. Unset ignore SKIP-with-argument. */ - - case MATCH_NOMATCH: - case MATCH_PRUNE: - case MATCH_THEN: - mb->ignore_skip_arg = 0; - new_start_match = start_match + 1; -#ifdef SUPPORT_UNICODE - if (utf) - ACROSSCHAR(new_start_match < end_subject, new_start_match, - new_start_match++); -#endif - break; - - /* COMMIT disables the bumpalong, but otherwise behaves as NOMATCH. */ - - case MATCH_COMMIT: - rc = MATCH_NOMATCH; - goto ENDLOOP; - - /* Any other return is either a match, or some kind of error. */ - - default: - goto ENDLOOP; - } - - /* Control reaches here for the various types of "no match at this point" - result. Reset the code to MATCH_NOMATCH for subsequent checking. */ - - rc = MATCH_NOMATCH; - - /* If PCRE2_FIRSTLINE is set, the match must happen before or at the first - newline in the subject (though it may continue over the newline). Therefore, - if we have just failed to match, starting at a newline, do not continue. */ - - if (firstline && IS_NEWLINE(start_match)) break; - - /* Advance to new matching position */ - - start_match = new_start_match; - - /* Break the loop if the pattern is anchored or if we have passed the end of - the subject. */ - - if (anchored || start_match > end_subject) break; - - /* If we have just passed a CR and we are now at a LF, and the pattern does - not contain any explicit matches for \r or \n, and the newline option is CRLF - or ANY or ANYCRLF, advance the match position by one more code unit. In - normal matching start_match will aways be greater than the first position at - this stage, but a failed *SKIP can cause a return at the same point, which is - why the first test exists. */ - - if (start_match > subject + start_offset && - start_match[-1] == CHAR_CR && - start_match < end_subject && - *start_match == CHAR_NL && - (re->flags & PCRE2_HASCRORLF) == 0 && - (mb->nltype == NLTYPE_ANY || - mb->nltype == NLTYPE_ANYCRLF || - mb->nllen == 2)) - start_match++; - - mb->mark = NULL; /* Reset for start of next match attempt */ - } /* End of for(;;) "bumpalong" loop */ - -/* ==========================================================================*/ - -/* When we reach here, one of the following stopping conditions is true: - -(1) The match succeeded, either completely, or partially; - -(2) The pattern is anchored or the match was failed after (*COMMIT); - -(3) We are past the end of the subject or the bumpalong limit; - -(4) PCRE2_FIRSTLINE is set and we have failed to match at a newline, because - this option requests that a match occur at or before the first newline in - the subject. - -(5) Some kind of error occurred. - -*/ - -ENDLOOP: - -/* If end_subject != true_end_subject, it means we are handling invalid UTF, -and have just processed a non-terminal fragment. If this resulted in no match -or a partial match we must carry on to the next fragment (a partial match is -returned to the caller only at the very end of the subject). A loop is used to -avoid trying to match against empty fragments; if the pattern can match an -empty string it would have done so already. */ - -#ifdef SUPPORT_UNICODE -if (utf && end_subject != true_end_subject && - (rc == MATCH_NOMATCH || rc == PCRE2_ERROR_PARTIAL)) - { - for (;;) - { - /* Advance past the first bad code unit, and then skip invalid character - starting code units in 8-bit and 16-bit modes. */ - - start_match = end_subject + 1; - -#if PCRE2_CODE_UNIT_WIDTH != 32 - while (start_match < true_end_subject && NOT_FIRSTCU(*start_match)) - start_match++; -#endif - - /* If we have hit the end of the subject, there isn't another non-empty - fragment, so give up. */ - - if (start_match >= true_end_subject) - { - rc = MATCH_NOMATCH; /* In case it was partial */ - break; - } - - /* Check the rest of the subject */ - - mb->check_subject = start_match; - rc = PRIV(valid_utf)(start_match, length - (start_match - subject), - &(match_data->startchar)); - - /* The rest of the subject is valid UTF. */ - - if (rc == 0) - { - mb->end_subject = end_subject = true_end_subject; - fragment_options = PCRE2_NOTBOL; - goto FRAGMENT_RESTART; - } - - /* A subsequent UTF error has been found; if the next fragment is - non-empty, set up to process it. Otherwise, let the loop advance. */ - - else if (rc < 0) - { - mb->end_subject = end_subject = start_match + match_data->startchar; - if (end_subject > start_match) - { - fragment_options = PCRE2_NOTBOL|PCRE2_NOTEOL; - goto FRAGMENT_RESTART; - } - } - } - } -#endif /* SUPPORT_UNICODE */ - -/* Fill in fields that are always returned in the match data. */ - -match_data->code = re; -match_data->mark = mb->mark; -match_data->matchedby = PCRE2_MATCHEDBY_INTERPRETER; - -/* Handle a fully successful match. Set the return code to the number of -captured strings, or 0 if there were too many to fit into the ovector, and then -set the remaining returned values before returning. Make a copy of the subject -string if requested. */ - -if (rc == MATCH_MATCH) - { - match_data->rc = ((int)mb->end_offset_top >= 2 * match_data->oveccount)? - 0 : (int)mb->end_offset_top/2 + 1; - match_data->startchar = start_match - subject; - match_data->leftchar = mb->start_used_ptr - subject; - match_data->rightchar = ((mb->last_used_ptr > mb->end_match_ptr)? - mb->last_used_ptr : mb->end_match_ptr) - subject; - if ((options & PCRE2_COPY_MATCHED_SUBJECT) != 0) - { - length = CU2BYTES(length + was_zero_terminated); - match_data->subject = match_data->memctl.malloc(length, - match_data->memctl.memory_data); - if (match_data->subject == NULL) return PCRE2_ERROR_NOMEMORY; - memcpy((void *)match_data->subject, subject, length); - match_data->flags |= PCRE2_MD_COPIED_SUBJECT; - } - else match_data->subject = subject; - return match_data->rc; - } - -/* Control gets here if there has been a partial match, an error, or if the -overall match attempt has failed at all permitted starting positions. Any mark -data is in the nomatch_mark field. */ - -match_data->mark = mb->nomatch_mark; - -/* For anything other than nomatch or partial match, just return the code. */ - -if (rc != MATCH_NOMATCH && rc != PCRE2_ERROR_PARTIAL) match_data->rc = rc; - -/* Handle a partial match. If a "soft" partial match was requested, searching -for a complete match will have continued, and the value of rc at this point -will be MATCH_NOMATCH. For a "hard" partial match, it will already be -PCRE2_ERROR_PARTIAL. */ - -else if (match_partial != NULL) - { - match_data->subject = subject; - match_data->ovector[0] = match_partial - subject; - match_data->ovector[1] = end_subject - subject; - match_data->startchar = match_partial - subject; - match_data->leftchar = start_partial - subject; - match_data->rightchar = end_subject - subject; - match_data->rc = PCRE2_ERROR_PARTIAL; - } - -/* Else this is the classic nomatch case. */ - -else match_data->rc = PCRE2_ERROR_NOMATCH; - -return match_data->rc; -} - -/* These #undefs are here to enable unity builds with CMake. */ - -#undef NLBLOCK /* Block containing newline information */ -#undef PSSTART /* Field containing processed string start */ -#undef PSEND /* Field containing processed string end */ - -/* End of pcre2_match.c */ diff --git a/modules/regex/pcre2/src/pcre2_match_data.c b/modules/regex/pcre2/src/pcre2_match_data.c deleted file mode 100644 index fa129b8..0000000 --- a/modules/regex/pcre2/src/pcre2_match_data.c +++ /dev/null @@ -1,173 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -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-2022 University of Cambridge - ------------------------------------------------------------------------------ -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 OWNER 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. ------------------------------------------------------------------------------ -*/ - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "pcre2_internal.h" - - - -/************************************************* -* Create a match data block given ovector size * -*************************************************/ - -/* A minimum of 1 is imposed on the number of ovector pairs. A maximum is also -imposed because the oveccount field in a match data block is uintt6_t. */ - -PCRE2_EXP_DEFN pcre2_match_data * PCRE2_CALL_CONVENTION -pcre2_match_data_create(uint32_t oveccount, pcre2_general_context *gcontext) -{ -pcre2_match_data *yield; -if (oveccount < 1) oveccount = 1; -if (oveccount > UINT16_MAX) oveccount = UINT16_MAX; -yield = PRIV(memctl_malloc)( - offsetof(pcre2_match_data, ovector) + 2*oveccount*sizeof(PCRE2_SIZE), - (pcre2_memctl *)gcontext); -if (yield == NULL) return NULL; -yield->oveccount = oveccount; -yield->flags = 0; -yield->heapframes = NULL; -yield->heapframes_size = 0; -return yield; -} - - - -/************************************************* -* Create a match data block using pattern data * -*************************************************/ - -/* If no context is supplied, use the memory allocator from the code. */ - -PCRE2_EXP_DEFN pcre2_match_data * PCRE2_CALL_CONVENTION -pcre2_match_data_create_from_pattern(const pcre2_code *code, - pcre2_general_context *gcontext) -{ -if (gcontext == NULL) gcontext = (pcre2_general_context *)code; -return pcre2_match_data_create(((pcre2_real_code *)code)->top_bracket + 1, - gcontext); -} - - - -/************************************************* -* Free a match data block * -*************************************************/ - -PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION -pcre2_match_data_free(pcre2_match_data *match_data) -{ -if (match_data != NULL) - { - if (match_data->heapframes != NULL) - match_data->memctl.free(match_data->heapframes, - match_data->memctl.memory_data); - if ((match_data->flags & PCRE2_MD_COPIED_SUBJECT) != 0) - match_data->memctl.free((void *)match_data->subject, - match_data->memctl.memory_data); - match_data->memctl.free(match_data, match_data->memctl.memory_data); - } -} - - - -/************************************************* -* Get last mark in match * -*************************************************/ - -PCRE2_EXP_DEFN PCRE2_SPTR PCRE2_CALL_CONVENTION -pcre2_get_mark(pcre2_match_data *match_data) -{ -return match_data->mark; -} - - - -/************************************************* -* Get pointer to ovector * -*************************************************/ - -PCRE2_EXP_DEFN PCRE2_SIZE * PCRE2_CALL_CONVENTION -pcre2_get_ovector_pointer(pcre2_match_data *match_data) -{ -return match_data->ovector; -} - - - -/************************************************* -* Get number of ovector slots * -*************************************************/ - -PCRE2_EXP_DEFN uint32_t PCRE2_CALL_CONVENTION -pcre2_get_ovector_count(pcre2_match_data *match_data) -{ -return match_data->oveccount; -} - - - -/************************************************* -* Get starting code unit in match * -*************************************************/ - -PCRE2_EXP_DEFN PCRE2_SIZE PCRE2_CALL_CONVENTION -pcre2_get_startchar(pcre2_match_data *match_data) -{ -return match_data->startchar; -} - - - -/************************************************* -* Get size of match data block * -*************************************************/ - -PCRE2_EXP_DEFN PCRE2_SIZE PCRE2_CALL_CONVENTION -pcre2_get_match_data_size(pcre2_match_data *match_data) -{ -return offsetof(pcre2_match_data, ovector) + - 2 * (match_data->oveccount) * sizeof(PCRE2_SIZE); -} - -/* End of pcre2_match_data.c */ diff --git a/modules/regex/pcre2/src/pcre2_newline.c b/modules/regex/pcre2/src/pcre2_newline.c deleted file mode 100644 index 6e9366d..0000000 --- a/modules/regex/pcre2/src/pcre2_newline.c +++ /dev/null @@ -1,243 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -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 University of Cambridge - ------------------------------------------------------------------------------ -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 OWNER 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. ------------------------------------------------------------------------------ -*/ - - -/* This module contains internal functions for testing newlines when more than -one kind of newline is to be recognized. When a newline is found, its length is -returned. In principle, we could implement several newline "types", each -referring to a different set of newline characters. At present, PCRE2 supports -only NLTYPE_FIXED, which gets handled without these functions, NLTYPE_ANYCRLF, -and NLTYPE_ANY. The full list of Unicode newline characters is taken from -http://unicode.org/unicode/reports/tr18/. */ - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "pcre2_internal.h" - - - -/************************************************* -* Check for newline at given position * -*************************************************/ - -/* This function is called only via the IS_NEWLINE macro, which does so only -when the newline type is NLTYPE_ANY or NLTYPE_ANYCRLF. The case of a fixed -newline (NLTYPE_FIXED) is handled inline. It is guaranteed that the code unit -pointed to by ptr is less than the end of the string. - -Arguments: - ptr pointer to possible newline - type the newline type - endptr pointer to the end of the string - lenptr where to return the length - utf TRUE if in utf mode - -Returns: TRUE or FALSE -*/ - -BOOL -PRIV(is_newline)(PCRE2_SPTR ptr, uint32_t type, PCRE2_SPTR endptr, - uint32_t *lenptr, BOOL utf) -{ -uint32_t c; - -#ifdef SUPPORT_UNICODE -if (utf) { GETCHAR(c, ptr); } else c = *ptr; -#else -(void)utf; -c = *ptr; -#endif /* SUPPORT_UNICODE */ - -if (type == NLTYPE_ANYCRLF) switch(c) - { - case CHAR_LF: - *lenptr = 1; - return TRUE; - - case CHAR_CR: - *lenptr = (ptr < endptr - 1 && ptr[1] == CHAR_LF)? 2 : 1; - return TRUE; - - default: - return FALSE; - } - -/* NLTYPE_ANY */ - -else switch(c) - { -#ifdef EBCDIC - case CHAR_NEL: -#endif - case CHAR_LF: - case CHAR_VT: - case CHAR_FF: - *lenptr = 1; - return TRUE; - - case CHAR_CR: - *lenptr = (ptr < endptr - 1 && ptr[1] == CHAR_LF)? 2 : 1; - return TRUE; - -#ifndef EBCDIC -#if PCRE2_CODE_UNIT_WIDTH == 8 - case CHAR_NEL: - *lenptr = utf? 2 : 1; - return TRUE; - - case 0x2028: /* LS */ - case 0x2029: /* PS */ - *lenptr = 3; - return TRUE; - -#else /* 16-bit or 32-bit code units */ - case CHAR_NEL: - case 0x2028: /* LS */ - case 0x2029: /* PS */ - *lenptr = 1; - return TRUE; -#endif -#endif /* Not EBCDIC */ - - default: - return FALSE; - } -} - - - -/************************************************* -* Check for newline at previous position * -*************************************************/ - -/* This function is called only via the WAS_NEWLINE macro, which does so only -when the newline type is NLTYPE_ANY or NLTYPE_ANYCRLF. The case of a fixed -newline (NLTYPE_FIXED) is handled inline. It is guaranteed that the initial -value of ptr is greater than the start of the string that is being processed. - -Arguments: - ptr pointer to possible newline - type the newline type - startptr pointer to the start of the string - lenptr where to return the length - utf TRUE if in utf mode - -Returns: TRUE or FALSE -*/ - -BOOL -PRIV(was_newline)(PCRE2_SPTR ptr, uint32_t type, PCRE2_SPTR startptr, - uint32_t *lenptr, BOOL utf) -{ -uint32_t c; -ptr--; - -#ifdef SUPPORT_UNICODE -if (utf) - { - BACKCHAR(ptr); - GETCHAR(c, ptr); - } -else c = *ptr; -#else -(void)utf; -c = *ptr; -#endif /* SUPPORT_UNICODE */ - -if (type == NLTYPE_ANYCRLF) switch(c) - { - case CHAR_LF: - *lenptr = (ptr > startptr && ptr[-1] == CHAR_CR)? 2 : 1; - return TRUE; - - case CHAR_CR: - *lenptr = 1; - return TRUE; - - default: - return FALSE; - } - -/* NLTYPE_ANY */ - -else switch(c) - { - case CHAR_LF: - *lenptr = (ptr > startptr && ptr[-1] == CHAR_CR)? 2 : 1; - return TRUE; - -#ifdef EBCDIC - case CHAR_NEL: -#endif - case CHAR_VT: - case CHAR_FF: - case CHAR_CR: - *lenptr = 1; - return TRUE; - -#ifndef EBCDIC -#if PCRE2_CODE_UNIT_WIDTH == 8 - case CHAR_NEL: - *lenptr = utf? 2 : 1; - return TRUE; - - case 0x2028: /* LS */ - case 0x2029: /* PS */ - *lenptr = 3; - return TRUE; - -#else /* 16-bit or 32-bit code units */ - case CHAR_NEL: - case 0x2028: /* LS */ - case 0x2029: /* PS */ - *lenptr = 1; - return TRUE; -#endif -#endif /* Not EBCDIC */ - - default: - return FALSE; - } -} - -/* End of pcre2_newline.c */ diff --git a/modules/regex/pcre2/src/pcre2_ord2utf.c b/modules/regex/pcre2/src/pcre2_ord2utf.c deleted file mode 100644 index 1403730..0000000 --- a/modules/regex/pcre2/src/pcre2_ord2utf.c +++ /dev/null @@ -1,120 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -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 University of Cambridge - ------------------------------------------------------------------------------ -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 OWNER 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. ------------------------------------------------------------------------------ -*/ - - -/* This file contains a function that converts a Unicode character code point -into a UTF string. The behaviour is different for each code unit width. */ - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "pcre2_internal.h" - - -/* If SUPPORT_UNICODE is not defined, this function will never be called. -Supply a dummy function because some compilers do not like empty source -modules. */ - -#ifndef SUPPORT_UNICODE -unsigned int -PRIV(ord2utf)(uint32_t cvalue, PCRE2_UCHAR *buffer) -{ -(void)(cvalue); -(void)(buffer); -return 0; -} -#else /* SUPPORT_UNICODE */ - - -/************************************************* -* Convert code point to UTF * -*************************************************/ - -/* -Arguments: - cvalue the character value - buffer pointer to buffer for result - -Returns: number of code units placed in the buffer -*/ - -unsigned int -PRIV(ord2utf)(uint32_t cvalue, PCRE2_UCHAR *buffer) -{ -/* Convert to UTF-8 */ - -#if PCRE2_CODE_UNIT_WIDTH == 8 -int i, j; -for (i = 0; i < PRIV(utf8_table1_size); i++) - if ((int)cvalue <= PRIV(utf8_table1)[i]) break; -buffer += i; -for (j = i; j > 0; j--) - { - *buffer-- = 0x80 | (cvalue & 0x3f); - cvalue >>= 6; - } -*buffer = PRIV(utf8_table2)[i] | cvalue; -return i + 1; - -/* Convert to UTF-16 */ - -#elif PCRE2_CODE_UNIT_WIDTH == 16 -if (cvalue <= 0xffff) - { - *buffer = (PCRE2_UCHAR)cvalue; - return 1; - } -cvalue -= 0x10000; -*buffer++ = 0xd800 | (cvalue >> 10); -*buffer = 0xdc00 | (cvalue & 0x3ff); -return 2; - -/* Convert to UTF-32 */ - -#else -*buffer = (PCRE2_UCHAR)cvalue; -return 1; -#endif -} -#endif /* SUPPORT_UNICODE */ - -/* End of pcre_ord2utf.c */ diff --git a/modules/regex/pcre2/src/pcre2_pattern_info.c b/modules/regex/pcre2/src/pcre2_pattern_info.c deleted file mode 100644 index a29f5ef..0000000 --- a/modules/regex/pcre2/src/pcre2_pattern_info.c +++ /dev/null @@ -1,432 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -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-2018 University of Cambridge - ------------------------------------------------------------------------------ -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 OWNER 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. ------------------------------------------------------------------------------ -*/ - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "pcre2_internal.h" - - -/************************************************* -* Return info about compiled pattern * -*************************************************/ - -/* -Arguments: - code points to compiled code - what what information is required - where where to put the information; if NULL, return length - -Returns: 0 when data returned - > 0 when length requested - < 0 on error or unset value -*/ - -PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION -pcre2_pattern_info(const pcre2_code *code, uint32_t what, void *where) -{ -const pcre2_real_code *re = (pcre2_real_code *)code; - -if (where == NULL) /* Requests field length */ - { - switch(what) - { - case PCRE2_INFO_ALLOPTIONS: - case PCRE2_INFO_ARGOPTIONS: - case PCRE2_INFO_BACKREFMAX: - case PCRE2_INFO_BSR: - case PCRE2_INFO_CAPTURECOUNT: - case PCRE2_INFO_DEPTHLIMIT: - case PCRE2_INFO_EXTRAOPTIONS: - case PCRE2_INFO_FIRSTCODETYPE: - case PCRE2_INFO_FIRSTCODEUNIT: - case PCRE2_INFO_HASBACKSLASHC: - case PCRE2_INFO_HASCRORLF: - case PCRE2_INFO_HEAPLIMIT: - case PCRE2_INFO_JCHANGED: - case PCRE2_INFO_LASTCODETYPE: - case PCRE2_INFO_LASTCODEUNIT: - case PCRE2_INFO_MATCHEMPTY: - case PCRE2_INFO_MATCHLIMIT: - case PCRE2_INFO_MAXLOOKBEHIND: - case PCRE2_INFO_MINLENGTH: - case PCRE2_INFO_NAMEENTRYSIZE: - case PCRE2_INFO_NAMECOUNT: - case PCRE2_INFO_NEWLINE: - return sizeof(uint32_t); - - case PCRE2_INFO_FIRSTBITMAP: - return sizeof(const uint8_t *); - - case PCRE2_INFO_JITSIZE: - case PCRE2_INFO_SIZE: - case PCRE2_INFO_FRAMESIZE: - return sizeof(size_t); - - case PCRE2_INFO_NAMETABLE: - return sizeof(PCRE2_SPTR); - } - } - -if (re == NULL) return PCRE2_ERROR_NULL; - -/* Check that the first field in the block is the magic number. If it is not, -return with PCRE2_ERROR_BADMAGIC. */ - -if (re->magic_number != MAGIC_NUMBER) return PCRE2_ERROR_BADMAGIC; - -/* Check that this pattern was compiled in the correct bit mode */ - -if ((re->flags & (PCRE2_CODE_UNIT_WIDTH/8)) == 0) return PCRE2_ERROR_BADMODE; - -switch(what) - { - case PCRE2_INFO_ALLOPTIONS: - *((uint32_t *)where) = re->overall_options; - break; - - case PCRE2_INFO_ARGOPTIONS: - *((uint32_t *)where) = re->compile_options; - break; - - case PCRE2_INFO_BACKREFMAX: - *((uint32_t *)where) = re->top_backref; - break; - - case PCRE2_INFO_BSR: - *((uint32_t *)where) = re->bsr_convention; - break; - - case PCRE2_INFO_CAPTURECOUNT: - *((uint32_t *)where) = re->top_bracket; - break; - - case PCRE2_INFO_DEPTHLIMIT: - *((uint32_t *)where) = re->limit_depth; - if (re->limit_depth == UINT32_MAX) return PCRE2_ERROR_UNSET; - break; - - case PCRE2_INFO_EXTRAOPTIONS: - *((uint32_t *)where) = re->extra_options; - break; - - case PCRE2_INFO_FIRSTCODETYPE: - *((uint32_t *)where) = ((re->flags & PCRE2_FIRSTSET) != 0)? 1 : - ((re->flags & PCRE2_STARTLINE) != 0)? 2 : 0; - break; - - case PCRE2_INFO_FIRSTCODEUNIT: - *((uint32_t *)where) = ((re->flags & PCRE2_FIRSTSET) != 0)? - re->first_codeunit : 0; - break; - - case PCRE2_INFO_FIRSTBITMAP: - *((const uint8_t **)where) = ((re->flags & PCRE2_FIRSTMAPSET) != 0)? - &(re->start_bitmap[0]) : NULL; - break; - - case PCRE2_INFO_FRAMESIZE: - *((size_t *)where) = offsetof(heapframe, ovector) + - re->top_bracket * 2 * sizeof(PCRE2_SIZE); - break; - - case PCRE2_INFO_HASBACKSLASHC: - *((uint32_t *)where) = (re->flags & PCRE2_HASBKC) != 0; - break; - - case PCRE2_INFO_HASCRORLF: - *((uint32_t *)where) = (re->flags & PCRE2_HASCRORLF) != 0; - break; - - case PCRE2_INFO_HEAPLIMIT: - *((uint32_t *)where) = re->limit_heap; - if (re->limit_heap == UINT32_MAX) return PCRE2_ERROR_UNSET; - break; - - case PCRE2_INFO_JCHANGED: - *((uint32_t *)where) = (re->flags & PCRE2_JCHANGED) != 0; - break; - - case PCRE2_INFO_JITSIZE: -#ifdef SUPPORT_JIT - *((size_t *)where) = (re->executable_jit != NULL)? - PRIV(jit_get_size)(re->executable_jit) : 0; -#else - *((size_t *)where) = 0; -#endif - break; - - case PCRE2_INFO_LASTCODETYPE: - *((uint32_t *)where) = ((re->flags & PCRE2_LASTSET) != 0)? 1 : 0; - break; - - case PCRE2_INFO_LASTCODEUNIT: - *((uint32_t *)where) = ((re->flags & PCRE2_LASTSET) != 0)? - re->last_codeunit : 0; - break; - - case PCRE2_INFO_MATCHEMPTY: - *((uint32_t *)where) = (re->flags & PCRE2_MATCH_EMPTY) != 0; - break; - - case PCRE2_INFO_MATCHLIMIT: - *((uint32_t *)where) = re->limit_match; - if (re->limit_match == UINT32_MAX) return PCRE2_ERROR_UNSET; - break; - - case PCRE2_INFO_MAXLOOKBEHIND: - *((uint32_t *)where) = re->max_lookbehind; - break; - - case PCRE2_INFO_MINLENGTH: - *((uint32_t *)where) = re->minlength; - break; - - case PCRE2_INFO_NAMEENTRYSIZE: - *((uint32_t *)where) = re->name_entry_size; - break; - - case PCRE2_INFO_NAMECOUNT: - *((uint32_t *)where) = re->name_count; - break; - - case PCRE2_INFO_NAMETABLE: - *((PCRE2_SPTR *)where) = (PCRE2_SPTR)((char *)re + sizeof(pcre2_real_code)); - break; - - case PCRE2_INFO_NEWLINE: - *((uint32_t *)where) = re->newline_convention; - break; - - case PCRE2_INFO_SIZE: - *((size_t *)where) = re->blocksize; - break; - - default: return PCRE2_ERROR_BADOPTION; - } - -return 0; -} - - - -/************************************************* -* Callout enumerator * -*************************************************/ - -/* -Arguments: - code points to compiled code - callback function called for each callout block - callout_data user data passed to the callback - -Returns: 0 when successfully completed - < 0 on local error - != 0 for callback error -*/ - -PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION -pcre2_callout_enumerate(const pcre2_code *code, - int (*callback)(pcre2_callout_enumerate_block *, void *), void *callout_data) -{ -pcre2_real_code *re = (pcre2_real_code *)code; -pcre2_callout_enumerate_block cb; -PCRE2_SPTR cc; -#ifdef SUPPORT_UNICODE -BOOL utf; -#endif - -if (re == NULL) return PCRE2_ERROR_NULL; - -#ifdef SUPPORT_UNICODE -utf = (re->overall_options & PCRE2_UTF) != 0; -#endif - -/* Check that the first field in the block is the magic number. If it is not, -return with PCRE2_ERROR_BADMAGIC. */ - -if (re->magic_number != MAGIC_NUMBER) return PCRE2_ERROR_BADMAGIC; - -/* Check that this pattern was compiled in the correct bit mode */ - -if ((re->flags & (PCRE2_CODE_UNIT_WIDTH/8)) == 0) return PCRE2_ERROR_BADMODE; - -cb.version = 0; -cc = (PCRE2_SPTR)((uint8_t *)re + sizeof(pcre2_real_code)) - + re->name_count * re->name_entry_size; - -while (TRUE) - { - int rc; - switch (*cc) - { - case OP_END: - return 0; - - case OP_CHAR: - case OP_CHARI: - case OP_NOT: - case OP_NOTI: - case OP_STAR: - case OP_MINSTAR: - case OP_PLUS: - case OP_MINPLUS: - case OP_QUERY: - case OP_MINQUERY: - case OP_UPTO: - case OP_MINUPTO: - case OP_EXACT: - case OP_POSSTAR: - case OP_POSPLUS: - case OP_POSQUERY: - case OP_POSUPTO: - case OP_STARI: - case OP_MINSTARI: - case OP_PLUSI: - case OP_MINPLUSI: - case OP_QUERYI: - case OP_MINQUERYI: - case OP_UPTOI: - case OP_MINUPTOI: - case OP_EXACTI: - case OP_POSSTARI: - case OP_POSPLUSI: - case OP_POSQUERYI: - case OP_POSUPTOI: - case OP_NOTSTAR: - case OP_NOTMINSTAR: - case OP_NOTPLUS: - case OP_NOTMINPLUS: - case OP_NOTQUERY: - case OP_NOTMINQUERY: - case OP_NOTUPTO: - case OP_NOTMINUPTO: - case OP_NOTEXACT: - case OP_NOTPOSSTAR: - case OP_NOTPOSPLUS: - case OP_NOTPOSQUERY: - case OP_NOTPOSUPTO: - case OP_NOTSTARI: - case OP_NOTMINSTARI: - case OP_NOTPLUSI: - case OP_NOTMINPLUSI: - case OP_NOTQUERYI: - case OP_NOTMINQUERYI: - case OP_NOTUPTOI: - case OP_NOTMINUPTOI: - case OP_NOTEXACTI: - case OP_NOTPOSSTARI: - case OP_NOTPOSPLUSI: - case OP_NOTPOSQUERYI: - case OP_NOTPOSUPTOI: - cc += PRIV(OP_lengths)[*cc]; -#ifdef SUPPORT_UNICODE - if (utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); -#endif - break; - - case OP_TYPESTAR: - case OP_TYPEMINSTAR: - case OP_TYPEPLUS: - case OP_TYPEMINPLUS: - case OP_TYPEQUERY: - case OP_TYPEMINQUERY: - case OP_TYPEUPTO: - case OP_TYPEMINUPTO: - case OP_TYPEEXACT: - case OP_TYPEPOSSTAR: - case OP_TYPEPOSPLUS: - case OP_TYPEPOSQUERY: - case OP_TYPEPOSUPTO: - cc += PRIV(OP_lengths)[*cc]; -#ifdef SUPPORT_UNICODE - if (cc[-1] == OP_PROP || cc[-1] == OP_NOTPROP) cc += 2; -#endif - break; - -#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8 - case OP_XCLASS: - cc += GET(cc, 1); - break; -#endif - - case OP_MARK: - case OP_COMMIT_ARG: - case OP_PRUNE_ARG: - case OP_SKIP_ARG: - case OP_THEN_ARG: - cc += PRIV(OP_lengths)[*cc] + cc[1]; - break; - - case OP_CALLOUT: - cb.pattern_position = GET(cc, 1); - cb.next_item_length = GET(cc, 1 + LINK_SIZE); - cb.callout_number = cc[1 + 2*LINK_SIZE]; - cb.callout_string_offset = 0; - cb.callout_string_length = 0; - cb.callout_string = NULL; - rc = callback(&cb, callout_data); - if (rc != 0) return rc; - cc += PRIV(OP_lengths)[*cc]; - break; - - case OP_CALLOUT_STR: - cb.pattern_position = GET(cc, 1); - cb.next_item_length = GET(cc, 1 + LINK_SIZE); - cb.callout_number = 0; - cb.callout_string_offset = GET(cc, 1 + 3*LINK_SIZE); - cb.callout_string_length = - GET(cc, 1 + 2*LINK_SIZE) - (1 + 4*LINK_SIZE) - 2; - cb.callout_string = cc + (1 + 4*LINK_SIZE) + 1; - rc = callback(&cb, callout_data); - if (rc != 0) return rc; - cc += GET(cc, 1 + 2*LINK_SIZE); - break; - - default: - cc += PRIV(OP_lengths)[*cc]; - break; - } - } -} - -/* End of pcre2_pattern_info.c */ diff --git a/modules/regex/pcre2/src/pcre2_script_run.c b/modules/regex/pcre2/src/pcre2_script_run.c deleted file mode 100644 index 4926fa6..0000000 --- a/modules/regex/pcre2/src/pcre2_script_run.c +++ /dev/null @@ -1,344 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -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 - ------------------------------------------------------------------------------ -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 OWNER 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. ------------------------------------------------------------------------------ -*/ - -/* This module contains the function for checking a script run. */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "pcre2_internal.h" - - -/************************************************* -* Check script run * -*************************************************/ - -/* A script run is conceptually a sequence of characters all in the same -Unicode script. However, it isn't quite that simple. There are special rules -for scripts that are commonly used together, and also special rules for digits. -This function implements the appropriate checks, which is possible only when -PCRE2 is compiled with Unicode support. The function returns TRUE if there is -no Unicode support; however, it should never be called in that circumstance -because an error is given by pcre2_compile() if a script run is called for in a -version of PCRE2 compiled without Unicode support. - -Arguments: - pgr point to the first character - endptr point after the last character - utf TRUE if in UTF mode - -Returns: TRUE if this is a valid script run -*/ - -/* These are states in the checking process. */ - -enum { SCRIPT_UNSET, /* Requirement as yet unknown */ - SCRIPT_MAP, /* Bitmap contains acceptable scripts */ - SCRIPT_HANPENDING, /* Have had only Han characters */ - SCRIPT_HANHIRAKATA, /* Expect Han or Hirikata */ - SCRIPT_HANBOPOMOFO, /* Expect Han or Bopomofo */ - SCRIPT_HANHANGUL /* Expect Han or Hangul */ - }; - -#define UCD_MAPSIZE (ucp_Unknown/32 + 1) -#define FULL_MAPSIZE (ucp_Script_Count/32 + 1) - -BOOL -PRIV(script_run)(PCRE2_SPTR ptr, PCRE2_SPTR endptr, BOOL utf) -{ -#ifdef SUPPORT_UNICODE -uint32_t require_state = SCRIPT_UNSET; -uint32_t require_map[FULL_MAPSIZE]; -uint32_t map[FULL_MAPSIZE]; -uint32_t require_digitset = 0; -uint32_t c; - -#if PCRE2_CODE_UNIT_WIDTH == 32 -(void)utf; /* Avoid compiler warning */ -#endif - -/* Any string containing fewer than 2 characters is a valid script run. */ - -if (ptr >= endptr) return TRUE; -GETCHARINCTEST(c, ptr); -if (ptr >= endptr) return TRUE; - -/* Initialize the require map. This is a full-size bitmap that has a bit for -every script, as opposed to the maps in ucd_script_sets, which only have bits -for scripts less than ucp_Unknown - those that appear in script extension -lists. */ - -for (int i = 0; i < FULL_MAPSIZE; i++) require_map[i] = 0; - -/* Scan strings of two or more characters, checking the Unicode characteristics -of each code point. There is special code for scripts that can be combined with -characters from the Han Chinese script. This may be used in conjunction with -four other scripts in these combinations: - -. Han with Hiragana and Katakana is allowed (for Japanese). -. Han with Bopomofo is allowed (for Taiwanese Mandarin). -. Han with Hangul is allowed (for Korean). - -If the first significant character's script is one of the four, the required -script type is immediately known. However, if the first significant -character's script is Han, we have to keep checking for a non-Han character. -Hence the SCRIPT_HANPENDING state. */ - -for (;;) - { - const ucd_record *ucd = GET_UCD(c); - uint32_t script = ucd->script; - - /* If the script is Unknown, the string is not a valid script run. Such - characters can only form script runs of length one (see test above). */ - - if (script == ucp_Unknown) return FALSE; - - /* A character without any script extensions whose script is Inherited or - Common is always accepted with any script. If there are extensions, the - following processing happens for all scripts. */ - - if (UCD_SCRIPTX_PROP(ucd) != 0 || (script != ucp_Inherited && script != ucp_Common)) - { - BOOL OK; - - /* Set up a full-sized map for this character that can include bits for all - scripts. Copy the scriptx map for this character (which covers those - scripts that appear in script extension lists), set the remaining values to - zero, and then, except for Common or Inherited, add this script's bit to - the map. */ - - memcpy(map, PRIV(ucd_script_sets) + UCD_SCRIPTX_PROP(ucd), UCD_MAPSIZE * sizeof(uint32_t)); - memset(map + UCD_MAPSIZE, 0, (FULL_MAPSIZE - UCD_MAPSIZE) * sizeof(uint32_t)); - if (script != ucp_Common && script != ucp_Inherited) MAPSET(map, script); - - /* Handle the different checking states */ - - switch(require_state) - { - /* First significant character - it might follow Common or Inherited - characters that do not have any script extensions. */ - - case SCRIPT_UNSET: - switch(script) - { - case ucp_Han: - require_state = SCRIPT_HANPENDING; - break; - - case ucp_Hiragana: - case ucp_Katakana: - require_state = SCRIPT_HANHIRAKATA; - break; - - case ucp_Bopomofo: - require_state = SCRIPT_HANBOPOMOFO; - break; - - case ucp_Hangul: - require_state = SCRIPT_HANHANGUL; - break; - - default: - memcpy(require_map, map, FULL_MAPSIZE * sizeof(uint32_t)); - require_state = SCRIPT_MAP; - break; - } - break; - - /* The first significant character was Han. An inspection of the Unicode - 11.0.0 files shows that there are the following types of Script Extension - list that involve the Han, Bopomofo, Hiragana, Katakana, and Hangul - scripts: - - . Bopomofo + Han - . Han + Hiragana + Katakana - . Hiragana + Katakana - . Bopopmofo + Hangul + Han + Hiragana + Katakana - - The following code tries to make sense of this. */ - -#define FOUND_BOPOMOFO 1 -#define FOUND_HIRAGANA 2 -#define FOUND_KATAKANA 4 -#define FOUND_HANGUL 8 - - case SCRIPT_HANPENDING: - if (script != ucp_Han) /* Another Han does nothing */ - { - uint32_t chspecial = 0; - - if (MAPBIT(map, ucp_Bopomofo) != 0) chspecial |= FOUND_BOPOMOFO; - if (MAPBIT(map, ucp_Hiragana) != 0) chspecial |= FOUND_HIRAGANA; - if (MAPBIT(map, ucp_Katakana) != 0) chspecial |= FOUND_KATAKANA; - if (MAPBIT(map, ucp_Hangul) != 0) chspecial |= FOUND_HANGUL; - - if (chspecial == 0) return FALSE; /* Not allowed with Han */ - - if (chspecial == FOUND_BOPOMOFO) - require_state = SCRIPT_HANBOPOMOFO; - else if (chspecial == (FOUND_HIRAGANA|FOUND_KATAKANA)) - require_state = SCRIPT_HANHIRAKATA; - - /* Otherwise this character must be allowed with all of them, so remain - in the pending state. */ - } - break; - - /* Previously encountered one of the "with Han" scripts. Check that - this character is appropriate. */ - - case SCRIPT_HANHIRAKATA: - if (MAPBIT(map, ucp_Han) + MAPBIT(map, ucp_Hiragana) + - MAPBIT(map, ucp_Katakana) == 0) return FALSE; - break; - - case SCRIPT_HANBOPOMOFO: - if (MAPBIT(map, ucp_Han) + MAPBIT(map, ucp_Bopomofo) == 0) return FALSE; - break; - - case SCRIPT_HANHANGUL: - if (MAPBIT(map, ucp_Han) + MAPBIT(map, ucp_Hangul) == 0) return FALSE; - break; - - /* Previously encountered one or more characters that are allowed with a - list of scripts. */ - - case SCRIPT_MAP: - OK = FALSE; - - for (int i = 0; i < FULL_MAPSIZE; i++) - { - if ((require_map[i] & map[i]) != 0) - { - OK = TRUE; - break; - } - } - - if (!OK) return FALSE; - - /* The rest of the string must be in this script, but we have to - allow for the Han complications. */ - - switch(script) - { - case ucp_Han: - require_state = SCRIPT_HANPENDING; - break; - - case ucp_Hiragana: - case ucp_Katakana: - require_state = SCRIPT_HANHIRAKATA; - break; - - case ucp_Bopomofo: - require_state = SCRIPT_HANBOPOMOFO; - break; - - case ucp_Hangul: - require_state = SCRIPT_HANHANGUL; - break; - - /* Compute the intersection of the required list of scripts and the - allowed scripts for this character. */ - - default: - for (int i = 0; i < FULL_MAPSIZE; i++) require_map[i] &= map[i]; - break; - } - - break; - } - } /* End checking character's script and extensions. */ - - /* The character is in an acceptable script. We must now ensure that all - decimal digits in the string come from the same set. Some scripts (e.g. - Common, Arabic) have more than one set of decimal digits. This code does - not allow mixing sets, even within the same script. The vector called - PRIV(ucd_digit_sets)[] contains, in its first element, the number of - following elements, and then, in ascending order, the code points of the - '9' characters in every set of 10 digits. Each set is identified by the - offset in the vector of its '9' character. An initial check of the first - value picks up ASCII digits quickly. Otherwise, a binary chop is used. */ - - if (ucd->chartype == ucp_Nd) - { - uint32_t digitset; - - if (c <= PRIV(ucd_digit_sets)[1]) digitset = 1; else - { - int mid; - int bot = 1; - int top = PRIV(ucd_digit_sets)[0]; - for (;;) - { - if (top <= bot + 1) /* <= rather than == is paranoia */ - { - digitset = top; - break; - } - mid = (top + bot) / 2; - if (c <= PRIV(ucd_digit_sets)[mid]) top = mid; else bot = mid; - } - } - - /* A required value of 0 means "unset". */ - - if (require_digitset == 0) require_digitset = digitset; - else if (digitset != require_digitset) return FALSE; - } /* End digit handling */ - - /* If we haven't yet got to the end, pick up the next character. */ - - if (ptr >= endptr) return TRUE; - GETCHARINCTEST(c, ptr); - } /* End checking loop */ - -#else /* NOT SUPPORT_UNICODE */ -(void)ptr; -(void)endptr; -(void)utf; -return TRUE; -#endif /* SUPPORT_UNICODE */ -} - -/* End of pcre2_script_run.c */ diff --git a/modules/regex/pcre2/src/pcre2_serialize.c b/modules/regex/pcre2/src/pcre2_serialize.c deleted file mode 100644 index ba17a26..0000000 --- a/modules/regex/pcre2/src/pcre2_serialize.c +++ /dev/null @@ -1,286 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -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-2020 University of Cambridge - ------------------------------------------------------------------------------ -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 OWNER 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. ------------------------------------------------------------------------------ -*/ - -/* This module contains functions for serializing and deserializing -a sequence of compiled codes. */ - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - - -#include "pcre2_internal.h" - -/* Magic number to provide a small check against being handed junk. */ - -#define SERIALIZED_DATA_MAGIC 0x50523253u - -/* Deserialization is limited to the current PCRE version and -character width. */ - -#define SERIALIZED_DATA_VERSION \ - ((PCRE2_MAJOR) | ((PCRE2_MINOR) << 16)) - -#define SERIALIZED_DATA_CONFIG \ - (sizeof(PCRE2_UCHAR) | ((sizeof(void*)) << 8) | ((sizeof(PCRE2_SIZE)) << 16)) - - - -/************************************************* -* Serialize compiled patterns * -*************************************************/ - -PCRE2_EXP_DEFN int32_t PCRE2_CALL_CONVENTION -pcre2_serialize_encode(const pcre2_code **codes, int32_t number_of_codes, - uint8_t **serialized_bytes, PCRE2_SIZE *serialized_size, - pcre2_general_context *gcontext) -{ -uint8_t *bytes; -uint8_t *dst_bytes; -int32_t i; -PCRE2_SIZE total_size; -const pcre2_real_code *re; -const uint8_t *tables; -pcre2_serialized_data *data; - -const pcre2_memctl *memctl = (gcontext != NULL) ? - &gcontext->memctl : &PRIV(default_compile_context).memctl; - -if (codes == NULL || serialized_bytes == NULL || serialized_size == NULL) - return PCRE2_ERROR_NULL; - -if (number_of_codes <= 0) return PCRE2_ERROR_BADDATA; - -/* Compute total size. */ -total_size = sizeof(pcre2_serialized_data) + TABLES_LENGTH; -tables = NULL; - -for (i = 0; i < number_of_codes; i++) - { - if (codes[i] == NULL) return PCRE2_ERROR_NULL; - re = (const pcre2_real_code *)(codes[i]); - if (re->magic_number != MAGIC_NUMBER) return PCRE2_ERROR_BADMAGIC; - if (tables == NULL) - tables = re->tables; - else if (tables != re->tables) - return PCRE2_ERROR_MIXEDTABLES; - total_size += re->blocksize; - } - -/* Initialize the byte stream. */ -bytes = memctl->malloc(total_size + sizeof(pcre2_memctl), memctl->memory_data); -if (bytes == NULL) return PCRE2_ERROR_NOMEMORY; - -/* The controller is stored as a hidden parameter. */ -memcpy(bytes, memctl, sizeof(pcre2_memctl)); -bytes += sizeof(pcre2_memctl); - -data = (pcre2_serialized_data *)bytes; -data->magic = SERIALIZED_DATA_MAGIC; -data->version = SERIALIZED_DATA_VERSION; -data->config = SERIALIZED_DATA_CONFIG; -data->number_of_codes = number_of_codes; - -/* Copy all compiled code data. */ -dst_bytes = bytes + sizeof(pcre2_serialized_data); -memcpy(dst_bytes, tables, TABLES_LENGTH); -dst_bytes += TABLES_LENGTH; - -for (i = 0; i < number_of_codes; i++) - { - re = (const pcre2_real_code *)(codes[i]); - (void)memcpy(dst_bytes, (char *)re, re->blocksize); - - /* Certain fields in the compiled code block are re-set during - deserialization. In order to ensure that the serialized data stream is always - the same for the same pattern, set them to zero here. We can't assume the - copy of the pattern is correctly aligned for accessing the fields as part of - a structure. Note the use of sizeof(void *) in the second of these, to - specify the size of a pointer. If sizeof(uint8_t *) is used (tables is a - pointer to uint8_t), gcc gives a warning because the first argument is also a - pointer to uint8_t. Casting the first argument to (void *) can stop this, but - it didn't stop Coverity giving the same complaint. */ - - (void)memset(dst_bytes + offsetof(pcre2_real_code, memctl), 0, - sizeof(pcre2_memctl)); - (void)memset(dst_bytes + offsetof(pcre2_real_code, tables), 0, - sizeof(void *)); - (void)memset(dst_bytes + offsetof(pcre2_real_code, executable_jit), 0, - sizeof(void *)); - - dst_bytes += re->blocksize; - } - -*serialized_bytes = bytes; -*serialized_size = total_size; -return number_of_codes; -} - - -/************************************************* -* Deserialize compiled patterns * -*************************************************/ - -PCRE2_EXP_DEFN int32_t PCRE2_CALL_CONVENTION -pcre2_serialize_decode(pcre2_code **codes, int32_t number_of_codes, - const uint8_t *bytes, pcre2_general_context *gcontext) -{ -const pcre2_serialized_data *data = (const pcre2_serialized_data *)bytes; -const pcre2_memctl *memctl = (gcontext != NULL) ? - &gcontext->memctl : &PRIV(default_compile_context).memctl; - -const uint8_t *src_bytes; -pcre2_real_code *dst_re; -uint8_t *tables; -int32_t i, j; - -/* Sanity checks. */ - -if (data == NULL || codes == NULL) return PCRE2_ERROR_NULL; -if (number_of_codes <= 0) return PCRE2_ERROR_BADDATA; -if (data->number_of_codes <= 0) return PCRE2_ERROR_BADSERIALIZEDDATA; -if (data->magic != SERIALIZED_DATA_MAGIC) return PCRE2_ERROR_BADMAGIC; -if (data->version != SERIALIZED_DATA_VERSION) return PCRE2_ERROR_BADMODE; -if (data->config != SERIALIZED_DATA_CONFIG) return PCRE2_ERROR_BADMODE; - -if (number_of_codes > data->number_of_codes) - number_of_codes = data->number_of_codes; - -src_bytes = bytes + sizeof(pcre2_serialized_data); - -/* Decode tables. The reference count for the tables is stored immediately -following them. */ - -tables = memctl->malloc(TABLES_LENGTH + sizeof(PCRE2_SIZE), memctl->memory_data); -if (tables == NULL) return PCRE2_ERROR_NOMEMORY; - -memcpy(tables, src_bytes, TABLES_LENGTH); -*(PCRE2_SIZE *)(tables + TABLES_LENGTH) = number_of_codes; -src_bytes += TABLES_LENGTH; - -/* Decode the byte stream. We must not try to read the size from the compiled -code block in the stream, because it might be unaligned, which causes errors on -hardware such as Sparc-64 that doesn't like unaligned memory accesses. The type -of the blocksize field is given its own name to ensure that it is the same here -as in the block. */ - -for (i = 0; i < number_of_codes; i++) - { - CODE_BLOCKSIZE_TYPE blocksize; - memcpy(&blocksize, src_bytes + offsetof(pcre2_real_code, blocksize), - sizeof(CODE_BLOCKSIZE_TYPE)); - if (blocksize <= sizeof(pcre2_real_code)) - return PCRE2_ERROR_BADSERIALIZEDDATA; - - /* The allocator provided by gcontext replaces the original one. */ - - dst_re = (pcre2_real_code *)PRIV(memctl_malloc)(blocksize, - (pcre2_memctl *)gcontext); - if (dst_re == NULL) - { - memctl->free(tables, memctl->memory_data); - for (j = 0; j < i; j++) - { - memctl->free(codes[j], memctl->memory_data); - codes[j] = NULL; - } - return PCRE2_ERROR_NOMEMORY; - } - - /* The new allocator must be preserved. */ - - memcpy(((uint8_t *)dst_re) + sizeof(pcre2_memctl), - src_bytes + sizeof(pcre2_memctl), blocksize - sizeof(pcre2_memctl)); - if (dst_re->magic_number != MAGIC_NUMBER || - dst_re->name_entry_size > MAX_NAME_SIZE + IMM2_SIZE + 1 || - dst_re->name_count > MAX_NAME_COUNT) - { - memctl->free(dst_re, memctl->memory_data); - return PCRE2_ERROR_BADSERIALIZEDDATA; - } - - /* At the moment only one table is supported. */ - - dst_re->tables = tables; - dst_re->executable_jit = NULL; - dst_re->flags |= PCRE2_DEREF_TABLES; - - codes[i] = dst_re; - src_bytes += blocksize; - } - -return number_of_codes; -} - - -/************************************************* -* Get the number of serialized patterns * -*************************************************/ - -PCRE2_EXP_DEFN int32_t PCRE2_CALL_CONVENTION -pcre2_serialize_get_number_of_codes(const uint8_t *bytes) -{ -const pcre2_serialized_data *data = (const pcre2_serialized_data *)bytes; - -if (data == NULL) return PCRE2_ERROR_NULL; -if (data->magic != SERIALIZED_DATA_MAGIC) return PCRE2_ERROR_BADMAGIC; -if (data->version != SERIALIZED_DATA_VERSION) return PCRE2_ERROR_BADMODE; -if (data->config != SERIALIZED_DATA_CONFIG) return PCRE2_ERROR_BADMODE; - -return data->number_of_codes; -} - - -/************************************************* -* Free the allocated stream * -*************************************************/ - -PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION -pcre2_serialize_free(uint8_t *bytes) -{ -if (bytes != NULL) - { - pcre2_memctl *memctl = (pcre2_memctl *)(bytes - sizeof(pcre2_memctl)); - memctl->free(memctl, memctl->memory_data); - } -} - -/* End of pcre2_serialize.c */ diff --git a/modules/regex/pcre2/src/pcre2_string_utils.c b/modules/regex/pcre2/src/pcre2_string_utils.c deleted file mode 100644 index ebfa943..0000000 --- a/modules/regex/pcre2/src/pcre2_string_utils.c +++ /dev/null @@ -1,237 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -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) 2018-2021 University of Cambridge - ------------------------------------------------------------------------------ -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 OWNER 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. ------------------------------------------------------------------------------ -*/ - -/* This module contains internal functions for comparing and finding the length -of strings. These are used instead of strcmp() etc because the standard -functions work only on 8-bit data. */ - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "pcre2_internal.h" - - -/************************************************* -* Emulated memmove() for systems without it * -*************************************************/ - -/* This function can make use of bcopy() if it is available. Otherwise do it by -steam, as there some non-Unix environments that lack both memmove() and -bcopy(). */ - -#if !defined(VPCOMPAT) && !defined(HAVE_MEMMOVE) -void * -PRIV(memmove)(void *d, const void *s, size_t n) -{ -#ifdef HAVE_BCOPY -bcopy(s, d, n); -return d; -#else -size_t i; -unsigned char *dest = (unsigned char *)d; -const unsigned char *src = (const unsigned char *)s; -if (dest > src) - { - dest += n; - src += n; - for (i = 0; i < n; ++i) *(--dest) = *(--src); - return (void *)dest; - } -else - { - for (i = 0; i < n; ++i) *dest++ = *src++; - return (void *)(dest - n); - } -#endif /* not HAVE_BCOPY */ -} -#endif /* not VPCOMPAT && not HAVE_MEMMOVE */ - - -/************************************************* -* Compare two zero-terminated PCRE2 strings * -*************************************************/ - -/* -Arguments: - str1 first string - str2 second string - -Returns: 0, 1, or -1 -*/ - -int -PRIV(strcmp)(PCRE2_SPTR str1, PCRE2_SPTR str2) -{ -PCRE2_UCHAR c1, c2; -while (*str1 != '\0' || *str2 != '\0') - { - c1 = *str1++; - c2 = *str2++; - if (c1 != c2) return ((c1 > c2) << 1) - 1; - } -return 0; -} - - -/************************************************* -* Compare zero-terminated PCRE2 & 8-bit strings * -*************************************************/ - -/* As the 8-bit string is almost always a literal, its type is specified as -const char *. - -Arguments: - str1 first string - str2 second string - -Returns: 0, 1, or -1 -*/ - -int -PRIV(strcmp_c8)(PCRE2_SPTR str1, const char *str2) -{ -PCRE2_UCHAR c1, c2; -while (*str1 != '\0' || *str2 != '\0') - { - c1 = *str1++; - c2 = *str2++; - if (c1 != c2) return ((c1 > c2) << 1) - 1; - } -return 0; -} - - -/************************************************* -* Compare two PCRE2 strings, given a length * -*************************************************/ - -/* -Arguments: - str1 first string - str2 second string - len the length - -Returns: 0, 1, or -1 -*/ - -int -PRIV(strncmp)(PCRE2_SPTR str1, PCRE2_SPTR str2, size_t len) -{ -PCRE2_UCHAR c1, c2; -for (; len > 0; len--) - { - c1 = *str1++; - c2 = *str2++; - if (c1 != c2) return ((c1 > c2) << 1) - 1; - } -return 0; -} - - -/************************************************* -* Compare PCRE2 string to 8-bit string by length * -*************************************************/ - -/* As the 8-bit string is almost always a literal, its type is specified as -const char *. - -Arguments: - str1 first string - str2 second string - len the length - -Returns: 0, 1, or -1 -*/ - -int -PRIV(strncmp_c8)(PCRE2_SPTR str1, const char *str2, size_t len) -{ -PCRE2_UCHAR c1, c2; -for (; len > 0; len--) - { - c1 = *str1++; - c2 = *str2++; - if (c1 != c2) return ((c1 > c2) << 1) - 1; - } -return 0; -} - - -/************************************************* -* Find the length of a PCRE2 string * -*************************************************/ - -/* -Argument: the string -Returns: the length -*/ - -PCRE2_SIZE -PRIV(strlen)(PCRE2_SPTR str) -{ -PCRE2_SIZE c = 0; -while (*str++ != 0) c++; -return c; -} - - -/************************************************* -* Copy 8-bit 0-terminated string to PCRE2 string * -*************************************************/ - -/* Arguments: - str1 buffer to receive the string - str2 8-bit string to be copied - -Returns: the number of code units used (excluding trailing zero) -*/ - -PCRE2_SIZE -PRIV(strcpy_c8)(PCRE2_UCHAR *str1, const char *str2) -{ -PCRE2_UCHAR *t = str1; -while (*str2 != 0) *t++ = *str2++; -*t = 0; -return t - str1; -} - -/* End of pcre2_string_utils.c */ diff --git a/modules/regex/pcre2/src/pcre2_study.c b/modules/regex/pcre2/src/pcre2_study.c deleted file mode 100644 index 4db3ad1..0000000 --- a/modules/regex/pcre2/src/pcre2_study.c +++ /dev/null @@ -1,1825 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -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 - ------------------------------------------------------------------------------ -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 OWNER 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. ------------------------------------------------------------------------------ -*/ - -/* This module contains functions for scanning a compiled pattern and -collecting data (e.g. minimum matching length). */ - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "pcre2_internal.h" - -/* The maximum remembered capturing brackets minimum. */ - -#define MAX_CACHE_BACKREF 128 - -/* Set a bit in the starting code unit bit map. */ - -#define SET_BIT(c) re->start_bitmap[(c)/8] |= (1u << ((c)&7)) - -/* Returns from set_start_bits() */ - -enum { SSB_FAIL, SSB_DONE, SSB_CONTINUE, SSB_UNKNOWN, SSB_TOODEEP }; - - -/************************************************* -* Find the minimum subject length for a group * -*************************************************/ - -/* Scan a parenthesized group and compute the minimum length of subject that -is needed to match it. This is a lower bound; it does not mean there is a -string of that length that matches. In UTF mode, the result is in characters -rather than code units. The field in a compiled pattern for storing the minimum -length is 16-bits long (on the grounds that anything longer than that is -pathological), so we give up when we reach that amount. This also means that -integer overflow for really crazy patterns cannot happen. - -Backreference minimum lengths are cached to speed up multiple references. This -function is called only when the highest back reference in the pattern is less -than or equal to MAX_CACHE_BACKREF, which is one less than the size of the -caching vector. The zeroth element contains the number of the highest set -value. - -Arguments: - re compiled pattern block - code pointer to start of group (the bracket) - startcode pointer to start of the whole pattern's code - utf UTF flag - recurses chain of recurse_check to catch mutual recursion - countptr pointer to call count (to catch over complexity) - backref_cache vector for caching back references. - -This function is no longer called when the pattern contains (*ACCEPT); however, -the old code for returning -1 is retained, just in case. - -Returns: the minimum length - -1 \C in UTF-8 mode - or (*ACCEPT) - or pattern too complicated - -2 internal error (missing capturing bracket) - -3 internal error (opcode not listed) -*/ - -static int -find_minlength(const pcre2_real_code *re, PCRE2_SPTR code, - PCRE2_SPTR startcode, BOOL utf, recurse_check *recurses, int *countptr, - int *backref_cache) -{ -int length = -1; -int branchlength = 0; -int prev_cap_recno = -1; -int prev_cap_d = 0; -int prev_recurse_recno = -1; -int prev_recurse_d = 0; -uint32_t once_fudge = 0; -BOOL had_recurse = FALSE; -BOOL dupcapused = (re->flags & PCRE2_DUPCAPUSED) != 0; -PCRE2_SPTR nextbranch = code + GET(code, 1); -PCRE2_UCHAR *cc = (PCRE2_UCHAR *)code + 1 + LINK_SIZE; -recurse_check this_recurse; - -/* If this is a "could be empty" group, its minimum length is 0. */ - -if (*code >= OP_SBRA && *code <= OP_SCOND) return 0; - -/* Skip over capturing bracket number */ - -if (*code == OP_CBRA || *code == OP_CBRAPOS) cc += IMM2_SIZE; - -/* A large and/or complex regex can take too long to process. */ - -if ((*countptr)++ > 1000) return -1; - -/* Scan along the opcodes for this branch. If we get to the end of the branch, -check the length against that of the other branches. If the accumulated length -passes 16-bits, reset to that value and skip the rest of the branch. */ - -for (;;) - { - int d, min, recno; - PCRE2_UCHAR op, *cs, *ce; - - if (branchlength >= UINT16_MAX) - { - branchlength = UINT16_MAX; - cc = (PCRE2_UCHAR *)nextbranch; - } - - op = *cc; - switch (op) - { - case OP_COND: - case OP_SCOND: - - /* If there is only one branch in a condition, the implied branch has zero - length, so we don't add anything. This covers the DEFINE "condition" - automatically. If there are two branches we can treat it the same as any - other non-capturing subpattern. */ - - cs = cc + GET(cc, 1); - if (*cs != OP_ALT) - { - cc = cs + 1 + LINK_SIZE; - break; - } - goto PROCESS_NON_CAPTURE; - - case OP_BRA: - /* There's a special case of OP_BRA, when it is wrapped round a repeated - OP_RECURSE. We'd like to process the latter at this level so that - remembering the value works for repeated cases. So we do nothing, but - set a fudge value to skip over the OP_KET after the recurse. */ - - if (cc[1+LINK_SIZE] == OP_RECURSE && cc[2*(1+LINK_SIZE)] == OP_KET) - { - once_fudge = 1 + LINK_SIZE; - cc += 1 + LINK_SIZE; - break; - } - /* Fall through */ - - case OP_ONCE: - case OP_SCRIPT_RUN: - case OP_SBRA: - case OP_BRAPOS: - case OP_SBRAPOS: - PROCESS_NON_CAPTURE: - d = find_minlength(re, cc, startcode, utf, recurses, countptr, - backref_cache); - if (d < 0) return d; - branchlength += d; - do cc += GET(cc, 1); while (*cc == OP_ALT); - cc += 1 + LINK_SIZE; - break; - - /* To save time for repeated capturing subpatterns, we remember the - length of the previous one. Unfortunately we can't do the same for - the unnumbered ones above. Nor can we do this if (?| is present in the - pattern because captures with the same number are not then identical. */ - - case OP_CBRA: - case OP_SCBRA: - case OP_CBRAPOS: - case OP_SCBRAPOS: - recno = (int)GET2(cc, 1+LINK_SIZE); - if (dupcapused || recno != prev_cap_recno) - { - prev_cap_recno = recno; - prev_cap_d = find_minlength(re, cc, startcode, utf, recurses, countptr, - backref_cache); - if (prev_cap_d < 0) return prev_cap_d; - } - branchlength += prev_cap_d; - do cc += GET(cc, 1); while (*cc == OP_ALT); - cc += 1 + LINK_SIZE; - break; - - /* ACCEPT makes things far too complicated; we have to give up. In fact, - from 10.34 onwards, if a pattern contains (*ACCEPT), this function is not - used. However, leave the code in place, just in case. */ - - case OP_ACCEPT: - case OP_ASSERT_ACCEPT: - return -1; - - /* Reached end of a branch; if it's a ket it is the end of a nested - call. If it's ALT it is an alternation in a nested call. If it is END it's - the end of the outer call. All can be handled by the same code. If the - length of any branch is zero, there is no need to scan any subsequent - branches. */ - - case OP_ALT: - case OP_KET: - case OP_KETRMAX: - case OP_KETRMIN: - case OP_KETRPOS: - case OP_END: - if (length < 0 || (!had_recurse && branchlength < length)) - length = branchlength; - if (op != OP_ALT || length == 0) return length; - nextbranch = cc + GET(cc, 1); - cc += 1 + LINK_SIZE; - branchlength = 0; - had_recurse = FALSE; - break; - - /* Skip over assertive subpatterns */ - - case OP_ASSERT: - case OP_ASSERT_NOT: - case OP_ASSERTBACK: - case OP_ASSERTBACK_NOT: - case OP_ASSERT_NA: - case OP_ASSERTBACK_NA: - do cc += GET(cc, 1); while (*cc == OP_ALT); - /* Fall through */ - - /* Skip over things that don't match chars */ - - case OP_REVERSE: - case OP_CREF: - case OP_DNCREF: - case OP_RREF: - case OP_DNRREF: - case OP_FALSE: - case OP_TRUE: - case OP_CALLOUT: - case OP_SOD: - case OP_SOM: - case OP_EOD: - case OP_EODN: - case OP_CIRC: - case OP_CIRCM: - case OP_DOLL: - case OP_DOLLM: - case OP_NOT_WORD_BOUNDARY: - case OP_WORD_BOUNDARY: - cc += PRIV(OP_lengths)[*cc]; - break; - - case OP_CALLOUT_STR: - cc += GET(cc, 1 + 2*LINK_SIZE); - break; - - /* Skip over a subpattern that has a {0} or {0,x} quantifier */ - - case OP_BRAZERO: - case OP_BRAMINZERO: - case OP_BRAPOSZERO: - case OP_SKIPZERO: - cc += PRIV(OP_lengths)[*cc]; - do cc += GET(cc, 1); while (*cc == OP_ALT); - cc += 1 + LINK_SIZE; - break; - - /* Handle literal characters and + repetitions */ - - case OP_CHAR: - case OP_CHARI: - case OP_NOT: - case OP_NOTI: - case OP_PLUS: - case OP_PLUSI: - case OP_MINPLUS: - case OP_MINPLUSI: - case OP_POSPLUS: - case OP_POSPLUSI: - case OP_NOTPLUS: - case OP_NOTPLUSI: - case OP_NOTMINPLUS: - case OP_NOTMINPLUSI: - case OP_NOTPOSPLUS: - case OP_NOTPOSPLUSI: - branchlength++; - cc += 2; -#ifdef SUPPORT_UNICODE - if (utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); -#endif - break; - - case OP_TYPEPLUS: - case OP_TYPEMINPLUS: - case OP_TYPEPOSPLUS: - branchlength++; - cc += (cc[1] == OP_PROP || cc[1] == OP_NOTPROP)? 4 : 2; - break; - - /* Handle exact repetitions. The count is already in characters, but we - may need to skip over a multibyte character in UTF mode. */ - - case OP_EXACT: - case OP_EXACTI: - case OP_NOTEXACT: - case OP_NOTEXACTI: - branchlength += GET2(cc,1); - cc += 2 + IMM2_SIZE; -#ifdef SUPPORT_UNICODE - if (utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); -#endif - break; - - case OP_TYPEEXACT: - branchlength += GET2(cc,1); - cc += 2 + IMM2_SIZE + ((cc[1 + IMM2_SIZE] == OP_PROP - || cc[1 + IMM2_SIZE] == OP_NOTPROP)? 2 : 0); - break; - - /* Handle single-char non-literal matchers */ - - case OP_PROP: - case OP_NOTPROP: - cc += 2; - /* Fall through */ - - case OP_NOT_DIGIT: - case OP_DIGIT: - case OP_NOT_WHITESPACE: - case OP_WHITESPACE: - case OP_NOT_WORDCHAR: - case OP_WORDCHAR: - case OP_ANY: - case OP_ALLANY: - case OP_EXTUNI: - case OP_HSPACE: - case OP_NOT_HSPACE: - case OP_VSPACE: - case OP_NOT_VSPACE: - branchlength++; - cc++; - break; - - /* "Any newline" might match two characters, but it also might match just - one. */ - - case OP_ANYNL: - branchlength += 1; - cc++; - break; - - /* The single-byte matcher means we can't proceed in UTF mode. (In - non-UTF mode \C will actually be turned into OP_ALLANY, so won't ever - appear, but leave the code, just in case.) */ - - case OP_ANYBYTE: -#ifdef SUPPORT_UNICODE - if (utf) return -1; -#endif - branchlength++; - cc++; - break; - - /* For repeated character types, we have to test for \p and \P, which have - an extra two bytes of parameters. */ - - case OP_TYPESTAR: - case OP_TYPEMINSTAR: - case OP_TYPEQUERY: - case OP_TYPEMINQUERY: - case OP_TYPEPOSSTAR: - case OP_TYPEPOSQUERY: - if (cc[1] == OP_PROP || cc[1] == OP_NOTPROP) cc += 2; - cc += PRIV(OP_lengths)[op]; - break; - - case OP_TYPEUPTO: - case OP_TYPEMINUPTO: - case OP_TYPEPOSUPTO: - if (cc[1 + IMM2_SIZE] == OP_PROP - || cc[1 + IMM2_SIZE] == OP_NOTPROP) cc += 2; - cc += PRIV(OP_lengths)[op]; - break; - - /* Check a class for variable quantification */ - - case OP_CLASS: - case OP_NCLASS: -#ifdef SUPPORT_WIDE_CHARS - case OP_XCLASS: - /* The original code caused an unsigned overflow in 64 bit systems, - so now we use a conditional statement. */ - if (op == OP_XCLASS) - cc += GET(cc, 1); - else - cc += PRIV(OP_lengths)[OP_CLASS]; -#else - cc += PRIV(OP_lengths)[OP_CLASS]; -#endif - - switch (*cc) - { - case OP_CRPLUS: - case OP_CRMINPLUS: - case OP_CRPOSPLUS: - branchlength++; - /* Fall through */ - - case OP_CRSTAR: - case OP_CRMINSTAR: - case OP_CRQUERY: - case OP_CRMINQUERY: - case OP_CRPOSSTAR: - case OP_CRPOSQUERY: - cc++; - break; - - case OP_CRRANGE: - case OP_CRMINRANGE: - case OP_CRPOSRANGE: - branchlength += GET2(cc,1); - cc += 1 + 2 * IMM2_SIZE; - break; - - default: - branchlength++; - break; - } - break; - - /* Backreferences and subroutine calls (OP_RECURSE) are treated in the same - way: we find the minimum length for the subpattern. A recursion - (backreference or subroutine) causes an a flag to be set that causes the - length of this branch to be ignored. The logic is that a recursion can only - make sense if there is another alternative that stops the recursing. That - will provide the minimum length (when no recursion happens). - - If PCRE2_MATCH_UNSET_BACKREF is set, a backreference to an unset bracket - matches an empty string (by default it causes a matching failure), so in - that case we must set the minimum length to zero. - - For backreferenes, if duplicate numbers are present in the pattern we check - for a reference to a duplicate. If it is, we don't know which version will - be referenced, so we have to set the minimum length to zero. */ - - /* Duplicate named pattern back reference. */ - - case OP_DNREF: - case OP_DNREFI: - if (!dupcapused && (re->overall_options & PCRE2_MATCH_UNSET_BACKREF) == 0) - { - int count = GET2(cc, 1+IMM2_SIZE); - PCRE2_UCHAR *slot = - (PCRE2_UCHAR *)((uint8_t *)re + sizeof(pcre2_real_code)) + - GET2(cc, 1) * re->name_entry_size; - - d = INT_MAX; - - /* Scan all groups with the same name; find the shortest. */ - - while (count-- > 0) - { - int dd, i; - recno = GET2(slot, 0); - - if (recno <= backref_cache[0] && backref_cache[recno] >= 0) - dd = backref_cache[recno]; - else - { - ce = cs = (PCRE2_UCHAR *)PRIV(find_bracket)(startcode, utf, recno); - if (cs == NULL) return -2; - do ce += GET(ce, 1); while (*ce == OP_ALT); - - dd = 0; - if (!dupcapused || - (PCRE2_UCHAR *)PRIV(find_bracket)(ce, utf, recno) == NULL) - { - if (cc > cs && cc < ce) /* Simple recursion */ - { - had_recurse = TRUE; - } - else - { - recurse_check *r = recurses; - for (r = recurses; r != NULL; r = r->prev) - if (r->group == cs) break; - if (r != NULL) /* Mutual recursion */ - { - had_recurse = TRUE; - } - else - { - this_recurse.prev = recurses; /* No recursion */ - this_recurse.group = cs; - dd = find_minlength(re, cs, startcode, utf, &this_recurse, - countptr, backref_cache); - if (dd < 0) return dd; - } - } - } - - backref_cache[recno] = dd; - for (i = backref_cache[0] + 1; i < recno; i++) backref_cache[i] = -1; - backref_cache[0] = recno; - } - - if (dd < d) d = dd; - if (d <= 0) break; /* No point looking at any more */ - slot += re->name_entry_size; - } - } - else d = 0; - cc += 1 + 2*IMM2_SIZE; - goto REPEAT_BACK_REFERENCE; - - /* Single back reference by number. References by name are converted to by - number when there is no duplication. */ - - case OP_REF: - case OP_REFI: - recno = GET2(cc, 1); - if (recno <= backref_cache[0] && backref_cache[recno] >= 0) - d = backref_cache[recno]; - else - { - int i; - d = 0; - - if ((re->overall_options & PCRE2_MATCH_UNSET_BACKREF) == 0) - { - ce = cs = (PCRE2_UCHAR *)PRIV(find_bracket)(startcode, utf, recno); - if (cs == NULL) return -2; - do ce += GET(ce, 1); while (*ce == OP_ALT); - - if (!dupcapused || - (PCRE2_UCHAR *)PRIV(find_bracket)(ce, utf, recno) == NULL) - { - if (cc > cs && cc < ce) /* Simple recursion */ - { - had_recurse = TRUE; - } - else - { - recurse_check *r = recurses; - for (r = recurses; r != NULL; r = r->prev) if (r->group == cs) break; - if (r != NULL) /* Mutual recursion */ - { - had_recurse = TRUE; - } - else /* No recursion */ - { - this_recurse.prev = recurses; - this_recurse.group = cs; - d = find_minlength(re, cs, startcode, utf, &this_recurse, countptr, - backref_cache); - if (d < 0) return d; - } - } - } - } - - backref_cache[recno] = d; - for (i = backref_cache[0] + 1; i < recno; i++) backref_cache[i] = -1; - backref_cache[0] = recno; - } - - cc += 1 + IMM2_SIZE; - - /* Handle repeated back references */ - - REPEAT_BACK_REFERENCE: - switch (*cc) - { - case OP_CRSTAR: - case OP_CRMINSTAR: - case OP_CRQUERY: - case OP_CRMINQUERY: - case OP_CRPOSSTAR: - case OP_CRPOSQUERY: - min = 0; - cc++; - break; - - case OP_CRPLUS: - case OP_CRMINPLUS: - case OP_CRPOSPLUS: - min = 1; - cc++; - break; - - case OP_CRRANGE: - case OP_CRMINRANGE: - case OP_CRPOSRANGE: - min = GET2(cc, 1); - cc += 1 + 2 * IMM2_SIZE; - break; - - default: - min = 1; - break; - } - - /* Take care not to overflow: (1) min and d are ints, so check that their - product is not greater than INT_MAX. (2) branchlength is limited to - UINT16_MAX (checked at the top of the loop). */ - - if ((d > 0 && (INT_MAX/d) < min) || UINT16_MAX - branchlength < min*d) - branchlength = UINT16_MAX; - else branchlength += min * d; - break; - - /* Recursion always refers to the first occurrence of a subpattern with a - given number. Therefore, we can always make use of caching, even when the - pattern contains multiple subpatterns with the same number. */ - - case OP_RECURSE: - cs = ce = (PCRE2_UCHAR *)startcode + GET(cc, 1); - recno = GET2(cs, 1+LINK_SIZE); - if (recno == prev_recurse_recno) - { - branchlength += prev_recurse_d; - } - else - { - do ce += GET(ce, 1); while (*ce == OP_ALT); - if (cc > cs && cc < ce) /* Simple recursion */ - had_recurse = TRUE; - else - { - recurse_check *r = recurses; - for (r = recurses; r != NULL; r = r->prev) if (r->group == cs) break; - if (r != NULL) /* Mutual recursion */ - had_recurse = TRUE; - else - { - this_recurse.prev = recurses; - this_recurse.group = cs; - prev_recurse_d = find_minlength(re, cs, startcode, utf, &this_recurse, - countptr, backref_cache); - if (prev_recurse_d < 0) return prev_recurse_d; - prev_recurse_recno = recno; - branchlength += prev_recurse_d; - } - } - } - cc += 1 + LINK_SIZE + once_fudge; - once_fudge = 0; - break; - - /* Anything else does not or need not match a character. We can get the - item's length from the table, but for those that can match zero occurrences - of a character, we must take special action for UTF-8 characters. As it - happens, the "NOT" versions of these opcodes are used at present only for - ASCII characters, so they could be omitted from this list. However, in - future that may change, so we include them here so as not to leave a - gotcha for a future maintainer. */ - - case OP_UPTO: - case OP_UPTOI: - case OP_NOTUPTO: - case OP_NOTUPTOI: - case OP_MINUPTO: - case OP_MINUPTOI: - case OP_NOTMINUPTO: - case OP_NOTMINUPTOI: - case OP_POSUPTO: - case OP_POSUPTOI: - case OP_NOTPOSUPTO: - case OP_NOTPOSUPTOI: - - case OP_STAR: - case OP_STARI: - case OP_NOTSTAR: - case OP_NOTSTARI: - case OP_MINSTAR: - case OP_MINSTARI: - case OP_NOTMINSTAR: - case OP_NOTMINSTARI: - case OP_POSSTAR: - case OP_POSSTARI: - case OP_NOTPOSSTAR: - case OP_NOTPOSSTARI: - - case OP_QUERY: - case OP_QUERYI: - case OP_NOTQUERY: - case OP_NOTQUERYI: - case OP_MINQUERY: - case OP_MINQUERYI: - case OP_NOTMINQUERY: - case OP_NOTMINQUERYI: - case OP_POSQUERY: - case OP_POSQUERYI: - case OP_NOTPOSQUERY: - case OP_NOTPOSQUERYI: - - cc += PRIV(OP_lengths)[op]; -#ifdef SUPPORT_UNICODE - if (utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); -#endif - break; - - /* Skip these, but we need to add in the name length. */ - - case OP_MARK: - case OP_COMMIT_ARG: - case OP_PRUNE_ARG: - case OP_SKIP_ARG: - case OP_THEN_ARG: - cc += PRIV(OP_lengths)[op] + cc[1]; - break; - - /* The remaining opcodes are just skipped over. */ - - case OP_CLOSE: - case OP_COMMIT: - case OP_FAIL: - case OP_PRUNE: - case OP_SET_SOM: - case OP_SKIP: - case OP_THEN: - cc += PRIV(OP_lengths)[op]; - break; - - /* This should not occur: we list all opcodes explicitly so that when - new ones get added they are properly considered. */ - - default: - return -3; - } - } -/* Control never gets here */ -} - - - -/************************************************* -* Set a bit and maybe its alternate case * -*************************************************/ - -/* Given a character, set its first code unit's bit in the table, and also the -corresponding bit for the other version of a letter if we are caseless. - -Arguments: - re points to the regex block - p points to the first code unit of the character - caseless TRUE if caseless - utf TRUE for UTF mode - ucp TRUE for UCP mode - -Returns: pointer after the character -*/ - -static PCRE2_SPTR -set_table_bit(pcre2_real_code *re, PCRE2_SPTR p, BOOL caseless, BOOL utf, - BOOL ucp) -{ -uint32_t c = *p++; /* First code unit */ - -(void)utf; /* Stop compiler warnings when UTF not supported */ -(void)ucp; - -/* In 16-bit and 32-bit modes, code units greater than 0xff set the bit for -0xff. */ - -#if PCRE2_CODE_UNIT_WIDTH != 8 -if (c > 0xff) SET_BIT(0xff); else -#endif - -SET_BIT(c); - -/* In UTF-8 or UTF-16 mode, pick up the remaining code units in order to find -the end of the character, even when caseless. */ - -#ifdef SUPPORT_UNICODE -if (utf) - { -#if PCRE2_CODE_UNIT_WIDTH == 8 - if (c >= 0xc0) GETUTF8INC(c, p); -#elif PCRE2_CODE_UNIT_WIDTH == 16 - if ((c & 0xfc00) == 0xd800) GETUTF16INC(c, p); -#endif - } -#endif /* SUPPORT_UNICODE */ - -/* If caseless, handle the other case of the character. */ - -if (caseless) - { -#ifdef SUPPORT_UNICODE - if (utf || ucp) - { - c = UCD_OTHERCASE(c); -#if PCRE2_CODE_UNIT_WIDTH == 8 - if (utf) - { - PCRE2_UCHAR buff[6]; - (void)PRIV(ord2utf)(c, buff); - SET_BIT(buff[0]); - } - else if (c < 256) SET_BIT(c); -#else /* 16-bit or 32-bit mode */ - if (c > 0xff) SET_BIT(0xff); else SET_BIT(c); -#endif - } - - else -#endif /* SUPPORT_UNICODE */ - - /* Not UTF or UCP */ - - if (MAX_255(c)) SET_BIT(re->tables[fcc_offset + c]); - } - -return p; -} - - - -/************************************************* -* Set bits for a positive character type * -*************************************************/ - -/* This function sets starting bits for a character type. In UTF-8 mode, we can -only do a direct setting for bytes less than 128, as otherwise there can be -confusion with bytes in the middle of UTF-8 characters. In a "traditional" -environment, the tables will only recognize ASCII characters anyway, but in at -least one Windows environment, some higher bytes bits were set in the tables. -So we deal with that case by considering the UTF-8 encoding. - -Arguments: - re the regex block - cbit type the type of character wanted - table_limit 32 for non-UTF-8; 16 for UTF-8 - -Returns: nothing -*/ - -static void -set_type_bits(pcre2_real_code *re, int cbit_type, unsigned int table_limit) -{ -uint32_t c; -for (c = 0; c < table_limit; c++) - re->start_bitmap[c] |= re->tables[c+cbits_offset+cbit_type]; -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8 -if (table_limit == 32) return; -for (c = 128; c < 256; c++) - { - if ((re->tables[cbits_offset + c/8] & (1u << (c&7))) != 0) - { - PCRE2_UCHAR buff[6]; - (void)PRIV(ord2utf)(c, buff); - SET_BIT(buff[0]); - } - } -#endif /* UTF-8 */ -} - - -/************************************************* -* Set bits for a negative character type * -*************************************************/ - -/* This function sets starting bits for a negative character type such as \D. -In UTF-8 mode, we can only do a direct setting for bytes less than 128, as -otherwise there can be confusion with bytes in the middle of UTF-8 characters. -Unlike in the positive case, where we can set appropriate starting bits for -specific high-valued UTF-8 characters, in this case we have to set the bits for -all high-valued characters. The lowest is 0xc2, but we overkill by starting at -0xc0 (192) for simplicity. - -Arguments: - re the regex block - cbit type the type of character wanted - table_limit 32 for non-UTF-8; 16 for UTF-8 - -Returns: nothing -*/ - -static void -set_nottype_bits(pcre2_real_code *re, int cbit_type, unsigned int table_limit) -{ -uint32_t c; -for (c = 0; c < table_limit; c++) - re->start_bitmap[c] |= (uint8_t)(~(re->tables[c+cbits_offset+cbit_type])); -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8 -if (table_limit != 32) for (c = 24; c < 32; c++) re->start_bitmap[c] = 0xff; -#endif -} - - - -/************************************************* -* Create bitmap of starting code units * -*************************************************/ - -/* This function scans a compiled unanchored expression recursively and -attempts to build a bitmap of the set of possible starting code units whose -values are less than 256. In 16-bit and 32-bit mode, values above 255 all cause -the 255 bit to be set. When calling set[_not]_type_bits() in UTF-8 (sic) mode -we pass a value of 16 rather than 32 as the final argument. (See comments in -those functions for the reason.) - -The SSB_CONTINUE return is useful for parenthesized groups in patterns such as -(a*)b where the group provides some optional starting code units but scanning -must continue at the outer level to find at least one mandatory code unit. At -the outermost level, this function fails unless the result is SSB_DONE. - -We restrict recursion (for nested groups) to 1000 to avoid stack overflow -issues. - -Arguments: - re points to the compiled regex block - code points to an expression - utf TRUE if in UTF mode - ucp TRUE if in UCP mode - depthptr pointer to recurse depth - -Returns: SSB_FAIL => Failed to find any starting code units - SSB_DONE => Found mandatory starting code units - SSB_CONTINUE => Found optional starting code units - SSB_UNKNOWN => Hit an unrecognized opcode - SSB_TOODEEP => Recursion is too deep -*/ - -static int -set_start_bits(pcre2_real_code *re, PCRE2_SPTR code, BOOL utf, BOOL ucp, - int *depthptr) -{ -uint32_t c; -int yield = SSB_DONE; - -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8 -int table_limit = utf? 16:32; -#else -int table_limit = 32; -#endif - -*depthptr += 1; -if (*depthptr > 1000) return SSB_TOODEEP; - -do - { - BOOL try_next = TRUE; - PCRE2_SPTR tcode = code + 1 + LINK_SIZE; - - if (*code == OP_CBRA || *code == OP_SCBRA || - *code == OP_CBRAPOS || *code == OP_SCBRAPOS) tcode += IMM2_SIZE; - - while (try_next) /* Loop for items in this branch */ - { - int rc; - uint8_t *classmap = NULL; -#ifdef SUPPORT_WIDE_CHARS - PCRE2_UCHAR xclassflags; -#endif - - switch(*tcode) - { - /* If we reach something we don't understand, it means a new opcode has - been created that hasn't been added to this function. Hopefully this - problem will be discovered during testing. */ - - default: - return SSB_UNKNOWN; - - /* Fail for a valid opcode that implies no starting bits. */ - - case OP_ACCEPT: - case OP_ASSERT_ACCEPT: - case OP_ALLANY: - case OP_ANY: - case OP_ANYBYTE: - case OP_CIRCM: - case OP_CLOSE: - case OP_COMMIT: - case OP_COMMIT_ARG: - case OP_COND: - case OP_CREF: - case OP_FALSE: - case OP_TRUE: - case OP_DNCREF: - case OP_DNREF: - case OP_DNREFI: - case OP_DNRREF: - case OP_DOLL: - case OP_DOLLM: - case OP_END: - case OP_EOD: - case OP_EODN: - case OP_EXTUNI: - case OP_FAIL: - case OP_MARK: - case OP_NOT: - case OP_NOTEXACT: - case OP_NOTEXACTI: - case OP_NOTI: - case OP_NOTMINPLUS: - case OP_NOTMINPLUSI: - case OP_NOTMINQUERY: - case OP_NOTMINQUERYI: - case OP_NOTMINSTAR: - case OP_NOTMINSTARI: - case OP_NOTMINUPTO: - case OP_NOTMINUPTOI: - case OP_NOTPLUS: - case OP_NOTPLUSI: - case OP_NOTPOSPLUS: - case OP_NOTPOSPLUSI: - case OP_NOTPOSQUERY: - case OP_NOTPOSQUERYI: - case OP_NOTPOSSTAR: - case OP_NOTPOSSTARI: - case OP_NOTPOSUPTO: - case OP_NOTPOSUPTOI: - case OP_NOTPROP: - case OP_NOTQUERY: - case OP_NOTQUERYI: - case OP_NOTSTAR: - case OP_NOTSTARI: - case OP_NOTUPTO: - case OP_NOTUPTOI: - case OP_NOT_HSPACE: - case OP_NOT_VSPACE: - case OP_PRUNE: - case OP_PRUNE_ARG: - case OP_RECURSE: - case OP_REF: - case OP_REFI: - case OP_REVERSE: - case OP_RREF: - case OP_SCOND: - case OP_SET_SOM: - case OP_SKIP: - case OP_SKIP_ARG: - case OP_SOD: - case OP_SOM: - case OP_THEN: - case OP_THEN_ARG: - return SSB_FAIL; - - /* OP_CIRC happens only at the start of an anchored branch (multiline ^ - uses OP_CIRCM). Skip over it. */ - - case OP_CIRC: - tcode += PRIV(OP_lengths)[OP_CIRC]; - break; - - /* A "real" property test implies no starting bits, but the fake property - PT_CLIST identifies a list of characters. These lists are short, as they - are used for characters with more than one "other case", so there is no - point in recognizing them for OP_NOTPROP. */ - - case OP_PROP: - if (tcode[1] != PT_CLIST) return SSB_FAIL; - { - const uint32_t *p = PRIV(ucd_caseless_sets) + tcode[2]; - while ((c = *p++) < NOTACHAR) - { -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8 - if (utf) - { - PCRE2_UCHAR buff[6]; - (void)PRIV(ord2utf)(c, buff); - c = buff[0]; - } -#endif - if (c > 0xff) SET_BIT(0xff); else SET_BIT(c); - } - } - try_next = FALSE; - break; - - /* We can ignore word boundary tests. */ - - case OP_WORD_BOUNDARY: - case OP_NOT_WORD_BOUNDARY: - tcode++; - break; - - /* If we hit a bracket or a positive lookahead assertion, recurse to set - bits from within the subpattern. If it can't find anything, we have to - give up. If it finds some mandatory character(s), we are done for this - branch. Otherwise, carry on scanning after the subpattern. */ - - case OP_BRA: - case OP_SBRA: - case OP_CBRA: - case OP_SCBRA: - case OP_BRAPOS: - case OP_SBRAPOS: - case OP_CBRAPOS: - case OP_SCBRAPOS: - case OP_ONCE: - case OP_SCRIPT_RUN: - case OP_ASSERT: - case OP_ASSERT_NA: - rc = set_start_bits(re, tcode, utf, ucp, depthptr); - if (rc == SSB_DONE) - { - try_next = FALSE; - } - else if (rc == SSB_CONTINUE) - { - do tcode += GET(tcode, 1); while (*tcode == OP_ALT); - tcode += 1 + LINK_SIZE; - } - else return rc; /* FAIL, UNKNOWN, or TOODEEP */ - break; - - /* If we hit ALT or KET, it means we haven't found anything mandatory in - this branch, though we might have found something optional. For ALT, we - continue with the next alternative, but we have to arrange that the final - result from subpattern is SSB_CONTINUE rather than SSB_DONE. For KET, - return SSB_CONTINUE: if this is the top level, that indicates failure, - but after a nested subpattern, it causes scanning to continue. */ - - case OP_ALT: - yield = SSB_CONTINUE; - try_next = FALSE; - break; - - case OP_KET: - case OP_KETRMAX: - case OP_KETRMIN: - case OP_KETRPOS: - return SSB_CONTINUE; - - /* Skip over callout */ - - case OP_CALLOUT: - tcode += PRIV(OP_lengths)[OP_CALLOUT]; - break; - - case OP_CALLOUT_STR: - tcode += GET(tcode, 1 + 2*LINK_SIZE); - break; - - /* Skip over lookbehind and negative lookahead assertions */ - - case OP_ASSERT_NOT: - case OP_ASSERTBACK: - case OP_ASSERTBACK_NOT: - case OP_ASSERTBACK_NA: - do tcode += GET(tcode, 1); while (*tcode == OP_ALT); - tcode += 1 + LINK_SIZE; - break; - - /* BRAZERO does the bracket, but carries on. */ - - case OP_BRAZERO: - case OP_BRAMINZERO: - case OP_BRAPOSZERO: - rc = set_start_bits(re, ++tcode, utf, ucp, depthptr); - if (rc == SSB_FAIL || rc == SSB_UNKNOWN || rc == SSB_TOODEEP) return rc; - do tcode += GET(tcode,1); while (*tcode == OP_ALT); - tcode += 1 + LINK_SIZE; - break; - - /* SKIPZERO skips the bracket. */ - - case OP_SKIPZERO: - tcode++; - do tcode += GET(tcode,1); while (*tcode == OP_ALT); - tcode += 1 + LINK_SIZE; - break; - - /* Single-char * or ? sets the bit and tries the next item */ - - case OP_STAR: - case OP_MINSTAR: - case OP_POSSTAR: - case OP_QUERY: - case OP_MINQUERY: - case OP_POSQUERY: - tcode = set_table_bit(re, tcode + 1, FALSE, utf, ucp); - break; - - case OP_STARI: - case OP_MINSTARI: - case OP_POSSTARI: - case OP_QUERYI: - case OP_MINQUERYI: - case OP_POSQUERYI: - tcode = set_table_bit(re, tcode + 1, TRUE, utf, ucp); - break; - - /* Single-char upto sets the bit and tries the next */ - - case OP_UPTO: - case OP_MINUPTO: - case OP_POSUPTO: - tcode = set_table_bit(re, tcode + 1 + IMM2_SIZE, FALSE, utf, ucp); - break; - - case OP_UPTOI: - case OP_MINUPTOI: - case OP_POSUPTOI: - tcode = set_table_bit(re, tcode + 1 + IMM2_SIZE, TRUE, utf, ucp); - break; - - /* At least one single char sets the bit and stops */ - - case OP_EXACT: - tcode += IMM2_SIZE; - /* Fall through */ - case OP_CHAR: - case OP_PLUS: - case OP_MINPLUS: - case OP_POSPLUS: - (void)set_table_bit(re, tcode + 1, FALSE, utf, ucp); - try_next = FALSE; - break; - - case OP_EXACTI: - tcode += IMM2_SIZE; - /* Fall through */ - case OP_CHARI: - case OP_PLUSI: - case OP_MINPLUSI: - case OP_POSPLUSI: - (void)set_table_bit(re, tcode + 1, TRUE, utf, ucp); - try_next = FALSE; - break; - - /* Special spacing and line-terminating items. These recognize specific - lists of characters. The difference between VSPACE and ANYNL is that the - latter can match the two-character CRLF sequence, but that is not - relevant for finding the first character, so their code here is - identical. */ - - case OP_HSPACE: - SET_BIT(CHAR_HT); - SET_BIT(CHAR_SPACE); - - /* For the 16-bit and 32-bit libraries (which can never be EBCDIC), set - the bits for 0xA0 and for code units >= 255, independently of UTF. */ - -#if PCRE2_CODE_UNIT_WIDTH != 8 - SET_BIT(0xA0); - SET_BIT(0xFF); -#else - /* For the 8-bit library in UTF-8 mode, set the bits for the first code - units of horizontal space characters. */ - -#ifdef SUPPORT_UNICODE - if (utf) - { - SET_BIT(0xC2); /* For U+00A0 */ - SET_BIT(0xE1); /* For U+1680, U+180E */ - SET_BIT(0xE2); /* For U+2000 - U+200A, U+202F, U+205F */ - SET_BIT(0xE3); /* For U+3000 */ - } - else -#endif - /* For the 8-bit library not in UTF-8 mode, set the bit for 0xA0, unless - the code is EBCDIC. */ - { -#ifndef EBCDIC - SET_BIT(0xA0); -#endif /* Not EBCDIC */ - } -#endif /* 8-bit support */ - - try_next = FALSE; - break; - - case OP_ANYNL: - case OP_VSPACE: - SET_BIT(CHAR_LF); - SET_BIT(CHAR_VT); - SET_BIT(CHAR_FF); - SET_BIT(CHAR_CR); - - /* For the 16-bit and 32-bit libraries (which can never be EBCDIC), set - the bits for NEL and for code units >= 255, independently of UTF. */ - -#if PCRE2_CODE_UNIT_WIDTH != 8 - SET_BIT(CHAR_NEL); - SET_BIT(0xFF); -#else - /* For the 8-bit library in UTF-8 mode, set the bits for the first code - units of vertical space characters. */ - -#ifdef SUPPORT_UNICODE - if (utf) - { - SET_BIT(0xC2); /* For U+0085 (NEL) */ - SET_BIT(0xE2); /* For U+2028, U+2029 */ - } - else -#endif - /* For the 8-bit library not in UTF-8 mode, set the bit for NEL. */ - { - SET_BIT(CHAR_NEL); - } -#endif /* 8-bit support */ - - try_next = FALSE; - break; - - /* Single character types set the bits and stop. Note that if PCRE2_UCP - is set, we do not see these opcodes because \d etc are converted to - properties. Therefore, these apply in the case when only characters less - than 256 are recognized to match the types. */ - - case OP_NOT_DIGIT: - set_nottype_bits(re, cbit_digit, table_limit); - try_next = FALSE; - break; - - case OP_DIGIT: - set_type_bits(re, cbit_digit, table_limit); - try_next = FALSE; - break; - - case OP_NOT_WHITESPACE: - set_nottype_bits(re, cbit_space, table_limit); - try_next = FALSE; - break; - - case OP_WHITESPACE: - set_type_bits(re, cbit_space, table_limit); - try_next = FALSE; - break; - - case OP_NOT_WORDCHAR: - set_nottype_bits(re, cbit_word, table_limit); - try_next = FALSE; - break; - - case OP_WORDCHAR: - set_type_bits(re, cbit_word, table_limit); - try_next = FALSE; - break; - - /* One or more character type fudges the pointer and restarts, knowing - it will hit a single character type and stop there. */ - - case OP_TYPEPLUS: - case OP_TYPEMINPLUS: - case OP_TYPEPOSPLUS: - tcode++; - break; - - case OP_TYPEEXACT: - tcode += 1 + IMM2_SIZE; - break; - - /* Zero or more repeats of character types set the bits and then - try again. */ - - case OP_TYPEUPTO: - case OP_TYPEMINUPTO: - case OP_TYPEPOSUPTO: - tcode += IMM2_SIZE; /* Fall through */ - - case OP_TYPESTAR: - case OP_TYPEMINSTAR: - case OP_TYPEPOSSTAR: - case OP_TYPEQUERY: - case OP_TYPEMINQUERY: - case OP_TYPEPOSQUERY: - switch(tcode[1]) - { - default: - case OP_ANY: - case OP_ALLANY: - return SSB_FAIL; - - case OP_HSPACE: - SET_BIT(CHAR_HT); - SET_BIT(CHAR_SPACE); - - /* For the 16-bit and 32-bit libraries (which can never be EBCDIC), set - the bits for 0xA0 and for code units >= 255, independently of UTF. */ - -#if PCRE2_CODE_UNIT_WIDTH != 8 - SET_BIT(0xA0); - SET_BIT(0xFF); -#else - /* For the 8-bit library in UTF-8 mode, set the bits for the first code - units of horizontal space characters. */ - -#ifdef SUPPORT_UNICODE - if (utf) - { - SET_BIT(0xC2); /* For U+00A0 */ - SET_BIT(0xE1); /* For U+1680, U+180E */ - SET_BIT(0xE2); /* For U+2000 - U+200A, U+202F, U+205F */ - SET_BIT(0xE3); /* For U+3000 */ - } - else -#endif - /* For the 8-bit library not in UTF-8 mode, set the bit for 0xA0, unless - the code is EBCDIC. */ - { -#ifndef EBCDIC - SET_BIT(0xA0); -#endif /* Not EBCDIC */ - } -#endif /* 8-bit support */ - break; - - case OP_ANYNL: - case OP_VSPACE: - SET_BIT(CHAR_LF); - SET_BIT(CHAR_VT); - SET_BIT(CHAR_FF); - SET_BIT(CHAR_CR); - - /* For the 16-bit and 32-bit libraries (which can never be EBCDIC), set - the bits for NEL and for code units >= 255, independently of UTF. */ - -#if PCRE2_CODE_UNIT_WIDTH != 8 - SET_BIT(CHAR_NEL); - SET_BIT(0xFF); -#else - /* For the 8-bit library in UTF-8 mode, set the bits for the first code - units of vertical space characters. */ - -#ifdef SUPPORT_UNICODE - if (utf) - { - SET_BIT(0xC2); /* For U+0085 (NEL) */ - SET_BIT(0xE2); /* For U+2028, U+2029 */ - } - else -#endif - /* For the 8-bit library not in UTF-8 mode, set the bit for NEL. */ - { - SET_BIT(CHAR_NEL); - } -#endif /* 8-bit support */ - break; - - case OP_NOT_DIGIT: - set_nottype_bits(re, cbit_digit, table_limit); - break; - - case OP_DIGIT: - set_type_bits(re, cbit_digit, table_limit); - break; - - case OP_NOT_WHITESPACE: - set_nottype_bits(re, cbit_space, table_limit); - break; - - case OP_WHITESPACE: - set_type_bits(re, cbit_space, table_limit); - break; - - case OP_NOT_WORDCHAR: - set_nottype_bits(re, cbit_word, table_limit); - break; - - case OP_WORDCHAR: - set_type_bits(re, cbit_word, table_limit); - break; - } - - tcode += 2; - break; - - /* Extended class: if there are any property checks, or if this is a - negative XCLASS without a map, give up. If there are no property checks, - there must be wide characters on the XCLASS list, because otherwise an - XCLASS would not have been created. This means that code points >= 255 - are potential starters. In the UTF-8 case we can scan them and set bits - for the relevant leading bytes. */ - -#ifdef SUPPORT_WIDE_CHARS - case OP_XCLASS: - xclassflags = tcode[1 + LINK_SIZE]; - if ((xclassflags & XCL_HASPROP) != 0 || - (xclassflags & (XCL_MAP|XCL_NOT)) == XCL_NOT) - return SSB_FAIL; - - /* We have a positive XCLASS or a negative one without a map. Set up the - map pointer if there is one, and fall through. */ - - classmap = ((xclassflags & XCL_MAP) == 0)? NULL : - (uint8_t *)(tcode + 1 + LINK_SIZE + 1); - - /* In UTF-8 mode, scan the character list and set bits for leading bytes, - then jump to handle the map. */ - -#if PCRE2_CODE_UNIT_WIDTH == 8 - if (utf && (xclassflags & XCL_NOT) == 0) - { - PCRE2_UCHAR b, e; - PCRE2_SPTR p = tcode + 1 + LINK_SIZE + 1 + ((classmap == NULL)? 0:32); - tcode += GET(tcode, 1); - - for (;;) switch (*p++) - { - case XCL_SINGLE: - b = *p++; - while ((*p & 0xc0) == 0x80) p++; - re->start_bitmap[b/8] |= (1u << (b&7)); - break; - - case XCL_RANGE: - b = *p++; - while ((*p & 0xc0) == 0x80) p++; - e = *p++; - while ((*p & 0xc0) == 0x80) p++; - for (; b <= e; b++) - re->start_bitmap[b/8] |= (1u << (b&7)); - break; - - case XCL_END: - goto HANDLE_CLASSMAP; - - default: - return SSB_UNKNOWN; /* Internal error, should not occur */ - } - } -#endif /* SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8 */ -#endif /* SUPPORT_WIDE_CHARS */ - - /* It seems that the fall through comment must be outside the #ifdef if - it is to avoid the gcc compiler warning. */ - - /* Fall through */ - - /* Enter here for a negative non-XCLASS. In the 8-bit library, if we are - in UTF mode, any byte with a value >= 0xc4 is a potentially valid starter - because it starts a character with a value > 255. In 8-bit non-UTF mode, - there is no difference between CLASS and NCLASS. In all other wide - character modes, set the 0xFF bit to indicate code units >= 255. */ - - case OP_NCLASS: -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8 - if (utf) - { - re->start_bitmap[24] |= 0xf0; /* Bits for 0xc4 - 0xc8 */ - memset(re->start_bitmap+25, 0xff, 7); /* Bits for 0xc9 - 0xff */ - } -#elif PCRE2_CODE_UNIT_WIDTH != 8 - SET_BIT(0xFF); /* For characters >= 255 */ -#endif - /* Fall through */ - - /* Enter here for a positive non-XCLASS. If we have fallen through from - an XCLASS, classmap will already be set; just advance the code pointer. - Otherwise, set up classmap for a a non-XCLASS and advance past it. */ - - case OP_CLASS: - if (*tcode == OP_XCLASS) tcode += GET(tcode, 1); else - { - classmap = (uint8_t *)(++tcode); - tcode += 32 / sizeof(PCRE2_UCHAR); - } - - /* When wide characters are supported, classmap may be NULL. In UTF-8 - (sic) mode, the bits in a class bit map correspond to character values, - not to byte values. However, the bit map we are constructing is for byte - values. So we have to do a conversion for characters whose code point is - greater than 127. In fact, there are only two possible starting bytes for - characters in the range 128 - 255. */ - -#if defined SUPPORT_WIDE_CHARS && PCRE2_CODE_UNIT_WIDTH == 8 - HANDLE_CLASSMAP: -#endif - if (classmap != NULL) - { -#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8 - if (utf) - { - for (c = 0; c < 16; c++) re->start_bitmap[c] |= classmap[c]; - for (c = 128; c < 256; c++) - { - if ((classmap[c/8] & (1u << (c&7))) != 0) - { - int d = (c >> 6) | 0xc0; /* Set bit for this starter */ - re->start_bitmap[d/8] |= (1u << (d&7)); /* and then skip on to the */ - c = (c & 0xc0) + 0x40 - 1; /* next relevant character. */ - } - } - } - else -#endif - /* In all modes except UTF-8, the two bit maps are compatible. */ - - { - for (c = 0; c < 32; c++) re->start_bitmap[c] |= classmap[c]; - } - } - - /* Act on what follows the class. For a zero minimum repeat, continue; - otherwise stop processing. */ - - switch (*tcode) - { - case OP_CRSTAR: - case OP_CRMINSTAR: - case OP_CRQUERY: - case OP_CRMINQUERY: - case OP_CRPOSSTAR: - case OP_CRPOSQUERY: - tcode++; - break; - - case OP_CRRANGE: - case OP_CRMINRANGE: - case OP_CRPOSRANGE: - if (GET2(tcode, 1) == 0) tcode += 1 + 2 * IMM2_SIZE; - else try_next = FALSE; - break; - - default: - try_next = FALSE; - break; - } - break; /* End of class handling case */ - } /* End of switch for opcodes */ - } /* End of try_next loop */ - - code += GET(code, 1); /* Advance to next branch */ - } -while (*code == OP_ALT); - -return yield; -} - - - -/************************************************* -* Study a compiled expression * -*************************************************/ - -/* This function is handed a compiled expression that it must study to produce -information that will speed up the matching. - -Argument: - re points to the compiled expression - -Returns: 0 normally; non-zero should never normally occur - 1 unknown opcode in set_start_bits - 2 missing capturing bracket - 3 unknown opcode in find_minlength -*/ - -int -PRIV(study)(pcre2_real_code *re) -{ -int count = 0; -PCRE2_UCHAR *code; -BOOL utf = (re->overall_options & PCRE2_UTF) != 0; -BOOL ucp = (re->overall_options & PCRE2_UCP) != 0; - -/* Find start of compiled code */ - -code = (PCRE2_UCHAR *)((uint8_t *)re + sizeof(pcre2_real_code)) + - re->name_entry_size * re->name_count; - -/* For a pattern that has a first code unit, or a multiline pattern that -matches only at "line start", there is no point in seeking a list of starting -code units. */ - -if ((re->flags & (PCRE2_FIRSTSET|PCRE2_STARTLINE)) == 0) - { - int depth = 0; - int rc = set_start_bits(re, code, utf, ucp, &depth); - if (rc == SSB_UNKNOWN) return 1; - - /* If a list of starting code units was set up, scan the list to see if only - one or two were listed. Having only one listed is rare because usually a - single starting code unit will have been recognized and PCRE2_FIRSTSET set. - If two are listed, see if they are caseless versions of the same character; - if so we can replace the list with a caseless first code unit. This gives - better performance and is plausibly worth doing for patterns such as [Ww]ord - or (word|WORD). */ - - if (rc == SSB_DONE) - { - int i; - int a = -1; - int b = -1; - uint8_t *p = re->start_bitmap; - uint32_t flags = PCRE2_FIRSTMAPSET; - - for (i = 0; i < 256; p++, i += 8) - { - uint8_t x = *p; - if (x != 0) - { - int c; - uint8_t y = x & (~x + 1); /* Least significant bit */ - if (y != x) goto DONE; /* More than one bit set */ - - /* In the 16-bit and 32-bit libraries, the bit for 0xff means "0xff and - all wide characters", so we cannot use it here. */ - -#if PCRE2_CODE_UNIT_WIDTH != 8 - if (i == 248 && x == 0x80) goto DONE; -#endif - - /* Compute the character value */ - - c = i; - switch (x) - { - case 1: break; - case 2: c += 1; break; case 4: c += 2; break; - case 8: c += 3; break; case 16: c += 4; break; - case 32: c += 5; break; case 64: c += 6; break; - case 128: c += 7; break; - } - - /* c contains the code unit value, in the range 0-255. In 8-bit UTF - mode, only values < 128 can be used. In all the other cases, c is a - character value. */ - -#if PCRE2_CODE_UNIT_WIDTH == 8 - if (utf && c > 127) goto DONE; -#endif - if (a < 0) a = c; /* First one found, save in a */ - else if (b < 0) /* Second one found */ - { - int d = TABLE_GET((unsigned int)c, re->tables + fcc_offset, c); - -#ifdef SUPPORT_UNICODE - if (utf || ucp) - { - if (UCD_CASESET(c) != 0) goto DONE; /* Multiple case set */ - if (c > 127) d = UCD_OTHERCASE(c); - } -#endif /* SUPPORT_UNICODE */ - - if (d != a) goto DONE; /* Not the other case of a */ - b = c; /* Save second in b */ - } - else goto DONE; /* More than two characters found */ - } - } - - /* Replace the start code unit bits with a first code unit, but only if it - is not the same as a required later code unit. This is because a search for - a required code unit starts after an explicit first code unit, but at a - code unit found from the bitmap. Patterns such as /a*a/ don't work - if both the start unit and required unit are the same. */ - - if (a >= 0 && - ( - (re->flags & PCRE2_LASTSET) == 0 || - ( - re->last_codeunit != (uint32_t)a && - (b < 0 || re->last_codeunit != (uint32_t)b) - ) - )) - { - re->first_codeunit = a; - flags = PCRE2_FIRSTSET; - if (b >= 0) flags |= PCRE2_FIRSTCASELESS; - } - - DONE: - re->flags |= flags; - } - } - -/* Find the minimum length of subject string. If the pattern can match an empty -string, the minimum length is already known. If the pattern contains (*ACCEPT) -all bets are off, and we don't even try to find a minimum length. If there are -more back references than the size of the vector we are going to cache them in, -do nothing. A pattern that complicated will probably take a long time to -analyze and may in any case turn out to be too complicated. Note that back -reference minima are held as 16-bit numbers. */ - -if ((re->flags & (PCRE2_MATCH_EMPTY|PCRE2_HASACCEPT)) == 0 && - re->top_backref <= MAX_CACHE_BACKREF) - { - int min; - int backref_cache[MAX_CACHE_BACKREF+1]; - backref_cache[0] = 0; /* Highest one that is set */ - min = find_minlength(re, code, code, utf, NULL, &count, backref_cache); - switch(min) - { - case -1: /* \C in UTF mode or over-complex regex */ - break; /* Leave minlength unchanged (will be zero) */ - - case -2: - return 2; /* missing capturing bracket */ - - case -3: - return 3; /* unrecognized opcode */ - - default: - re->minlength = (min > UINT16_MAX)? UINT16_MAX : min; - break; - } - } - -return 0; -} - -/* End of pcre2_study.c */ diff --git a/modules/regex/pcre2/src/pcre2_substitute.c b/modules/regex/pcre2/src/pcre2_substitute.c deleted file mode 100644 index edbb78c..0000000 --- a/modules/regex/pcre2/src/pcre2_substitute.c +++ /dev/null @@ -1,1009 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -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-2022 University of Cambridge - ------------------------------------------------------------------------------ -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 OWNER 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. ------------------------------------------------------------------------------ -*/ - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "pcre2_internal.h" - -#define PTR_STACK_SIZE 20 - -#define SUBSTITUTE_OPTIONS \ - (PCRE2_SUBSTITUTE_EXTENDED|PCRE2_SUBSTITUTE_GLOBAL| \ - PCRE2_SUBSTITUTE_LITERAL|PCRE2_SUBSTITUTE_MATCHED| \ - PCRE2_SUBSTITUTE_OVERFLOW_LENGTH|PCRE2_SUBSTITUTE_REPLACEMENT_ONLY| \ - PCRE2_SUBSTITUTE_UNKNOWN_UNSET|PCRE2_SUBSTITUTE_UNSET_EMPTY) - - - -/************************************************* -* Find end of substitute text * -*************************************************/ - -/* In extended mode, we recognize ${name:+set text:unset text} and similar -constructions. This requires the identification of unescaped : and } -characters. This function scans for such. It must deal with nested ${ -constructions. The pointer to the text is updated, either to the required end -character, or to where an error was detected. - -Arguments: - code points to the compiled expression (for options) - ptrptr points to the pointer to the start of the text (updated) - ptrend end of the whole string - last TRUE if the last expected string (only } recognized) - -Returns: 0 on success - negative error code on failure -*/ - -static int -find_text_end(const pcre2_code *code, PCRE2_SPTR *ptrptr, PCRE2_SPTR ptrend, - BOOL last) -{ -int rc = 0; -uint32_t nestlevel = 0; -BOOL literal = FALSE; -PCRE2_SPTR ptr = *ptrptr; - -for (; ptr < ptrend; ptr++) - { - if (literal) - { - if (ptr[0] == CHAR_BACKSLASH && ptr < ptrend - 1 && ptr[1] == CHAR_E) - { - literal = FALSE; - ptr += 1; - } - } - - else if (*ptr == CHAR_RIGHT_CURLY_BRACKET) - { - if (nestlevel == 0) goto EXIT; - nestlevel--; - } - - else if (*ptr == CHAR_COLON && !last && nestlevel == 0) goto EXIT; - - else if (*ptr == CHAR_DOLLAR_SIGN) - { - if (ptr < ptrend - 1 && ptr[1] == CHAR_LEFT_CURLY_BRACKET) - { - nestlevel++; - ptr += 1; - } - } - - else if (*ptr == CHAR_BACKSLASH) - { - int erc; - int errorcode; - uint32_t ch; - - if (ptr < ptrend - 1) switch (ptr[1]) - { - case CHAR_L: - case CHAR_l: - case CHAR_U: - case CHAR_u: - ptr += 1; - continue; - } - - ptr += 1; /* Must point after \ */ - erc = PRIV(check_escape)(&ptr, ptrend, &ch, &errorcode, - code->overall_options, code->extra_options, FALSE, NULL); - ptr -= 1; /* Back to last code unit of escape */ - if (errorcode != 0) - { - rc = errorcode; - goto EXIT; - } - - switch(erc) - { - case 0: /* Data character */ - case ESC_E: /* Isolated \E is ignored */ - break; - - case ESC_Q: - literal = TRUE; - break; - - default: - rc = PCRE2_ERROR_BADREPESCAPE; - goto EXIT; - } - } - } - -rc = PCRE2_ERROR_REPMISSINGBRACE; /* Terminator not found */ - -EXIT: -*ptrptr = ptr; -return rc; -} - - - -/************************************************* -* Match and substitute * -*************************************************/ - -/* This function applies a compiled re to a subject string and creates a new -string with substitutions. The first 7 arguments are the same as for -pcre2_match(). Either string length may be PCRE2_ZERO_TERMINATED. - -Arguments: - code points to the compiled expression - subject points to the subject string - length length of subject string (may contain binary zeros) - start_offset where to start in the subject string - options option bits - match_data points to a match_data block, or is NULL - context points a PCRE2 context - replacement points to the replacement string - rlength length of replacement string - buffer where to put the substituted string - blength points to length of buffer; updated to length of string - -Returns: >= 0 number of substitutions made - < 0 an error code - PCRE2_ERROR_BADREPLACEMENT means invalid use of $ -*/ - -/* This macro checks for space in the buffer before copying into it. On -overflow, either give an error immediately, or keep on, accumulating the -length. */ - -#define CHECKMEMCPY(from,length) \ - { \ - if (!overflowed && lengthleft < length) \ - { \ - if ((suboptions & PCRE2_SUBSTITUTE_OVERFLOW_LENGTH) == 0) goto NOROOM; \ - overflowed = TRUE; \ - extra_needed = length - lengthleft; \ - } \ - else if (overflowed) \ - { \ - extra_needed += length; \ - } \ - else \ - { \ - memcpy(buffer + buff_offset, from, CU2BYTES(length)); \ - buff_offset += length; \ - lengthleft -= length; \ - } \ - } - -/* Here's the function */ - -PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION -pcre2_substitute(const pcre2_code *code, PCRE2_SPTR subject, PCRE2_SIZE length, - PCRE2_SIZE start_offset, uint32_t options, pcre2_match_data *match_data, - pcre2_match_context *mcontext, PCRE2_SPTR replacement, PCRE2_SIZE rlength, - PCRE2_UCHAR *buffer, PCRE2_SIZE *blength) -{ -int rc; -int subs; -int forcecase = 0; -int forcecasereset = 0; -uint32_t ovector_count; -uint32_t goptions = 0; -uint32_t suboptions; -pcre2_match_data *internal_match_data = NULL; -BOOL escaped_literal = FALSE; -BOOL overflowed = FALSE; -BOOL use_existing_match; -BOOL replacement_only; -#ifdef SUPPORT_UNICODE -BOOL utf = (code->overall_options & PCRE2_UTF) != 0; -BOOL ucp = (code->overall_options & PCRE2_UCP) != 0; -#endif -PCRE2_UCHAR temp[6]; -PCRE2_SPTR ptr; -PCRE2_SPTR repend; -PCRE2_SIZE extra_needed = 0; -PCRE2_SIZE buff_offset, buff_length, lengthleft, fraglength; -PCRE2_SIZE *ovector; -PCRE2_SIZE ovecsave[3]; -pcre2_substitute_callout_block scb; - -/* General initialization */ - -buff_offset = 0; -lengthleft = buff_length = *blength; -*blength = PCRE2_UNSET; -ovecsave[0] = ovecsave[1] = ovecsave[2] = PCRE2_UNSET; - -/* Partial matching is not valid. This must come after setting *blength to -PCRE2_UNSET, so as not to imply an offset in the replacement. */ - -if ((options & (PCRE2_PARTIAL_HARD|PCRE2_PARTIAL_SOFT)) != 0) - return PCRE2_ERROR_BADOPTION; - -/* Validate length and find the end of the replacement. A NULL replacement of -zero length is interpreted as an empty string. */ - -if (replacement == NULL) - { - if (rlength != 0) return PCRE2_ERROR_NULL; - replacement = (PCRE2_SPTR)""; - } - -if (rlength == PCRE2_ZERO_TERMINATED) rlength = PRIV(strlen)(replacement); -repend = replacement + rlength; - -/* Check for using a match that has already happened. Note that the subject -pointer in the match data may be NULL after a no-match. */ - -use_existing_match = ((options & PCRE2_SUBSTITUTE_MATCHED) != 0); -replacement_only = ((options & PCRE2_SUBSTITUTE_REPLACEMENT_ONLY) != 0); - -/* If starting from an existing match, there must be an externally provided -match data block. We create an internal match_data block in two cases: (a) an -external one is not supplied (and we are not starting from an existing match); -(b) an existing match is to be used for the first substitution. In the latter -case, we copy the existing match into the internal block, except for any cached -heap frame size and pointer. This ensures that no changes are made to the -external match data block. */ - -if (match_data == NULL) - { - pcre2_general_context *gcontext; - if (use_existing_match) return PCRE2_ERROR_NULL; - gcontext = (mcontext == NULL)? - (pcre2_general_context *)code : - (pcre2_general_context *)mcontext; - match_data = internal_match_data = - pcre2_match_data_create_from_pattern(code, gcontext); - if (internal_match_data == NULL) return PCRE2_ERROR_NOMEMORY; - } - -else if (use_existing_match) - { - pcre2_general_context *gcontext = (mcontext == NULL)? - (pcre2_general_context *)code : - (pcre2_general_context *)mcontext; - int pairs = (code->top_bracket + 1 < match_data->oveccount)? - code->top_bracket + 1 : match_data->oveccount; - internal_match_data = pcre2_match_data_create(match_data->oveccount, - gcontext); - if (internal_match_data == NULL) return PCRE2_ERROR_NOMEMORY; - memcpy(internal_match_data, match_data, offsetof(pcre2_match_data, ovector) - + 2*pairs*sizeof(PCRE2_SIZE)); - internal_match_data->heapframes = NULL; - internal_match_data->heapframes_size = 0; - match_data = internal_match_data; - } - -/* Remember ovector details */ - -ovector = pcre2_get_ovector_pointer(match_data); -ovector_count = pcre2_get_ovector_count(match_data); - -/* Fixed things in the callout block */ - -scb.version = 0; -scb.input = subject; -scb.output = (PCRE2_SPTR)buffer; -scb.ovector = ovector; - -/* A NULL subject of zero length is treated as an empty string. */ - -if (subject == NULL) - { - if (length != 0) return PCRE2_ERROR_NULL; - subject = (PCRE2_SPTR)""; - } - -/* Find length of zero-terminated subject */ - -if (length == PCRE2_ZERO_TERMINATED) - length = subject? PRIV(strlen)(subject) : 0; - -/* Check UTF replacement string if necessary. */ - -#ifdef SUPPORT_UNICODE -if (utf && (options & PCRE2_NO_UTF_CHECK) == 0) - { - rc = PRIV(valid_utf)(replacement, rlength, &(match_data->startchar)); - if (rc != 0) - { - match_data->leftchar = 0; - goto EXIT; - } - } -#endif /* SUPPORT_UNICODE */ - -/* Save the substitute options and remove them from the match options. */ - -suboptions = options & SUBSTITUTE_OPTIONS; -options &= ~SUBSTITUTE_OPTIONS; - -/* Error if the start match offset is greater than the length of the subject. */ - -if (start_offset > length) - { - match_data->leftchar = 0; - rc = PCRE2_ERROR_BADOFFSET; - goto EXIT; - } - -/* Copy up to the start offset, unless only the replacement is required. */ - -if (!replacement_only) CHECKMEMCPY(subject, start_offset); - -/* Loop for global substituting. If PCRE2_SUBSTITUTE_MATCHED is set, the first -match is taken from the match_data that was passed in. */ - -subs = 0; -do - { - PCRE2_SPTR ptrstack[PTR_STACK_SIZE]; - uint32_t ptrstackptr = 0; - - if (use_existing_match) - { - rc = match_data->rc; - use_existing_match = FALSE; - } - else rc = pcre2_match(code, subject, length, start_offset, options|goptions, - match_data, mcontext); - -#ifdef SUPPORT_UNICODE - if (utf) options |= PCRE2_NO_UTF_CHECK; /* Only need to check once */ -#endif - - /* Any error other than no match returns the error code. No match when not - doing the special after-empty-match global rematch, or when at the end of the - subject, breaks the global loop. Otherwise, advance the starting point by one - character, copying it to the output, and try again. */ - - if (rc < 0) - { - PCRE2_SIZE save_start; - - if (rc != PCRE2_ERROR_NOMATCH) goto EXIT; - if (goptions == 0 || start_offset >= length) break; - - /* Advance by one code point. Then, if CRLF is a valid newline sequence and - we have advanced into the middle of it, advance one more code point. In - other words, do not start in the middle of CRLF, even if CR and LF on their - own are valid newlines. */ - - save_start = start_offset++; - if (subject[start_offset-1] == CHAR_CR && - code->newline_convention != PCRE2_NEWLINE_CR && - code->newline_convention != PCRE2_NEWLINE_LF && - start_offset < length && - subject[start_offset] == CHAR_LF) - start_offset++; - - /* Otherwise, in UTF mode, advance past any secondary code points. */ - - else if ((code->overall_options & PCRE2_UTF) != 0) - { -#if PCRE2_CODE_UNIT_WIDTH == 8 - while (start_offset < length && (subject[start_offset] & 0xc0) == 0x80) - start_offset++; -#elif PCRE2_CODE_UNIT_WIDTH == 16 - while (start_offset < length && - (subject[start_offset] & 0xfc00) == 0xdc00) - start_offset++; -#endif - } - - /* Copy what we have advanced past (unless not required), reset the special - global options, and continue to the next match. */ - - fraglength = start_offset - save_start; - if (!replacement_only) CHECKMEMCPY(subject + save_start, fraglength); - goptions = 0; - continue; - } - - /* Handle a successful match. Matches that use \K to end before they start - or start before the current point in the subject are not supported. */ - - if (ovector[1] < ovector[0] || ovector[0] < start_offset) - { - rc = PCRE2_ERROR_BADSUBSPATTERN; - goto EXIT; - } - - /* Check for the same match as previous. This is legitimate after matching an - empty string that starts after the initial match offset. We have tried again - at the match point in case the pattern is one like /(?<=\G.)/ which can never - match at its starting point, so running the match achieves the bumpalong. If - we do get the same (null) match at the original match point, it isn't such a - pattern, so we now do the empty string magic. In all other cases, a repeat - match should never occur. */ - - if (ovecsave[0] == ovector[0] && ovecsave[1] == ovector[1]) - { - if (ovector[0] == ovector[1] && ovecsave[2] != start_offset) - { - goptions = PCRE2_NOTEMPTY_ATSTART | PCRE2_ANCHORED; - ovecsave[2] = start_offset; - continue; /* Back to the top of the loop */ - } - rc = PCRE2_ERROR_INTERNAL_DUPMATCH; - goto EXIT; - } - - /* Count substitutions with a paranoid check for integer overflow; surely no - real call to this function would ever hit this! */ - - if (subs == INT_MAX) - { - rc = PCRE2_ERROR_TOOMANYREPLACE; - goto EXIT; - } - subs++; - - /* Copy the text leading up to the match (unless not required), and remember - where the insert begins and how many ovector pairs are set. */ - - if (rc == 0) rc = ovector_count; - fraglength = ovector[0] - start_offset; - if (!replacement_only) CHECKMEMCPY(subject + start_offset, fraglength); - scb.output_offsets[0] = buff_offset; - scb.oveccount = rc; - - /* Process the replacement string. If the entire replacement is literal, just - copy it with length check. */ - - ptr = replacement; - if ((suboptions & PCRE2_SUBSTITUTE_LITERAL) != 0) - { - CHECKMEMCPY(ptr, rlength); - } - - /* Within a non-literal replacement, which must be scanned character by - character, local literal mode can be set by \Q, but only in extended mode - when backslashes are being interpreted. In extended mode we must handle - nested substrings that are to be reprocessed. */ - - else for (;;) - { - uint32_t ch; - unsigned int chlen; - - /* If at the end of a nested substring, pop the stack. */ - - if (ptr >= repend) - { - if (ptrstackptr == 0) break; /* End of replacement string */ - repend = ptrstack[--ptrstackptr]; - ptr = ptrstack[--ptrstackptr]; - continue; - } - - /* Handle the next character */ - - if (escaped_literal) - { - if (ptr[0] == CHAR_BACKSLASH && ptr < repend - 1 && ptr[1] == CHAR_E) - { - escaped_literal = FALSE; - ptr += 2; - continue; - } - goto LOADLITERAL; - } - - /* Not in literal mode. */ - - if (*ptr == CHAR_DOLLAR_SIGN) - { - int group, n; - uint32_t special = 0; - BOOL inparens; - BOOL star; - PCRE2_SIZE sublength; - PCRE2_SPTR text1_start = NULL; - PCRE2_SPTR text1_end = NULL; - PCRE2_SPTR text2_start = NULL; - PCRE2_SPTR text2_end = NULL; - PCRE2_UCHAR next; - PCRE2_UCHAR name[33]; - - if (++ptr >= repend) goto BAD; - if ((next = *ptr) == CHAR_DOLLAR_SIGN) goto LOADLITERAL; - - group = -1; - n = 0; - inparens = FALSE; - star = FALSE; - - if (next == CHAR_LEFT_CURLY_BRACKET) - { - if (++ptr >= repend) goto BAD; - next = *ptr; - inparens = TRUE; - } - - if (next == CHAR_ASTERISK) - { - if (++ptr >= repend) goto BAD; - next = *ptr; - star = TRUE; - } - - if (!star && next >= CHAR_0 && next <= CHAR_9) - { - group = next - CHAR_0; - while (++ptr < repend) - { - next = *ptr; - if (next < CHAR_0 || next > CHAR_9) break; - group = group * 10 + next - CHAR_0; - - /* A check for a number greater than the hightest captured group - is sufficient here; no need for a separate overflow check. If unknown - groups are to be treated as unset, just skip over any remaining - digits and carry on. */ - - if (group > code->top_bracket) - { - if ((suboptions & PCRE2_SUBSTITUTE_UNKNOWN_UNSET) != 0) - { - while (++ptr < repend && *ptr >= CHAR_0 && *ptr <= CHAR_9); - break; - } - else - { - rc = PCRE2_ERROR_NOSUBSTRING; - goto PTREXIT; - } - } - } - } - else - { - const uint8_t *ctypes = code->tables + ctypes_offset; - while (MAX_255(next) && (ctypes[next] & ctype_word) != 0) - { - name[n++] = next; - if (n > 32) goto BAD; - if (++ptr >= repend) break; - next = *ptr; - } - if (n == 0) goto BAD; - name[n] = 0; - } - - /* In extended mode we recognize ${name:+set text:unset text} and - ${name:-default text}. */ - - if (inparens) - { - if ((suboptions & PCRE2_SUBSTITUTE_EXTENDED) != 0 && - !star && ptr < repend - 2 && next == CHAR_COLON) - { - special = *(++ptr); - if (special != CHAR_PLUS && special != CHAR_MINUS) - { - rc = PCRE2_ERROR_BADSUBSTITUTION; - goto PTREXIT; - } - - text1_start = ++ptr; - rc = find_text_end(code, &ptr, repend, special == CHAR_MINUS); - if (rc != 0) goto PTREXIT; - text1_end = ptr; - - if (special == CHAR_PLUS && *ptr == CHAR_COLON) - { - text2_start = ++ptr; - rc = find_text_end(code, &ptr, repend, TRUE); - if (rc != 0) goto PTREXIT; - text2_end = ptr; - } - } - - else - { - if (ptr >= repend || *ptr != CHAR_RIGHT_CURLY_BRACKET) - { - rc = PCRE2_ERROR_REPMISSINGBRACE; - goto PTREXIT; - } - } - - ptr++; - } - - /* Have found a syntactically correct group number or name, or *name. - Only *MARK is currently recognized. */ - - if (star) - { - if (PRIV(strcmp_c8)(name, STRING_MARK) == 0) - { - PCRE2_SPTR mark = pcre2_get_mark(match_data); - if (mark != NULL) - { - PCRE2_SPTR mark_start = mark; - while (*mark != 0) mark++; - fraglength = mark - mark_start; - CHECKMEMCPY(mark_start, fraglength); - } - } - else goto BAD; - } - - /* Substitute the contents of a group. We don't use substring_copy - functions any more, in order to support case forcing. */ - - else - { - PCRE2_SPTR subptr, subptrend; - - /* Find a number for a named group. In case there are duplicate names, - search for the first one that is set. If the name is not found when - PCRE2_SUBSTITUTE_UNKNOWN_EMPTY is set, set the group number to a - non-existent group. */ - - if (group < 0) - { - PCRE2_SPTR first, last, entry; - rc = pcre2_substring_nametable_scan(code, name, &first, &last); - if (rc == PCRE2_ERROR_NOSUBSTRING && - (suboptions & PCRE2_SUBSTITUTE_UNKNOWN_UNSET) != 0) - { - group = code->top_bracket + 1; - } - else - { - if (rc < 0) goto PTREXIT; - for (entry = first; entry <= last; entry += rc) - { - uint32_t ng = GET2(entry, 0); - if (ng < ovector_count) - { - if (group < 0) group = ng; /* First in ovector */ - if (ovector[ng*2] != PCRE2_UNSET) - { - group = ng; /* First that is set */ - break; - } - } - } - - /* If group is still negative, it means we did not find a group - that is in the ovector. Just set the first group. */ - - if (group < 0) group = GET2(first, 0); - } - } - - /* We now have a group that is identified by number. Find the length of - the captured string. If a group in a non-special substitution is unset - when PCRE2_SUBSTITUTE_UNSET_EMPTY is set, substitute nothing. */ - - rc = pcre2_substring_length_bynumber(match_data, group, &sublength); - if (rc < 0) - { - if (rc == PCRE2_ERROR_NOSUBSTRING && - (suboptions & PCRE2_SUBSTITUTE_UNKNOWN_UNSET) != 0) - { - rc = PCRE2_ERROR_UNSET; - } - if (rc != PCRE2_ERROR_UNSET) goto PTREXIT; /* Non-unset errors */ - if (special == 0) /* Plain substitution */ - { - if ((suboptions & PCRE2_SUBSTITUTE_UNSET_EMPTY) != 0) continue; - goto PTREXIT; /* Else error */ - } - } - - /* If special is '+' we have a 'set' and possibly an 'unset' text, - both of which are reprocessed when used. If special is '-' we have a - default text for when the group is unset; it must be reprocessed. */ - - if (special != 0) - { - if (special == CHAR_MINUS) - { - if (rc == 0) goto LITERAL_SUBSTITUTE; - text2_start = text1_start; - text2_end = text1_end; - } - - if (ptrstackptr >= PTR_STACK_SIZE) goto BAD; - ptrstack[ptrstackptr++] = ptr; - ptrstack[ptrstackptr++] = repend; - - if (rc == 0) - { - ptr = text1_start; - repend = text1_end; - } - else - { - ptr = text2_start; - repend = text2_end; - } - continue; - } - - /* Otherwise we have a literal substitution of a group's contents. */ - - LITERAL_SUBSTITUTE: - subptr = subject + ovector[group*2]; - subptrend = subject + ovector[group*2 + 1]; - - /* Substitute a literal string, possibly forcing alphabetic case. */ - - while (subptr < subptrend) - { - GETCHARINCTEST(ch, subptr); - if (forcecase != 0) - { -#ifdef SUPPORT_UNICODE - if (utf || ucp) - { - uint32_t type = UCD_CHARTYPE(ch); - if (PRIV(ucp_gentype)[type] == ucp_L && - type != ((forcecase > 0)? ucp_Lu : ucp_Ll)) - ch = UCD_OTHERCASE(ch); - } - else -#endif - { - if (((code->tables + cbits_offset + - ((forcecase > 0)? cbit_upper:cbit_lower) - )[ch/8] & (1u << (ch%8))) == 0) - ch = (code->tables + fcc_offset)[ch]; - } - forcecase = forcecasereset; - } - -#ifdef SUPPORT_UNICODE - if (utf) chlen = PRIV(ord2utf)(ch, temp); else -#endif - { - temp[0] = ch; - chlen = 1; - } - CHECKMEMCPY(temp, chlen); - } - } - } - - /* Handle an escape sequence in extended mode. We can use check_escape() - to process \Q, \E, \c, \o, \x and \ followed by non-alphanumerics, but - the case-forcing escapes are not supported in pcre2_compile() so must be - recognized here. */ - - else if ((suboptions & PCRE2_SUBSTITUTE_EXTENDED) != 0 && - *ptr == CHAR_BACKSLASH) - { - int errorcode; - - if (ptr < repend - 1) switch (ptr[1]) - { - case CHAR_L: - forcecase = forcecasereset = -1; - ptr += 2; - continue; - - case CHAR_l: - forcecase = -1; - forcecasereset = 0; - ptr += 2; - continue; - - case CHAR_U: - forcecase = forcecasereset = 1; - ptr += 2; - continue; - - case CHAR_u: - forcecase = 1; - forcecasereset = 0; - ptr += 2; - continue; - - default: - break; - } - - ptr++; /* Point after \ */ - rc = PRIV(check_escape)(&ptr, repend, &ch, &errorcode, - code->overall_options, code->extra_options, FALSE, NULL); - if (errorcode != 0) goto BADESCAPE; - - switch(rc) - { - case ESC_E: - forcecase = forcecasereset = 0; - continue; - - case ESC_Q: - escaped_literal = TRUE; - continue; - - case 0: /* Data character */ - goto LITERAL; - - default: - goto BADESCAPE; - } - } - - /* Handle a literal code unit */ - - else - { - LOADLITERAL: - GETCHARINCTEST(ch, ptr); /* Get character value, increment pointer */ - - LITERAL: - if (forcecase != 0) - { -#ifdef SUPPORT_UNICODE - if (utf || ucp) - { - uint32_t type = UCD_CHARTYPE(ch); - if (PRIV(ucp_gentype)[type] == ucp_L && - type != ((forcecase > 0)? ucp_Lu : ucp_Ll)) - ch = UCD_OTHERCASE(ch); - } - else -#endif - { - if (((code->tables + cbits_offset + - ((forcecase > 0)? cbit_upper:cbit_lower) - )[ch/8] & (1u << (ch%8))) == 0) - ch = (code->tables + fcc_offset)[ch]; - } - forcecase = forcecasereset; - } - -#ifdef SUPPORT_UNICODE - if (utf) chlen = PRIV(ord2utf)(ch, temp); else -#endif - { - temp[0] = ch; - chlen = 1; - } - CHECKMEMCPY(temp, chlen); - } /* End handling a literal code unit */ - } /* End of loop for scanning the replacement. */ - - /* The replacement has been copied to the output, or its size has been - remembered. Do the callout if there is one and we have done an actual - replacement. */ - - if (!overflowed && mcontext != NULL && mcontext->substitute_callout != NULL) - { - scb.subscount = subs; - scb.output_offsets[1] = buff_offset; - rc = mcontext->substitute_callout(&scb, mcontext->substitute_callout_data); - - /* A non-zero return means cancel this substitution. Instead, copy the - matched string fragment. */ - - if (rc != 0) - { - PCRE2_SIZE newlength = scb.output_offsets[1] - scb.output_offsets[0]; - PCRE2_SIZE oldlength = ovector[1] - ovector[0]; - - buff_offset -= newlength; - lengthleft += newlength; - if (!replacement_only) CHECKMEMCPY(subject + ovector[0], oldlength); - - /* A negative return means do not do any more. */ - - if (rc < 0) suboptions &= (~PCRE2_SUBSTITUTE_GLOBAL); - } - } - - /* Save the details of this match. See above for how this data is used. If we - matched an empty string, do the magic for global matches. Update the start - offset to point to the rest of the subject string. If we re-used an existing - match for the first match, switch to the internal match data block. */ - - ovecsave[0] = ovector[0]; - ovecsave[1] = ovector[1]; - ovecsave[2] = start_offset; - - goptions = (ovector[0] != ovector[1] || ovector[0] > start_offset)? 0 : - PCRE2_ANCHORED|PCRE2_NOTEMPTY_ATSTART; - start_offset = ovector[1]; - } while ((suboptions & PCRE2_SUBSTITUTE_GLOBAL) != 0); /* Repeat "do" loop */ - -/* Copy the rest of the subject unless not required, and terminate the output -with a binary zero. */ - -if (!replacement_only) - { - fraglength = length - start_offset; - CHECKMEMCPY(subject + start_offset, fraglength); - } - -temp[0] = 0; -CHECKMEMCPY(temp, 1); - -/* If overflowed is set it means the PCRE2_SUBSTITUTE_OVERFLOW_LENGTH is set, -and matching has carried on after a full buffer, in order to compute the length -needed. Otherwise, an overflow generates an immediate error return. */ - -if (overflowed) - { - rc = PCRE2_ERROR_NOMEMORY; - *blength = buff_length + extra_needed; - } - -/* After a successful execution, return the number of substitutions and set the -length of buffer used, excluding the trailing zero. */ - -else - { - rc = subs; - *blength = buff_offset - 1; - } - -EXIT: -if (internal_match_data != NULL) pcre2_match_data_free(internal_match_data); - else match_data->rc = rc; -return rc; - -NOROOM: -rc = PCRE2_ERROR_NOMEMORY; -goto EXIT; - -BAD: -rc = PCRE2_ERROR_BADREPLACEMENT; -goto PTREXIT; - -BADESCAPE: -rc = PCRE2_ERROR_BADREPESCAPE; - -PTREXIT: -*blength = (PCRE2_SIZE)(ptr - replacement); -goto EXIT; -} - -/* End of pcre2_substitute.c */ diff --git a/modules/regex/pcre2/src/pcre2_substring.c b/modules/regex/pcre2/src/pcre2_substring.c deleted file mode 100644 index ddf5774..0000000 --- a/modules/regex/pcre2/src/pcre2_substring.c +++ /dev/null @@ -1,547 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -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-2018 University of Cambridge - ------------------------------------------------------------------------------ -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 OWNER 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. ------------------------------------------------------------------------------ -*/ - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "pcre2_internal.h" - - - -/************************************************* -* Copy named captured string to given buffer * -*************************************************/ - -/* This function copies a single captured substring into a given buffer, -identifying it by name. If the regex permits duplicate names, the first -substring that is set is chosen. - -Arguments: - match_data points to the match data - stringname the name of the required substring - buffer where to put the substring - sizeptr the size of the buffer, updated to the size of the substring - -Returns: if successful: zero - if not successful, a negative error code: - (1) an error from nametable_scan() - (2) an error from copy_bynumber() - (3) PCRE2_ERROR_UNAVAILABLE: no group is in ovector - (4) PCRE2_ERROR_UNSET: all named groups in ovector are unset -*/ - -PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION -pcre2_substring_copy_byname(pcre2_match_data *match_data, PCRE2_SPTR stringname, - PCRE2_UCHAR *buffer, PCRE2_SIZE *sizeptr) -{ -PCRE2_SPTR first, last, entry; -int failrc, entrysize; -if (match_data->matchedby == PCRE2_MATCHEDBY_DFA_INTERPRETER) - return PCRE2_ERROR_DFA_UFUNC; -entrysize = pcre2_substring_nametable_scan(match_data->code, stringname, - &first, &last); -if (entrysize < 0) return entrysize; -failrc = PCRE2_ERROR_UNAVAILABLE; -for (entry = first; entry <= last; entry += entrysize) - { - uint32_t n = GET2(entry, 0); - if (n < match_data->oveccount) - { - if (match_data->ovector[n*2] != PCRE2_UNSET) - return pcre2_substring_copy_bynumber(match_data, n, buffer, sizeptr); - failrc = PCRE2_ERROR_UNSET; - } - } -return failrc; -} - - - -/************************************************* -* Copy numbered captured string to given buffer * -*************************************************/ - -/* This function copies a single captured substring into a given buffer, -identifying it by number. - -Arguments: - match_data points to the match data - stringnumber the number of the required substring - buffer where to put the substring - sizeptr the size of the buffer, updated to the size of the substring - -Returns: if successful: 0 - if not successful, a negative error code: - PCRE2_ERROR_NOMEMORY: buffer too small - PCRE2_ERROR_NOSUBSTRING: no such substring - PCRE2_ERROR_UNAVAILABLE: ovector too small - PCRE2_ERROR_UNSET: substring is not set -*/ - -PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION -pcre2_substring_copy_bynumber(pcre2_match_data *match_data, - uint32_t stringnumber, PCRE2_UCHAR *buffer, PCRE2_SIZE *sizeptr) -{ -int rc; -PCRE2_SIZE size; -rc = pcre2_substring_length_bynumber(match_data, stringnumber, &size); -if (rc < 0) return rc; -if (size + 1 > *sizeptr) return PCRE2_ERROR_NOMEMORY; -memcpy(buffer, match_data->subject + match_data->ovector[stringnumber*2], - CU2BYTES(size)); -buffer[size] = 0; -*sizeptr = size; -return 0; -} - - - -/************************************************* -* Extract named captured string * -*************************************************/ - -/* This function copies a single captured substring, identified by name, into -new memory. If the regex permits duplicate names, the first substring that is -set is chosen. - -Arguments: - match_data pointer to match_data - stringname the name of the required substring - stringptr where to put the pointer to the new memory - sizeptr where to put the length of the substring - -Returns: if successful: zero - if not successful, a negative value: - (1) an error from nametable_scan() - (2) an error from get_bynumber() - (3) PCRE2_ERROR_UNAVAILABLE: no group is in ovector - (4) PCRE2_ERROR_UNSET: all named groups in ovector are unset -*/ - -PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION -pcre2_substring_get_byname(pcre2_match_data *match_data, - PCRE2_SPTR stringname, PCRE2_UCHAR **stringptr, PCRE2_SIZE *sizeptr) -{ -PCRE2_SPTR first, last, entry; -int failrc, entrysize; -if (match_data->matchedby == PCRE2_MATCHEDBY_DFA_INTERPRETER) - return PCRE2_ERROR_DFA_UFUNC; -entrysize = pcre2_substring_nametable_scan(match_data->code, stringname, - &first, &last); -if (entrysize < 0) return entrysize; -failrc = PCRE2_ERROR_UNAVAILABLE; -for (entry = first; entry <= last; entry += entrysize) - { - uint32_t n = GET2(entry, 0); - if (n < match_data->oveccount) - { - if (match_data->ovector[n*2] != PCRE2_UNSET) - return pcre2_substring_get_bynumber(match_data, n, stringptr, sizeptr); - failrc = PCRE2_ERROR_UNSET; - } - } -return failrc; -} - - - -/************************************************* -* Extract captured string to new memory * -*************************************************/ - -/* This function copies a single captured substring into a piece of new -memory. - -Arguments: - match_data points to match data - stringnumber the number of the required substring - stringptr where to put a pointer to the new memory - sizeptr where to put the size of the substring - -Returns: if successful: 0 - if not successful, a negative error code: - PCRE2_ERROR_NOMEMORY: failed to get memory - PCRE2_ERROR_NOSUBSTRING: no such substring - PCRE2_ERROR_UNAVAILABLE: ovector too small - PCRE2_ERROR_UNSET: substring is not set -*/ - -PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION -pcre2_substring_get_bynumber(pcre2_match_data *match_data, - uint32_t stringnumber, PCRE2_UCHAR **stringptr, PCRE2_SIZE *sizeptr) -{ -int rc; -PCRE2_SIZE size; -PCRE2_UCHAR *yield; -rc = pcre2_substring_length_bynumber(match_data, stringnumber, &size); -if (rc < 0) return rc; -yield = PRIV(memctl_malloc)(sizeof(pcre2_memctl) + - (size + 1)*PCRE2_CODE_UNIT_WIDTH, (pcre2_memctl *)match_data); -if (yield == NULL) return PCRE2_ERROR_NOMEMORY; -yield = (PCRE2_UCHAR *)(((char *)yield) + sizeof(pcre2_memctl)); -memcpy(yield, match_data->subject + match_data->ovector[stringnumber*2], - CU2BYTES(size)); -yield[size] = 0; -*stringptr = yield; -*sizeptr = size; -return 0; -} - - - -/************************************************* -* Free memory obtained by get_substring * -*************************************************/ - -/* -Argument: the result of a previous pcre2_substring_get_byxxx() -Returns: nothing -*/ - -PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION -pcre2_substring_free(PCRE2_UCHAR *string) -{ -if (string != NULL) - { - pcre2_memctl *memctl = (pcre2_memctl *)((char *)string - sizeof(pcre2_memctl)); - memctl->free(memctl, memctl->memory_data); - } -} - - - -/************************************************* -* Get length of a named substring * -*************************************************/ - -/* This function returns the length of a named captured substring. If the regex -permits duplicate names, the first substring that is set is chosen. - -Arguments: - match_data pointer to match data - stringname the name of the required substring - sizeptr where to put the length - -Returns: 0 if successful, else a negative error number -*/ - -PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION -pcre2_substring_length_byname(pcre2_match_data *match_data, - PCRE2_SPTR stringname, PCRE2_SIZE *sizeptr) -{ -PCRE2_SPTR first, last, entry; -int failrc, entrysize; -if (match_data->matchedby == PCRE2_MATCHEDBY_DFA_INTERPRETER) - return PCRE2_ERROR_DFA_UFUNC; -entrysize = pcre2_substring_nametable_scan(match_data->code, stringname, - &first, &last); -if (entrysize < 0) return entrysize; -failrc = PCRE2_ERROR_UNAVAILABLE; -for (entry = first; entry <= last; entry += entrysize) - { - uint32_t n = GET2(entry, 0); - if (n < match_data->oveccount) - { - if (match_data->ovector[n*2] != PCRE2_UNSET) - return pcre2_substring_length_bynumber(match_data, n, sizeptr); - failrc = PCRE2_ERROR_UNSET; - } - } -return failrc; -} - - - -/************************************************* -* Get length of a numbered substring * -*************************************************/ - -/* This function returns the length of a captured substring. If the start is -beyond the end (which can happen when \K is used in an assertion), it sets the -length to zero. - -Arguments: - match_data pointer to match data - stringnumber the number of the required substring - sizeptr where to put the length, if not NULL - -Returns: if successful: 0 - if not successful, a negative error code: - PCRE2_ERROR_NOSUBSTRING: no such substring - PCRE2_ERROR_UNAVAILABLE: ovector is too small - PCRE2_ERROR_UNSET: substring is not set -*/ - -PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION -pcre2_substring_length_bynumber(pcre2_match_data *match_data, - uint32_t stringnumber, PCRE2_SIZE *sizeptr) -{ -PCRE2_SIZE left, right; -int count = match_data->rc; -if (count == PCRE2_ERROR_PARTIAL) - { - if (stringnumber > 0) return PCRE2_ERROR_PARTIAL; - count = 0; - } -else if (count < 0) return count; /* Match failed */ - -if (match_data->matchedby != PCRE2_MATCHEDBY_DFA_INTERPRETER) - { - if (stringnumber > match_data->code->top_bracket) - return PCRE2_ERROR_NOSUBSTRING; - if (stringnumber >= match_data->oveccount) - return PCRE2_ERROR_UNAVAILABLE; - if (match_data->ovector[stringnumber*2] == PCRE2_UNSET) - return PCRE2_ERROR_UNSET; - } -else /* Matched using pcre2_dfa_match() */ - { - if (stringnumber >= match_data->oveccount) return PCRE2_ERROR_UNAVAILABLE; - if (count != 0 && stringnumber >= (uint32_t)count) return PCRE2_ERROR_UNSET; - } - -left = match_data->ovector[stringnumber*2]; -right = match_data->ovector[stringnumber*2+1]; -if (sizeptr != NULL) *sizeptr = (left > right)? 0 : right - left; -return 0; -} - - - -/************************************************* -* Extract all captured strings to new memory * -*************************************************/ - -/* This function gets one chunk of memory and builds a list of pointers and all -the captured substrings in it. A NULL pointer is put on the end of the list. -The substrings are zero-terminated, but also, if the final argument is -non-NULL, a list of lengths is also returned. This allows binary data to be -handled. - -Arguments: - match_data points to the match data - listptr set to point to the list of pointers - lengthsptr set to point to the list of lengths (may be NULL) - -Returns: if successful: 0 - if not successful, a negative error code: - PCRE2_ERROR_NOMEMORY: failed to get memory, - or a match failure code -*/ - -PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION -pcre2_substring_list_get(pcre2_match_data *match_data, PCRE2_UCHAR ***listptr, - PCRE2_SIZE **lengthsptr) -{ -int i, count, count2; -PCRE2_SIZE size; -PCRE2_SIZE *lensp; -pcre2_memctl *memp; -PCRE2_UCHAR **listp; -PCRE2_UCHAR *sp; -PCRE2_SIZE *ovector; - -if ((count = match_data->rc) < 0) return count; /* Match failed */ -if (count == 0) count = match_data->oveccount; /* Ovector too small */ - -count2 = 2*count; -ovector = match_data->ovector; -size = sizeof(pcre2_memctl) + sizeof(PCRE2_UCHAR *); /* For final NULL */ -if (lengthsptr != NULL) size += sizeof(PCRE2_SIZE) * count; /* For lengths */ - -for (i = 0; i < count2; i += 2) - { - size += sizeof(PCRE2_UCHAR *) + CU2BYTES(1); - if (ovector[i+1] > ovector[i]) size += CU2BYTES(ovector[i+1] - ovector[i]); - } - -memp = PRIV(memctl_malloc)(size, (pcre2_memctl *)match_data); -if (memp == NULL) return PCRE2_ERROR_NOMEMORY; - -*listptr = listp = (PCRE2_UCHAR **)((char *)memp + sizeof(pcre2_memctl)); -lensp = (PCRE2_SIZE *)((char *)listp + sizeof(PCRE2_UCHAR *) * (count + 1)); - -if (lengthsptr == NULL) - { - sp = (PCRE2_UCHAR *)lensp; - lensp = NULL; - } -else - { - *lengthsptr = lensp; - sp = (PCRE2_UCHAR *)((char *)lensp + sizeof(PCRE2_SIZE) * count); - } - -for (i = 0; i < count2; i += 2) - { - size = (ovector[i+1] > ovector[i])? (ovector[i+1] - ovector[i]) : 0; - - /* Size == 0 includes the case when the capture is unset. Avoid adding - PCRE2_UNSET to match_data->subject because it overflows, even though with - zero size calling memcpy() is harmless. */ - - if (size != 0) memcpy(sp, match_data->subject + ovector[i], CU2BYTES(size)); - *listp++ = sp; - if (lensp != NULL) *lensp++ = size; - sp += size; - *sp++ = 0; - } - -*listp = NULL; -return 0; -} - - - -/************************************************* -* Free memory obtained by substring_list_get * -*************************************************/ - -/* -Argument: the result of a previous pcre2_substring_list_get() -Returns: nothing -*/ - -PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION -pcre2_substring_list_free(PCRE2_SPTR *list) -{ -if (list != NULL) - { - pcre2_memctl *memctl = (pcre2_memctl *)((char *)list - sizeof(pcre2_memctl)); - memctl->free(memctl, memctl->memory_data); - } -} - - - -/************************************************* -* Find (multiple) entries for named string * -*************************************************/ - -/* This function scans the nametable for a given name, using binary chop. It -returns either two pointers to the entries in the table, or, if no pointers are -given, the number of a unique group with the given name. If duplicate names are -permitted, and the name is not unique, an error is generated. - -Arguments: - code the compiled regex - stringname the name whose entries required - firstptr where to put the pointer to the first entry - lastptr where to put the pointer to the last entry - -Returns: PCRE2_ERROR_NOSUBSTRING if the name is not found - otherwise, if firstptr and lastptr are NULL: - a group number for a unique substring - else PCRE2_ERROR_NOUNIQUESUBSTRING - otherwise: - the length of each entry, having set firstptr and lastptr -*/ - -PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION -pcre2_substring_nametable_scan(const pcre2_code *code, PCRE2_SPTR stringname, - PCRE2_SPTR *firstptr, PCRE2_SPTR *lastptr) -{ -uint16_t bot = 0; -uint16_t top = code->name_count; -uint16_t entrysize = code->name_entry_size; -PCRE2_SPTR nametable = (PCRE2_SPTR)((char *)code + sizeof(pcre2_real_code)); - -while (top > bot) - { - uint16_t mid = (top + bot) / 2; - PCRE2_SPTR entry = nametable + entrysize*mid; - int c = PRIV(strcmp)(stringname, entry + IMM2_SIZE); - if (c == 0) - { - PCRE2_SPTR first; - PCRE2_SPTR last; - PCRE2_SPTR lastentry; - lastentry = nametable + entrysize * (code->name_count - 1); - first = last = entry; - while (first > nametable) - { - if (PRIV(strcmp)(stringname, (first - entrysize + IMM2_SIZE)) != 0) break; - first -= entrysize; - } - while (last < lastentry) - { - if (PRIV(strcmp)(stringname, (last + entrysize + IMM2_SIZE)) != 0) break; - last += entrysize; - } - if (firstptr == NULL) return (first == last)? - (int)GET2(entry, 0) : PCRE2_ERROR_NOUNIQUESUBSTRING; - *firstptr = first; - *lastptr = last; - return entrysize; - } - if (c > 0) bot = mid + 1; else top = mid; - } - -return PCRE2_ERROR_NOSUBSTRING; -} - - -/************************************************* -* Find number for named string * -*************************************************/ - -/* This function is a convenience wrapper for pcre2_substring_nametable_scan() -when it is known that names are unique. If there are duplicate names, it is not -defined which number is returned. - -Arguments: - code the compiled regex - stringname the name whose number is required - -Returns: the number of the named parenthesis, or a negative number - PCRE2_ERROR_NOSUBSTRING if not found - PCRE2_ERROR_NOUNIQUESUBSTRING if not unique -*/ - -PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION -pcre2_substring_number_from_name(const pcre2_code *code, - PCRE2_SPTR stringname) -{ -return pcre2_substring_nametable_scan(code, stringname, NULL, NULL); -} - -/* End of pcre2_substring.c */ diff --git a/modules/regex/pcre2/src/pcre2_tables.c b/modules/regex/pcre2/src/pcre2_tables.c deleted file mode 100644 index e00252f..0000000 --- a/modules/regex/pcre2/src/pcre2_tables.c +++ /dev/null @@ -1,234 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -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 - ------------------------------------------------------------------------------ -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 OWNER 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. ------------------------------------------------------------------------------ -*/ - -/* This module contains some fixed tables that are used by more than one of the -PCRE2 code modules. The tables are also #included by the pcre2test program, -which uses macros to change their names from _pcre2_xxx to xxxx, thereby -avoiding name clashes with the library. In this case, PCRE2_PCRE2TEST is -defined. */ - -#ifndef PCRE2_PCRE2TEST /* We're compiling the library */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include "pcre2_internal.h" -#endif /* PCRE2_PCRE2TEST */ - -/* Table of sizes for the fixed-length opcodes. It's defined in a macro so that -the definition is next to the definition of the opcodes in pcre2_internal.h. -This is mode-dependent, so it is skipped when this file is included by -pcre2test. */ - -#ifndef PCRE2_PCRE2TEST -const uint8_t PRIV(OP_lengths)[] = { OP_LENGTHS }; -#endif - -/* Tables of horizontal and vertical whitespace characters, suitable for -adding to classes. */ - -const uint32_t PRIV(hspace_list)[] = { HSPACE_LIST }; -const uint32_t PRIV(vspace_list)[] = { VSPACE_LIST }; - -/* These tables are the pairs of delimiters that are valid for callout string -arguments. For each starting delimiter there must be a matching ending -delimiter, which in fact is different only for bracket-like delimiters. */ - -const uint32_t PRIV(callout_start_delims)[] = { - CHAR_GRAVE_ACCENT, CHAR_APOSTROPHE, CHAR_QUOTATION_MARK, - CHAR_CIRCUMFLEX_ACCENT, CHAR_PERCENT_SIGN, CHAR_NUMBER_SIGN, - CHAR_DOLLAR_SIGN, CHAR_LEFT_CURLY_BRACKET, 0 }; - -const uint32_t PRIV(callout_end_delims[]) = { - CHAR_GRAVE_ACCENT, CHAR_APOSTROPHE, CHAR_QUOTATION_MARK, - CHAR_CIRCUMFLEX_ACCENT, CHAR_PERCENT_SIGN, CHAR_NUMBER_SIGN, - CHAR_DOLLAR_SIGN, CHAR_RIGHT_CURLY_BRACKET, 0 }; - - -/************************************************* -* Tables for UTF-8 support * -*************************************************/ - -/* These tables are required by pcre2test in 16- or 32-bit mode, as well -as for the library in 8-bit mode, because pcre2test uses UTF-8 internally for -handling wide characters. */ - -#if defined PCRE2_PCRE2TEST || \ - (defined SUPPORT_UNICODE && \ - defined PCRE2_CODE_UNIT_WIDTH && \ - PCRE2_CODE_UNIT_WIDTH == 8) - -/* These are the breakpoints for different numbers of bytes in a UTF-8 -character. */ - -const int PRIV(utf8_table1)[] = - { 0x7f, 0x7ff, 0xffff, 0x1fffff, 0x3ffffff, 0x7fffffff}; - -const int PRIV(utf8_table1_size) = sizeof(PRIV(utf8_table1)) / sizeof(int); - -/* These are the indicator bits and the mask for the data bits to set in the -first byte of a character, indexed by the number of additional bytes. */ - -const int PRIV(utf8_table2)[] = { 0, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc}; -const int PRIV(utf8_table3)[] = { 0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01}; - -/* Table of the number of extra bytes, indexed by the first byte masked with -0x3f. The highest number for a valid UTF-8 first byte is in fact 0x3d. */ - -const uint8_t PRIV(utf8_table4)[] = { - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 }; - -#endif /* UTF-8 support needed */ - -/* Tables concerned with Unicode properties are relevant only when Unicode -support is enabled. See also the pcre2_ucptables.c file, which is generated by -a Python script from Unicode data files. */ - -#ifdef SUPPORT_UNICODE - -/* Table to translate from particular type value to the general value. */ - -const uint32_t PRIV(ucp_gentype)[] = { - ucp_C, ucp_C, ucp_C, ucp_C, ucp_C, /* Cc, Cf, Cn, Co, Cs */ - ucp_L, ucp_L, ucp_L, ucp_L, ucp_L, /* Ll, Lu, Lm, Lo, Lt */ - ucp_M, ucp_M, ucp_M, /* Mc, Me, Mn */ - ucp_N, ucp_N, ucp_N, /* Nd, Nl, No */ - ucp_P, ucp_P, ucp_P, ucp_P, ucp_P, /* Pc, Pd, Pe, Pf, Pi */ - ucp_P, ucp_P, /* Ps, Po */ - ucp_S, ucp_S, ucp_S, ucp_S, /* Sc, Sk, Sm, So */ - ucp_Z, ucp_Z, ucp_Z /* Zl, Zp, Zs */ -}; - -/* This table encodes the rules for finding the end of an extended grapheme -cluster. Every code point has a grapheme break property which is one of the -ucp_gbXX values defined in pcre2_ucp.h. These changed between Unicode versions -10 and 11. The 2-dimensional table is indexed by the properties of two adjacent -code points. The left property selects a word from the table, and the right -property selects a bit from that word like this: - - PRIV(ucp_gbtable)[left-property] & (1u << right-property) - -The value is non-zero if a grapheme break is NOT permitted between the relevant -two code points. The breaking rules are as follows: - -1. Break at the start and end of text (pretty obviously). - -2. Do not break between a CR and LF; otherwise, break before and after - controls. - -3. Do not break Hangul syllable sequences, the rules for which are: - - L may be followed by L, V, LV or LVT - LV or V may be followed by V or T - LVT or T may be followed by T - -4. Do not break before extending characters or zero-width-joiner (ZWJ). - -The following rules are only for extended grapheme clusters (but that's what we -are implementing). - -5. Do not break before SpacingMarks. - -6. Do not break after Prepend characters. - -7. 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. - -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 - before the break point. This table encodes "join RI characters"; the code - has to deal with checking for previous adjoining RIs. - -9. Otherwise, break everywhere. -*/ - -#define ESZ (1< 0x10ffff is not permitted -PCRE2_ERROR_UTF8_ERR14 3-byte character with value 0xd800-0xdfff is not permitted -PCRE2_ERROR_UTF8_ERR15 Overlong 2-byte sequence -PCRE2_ERROR_UTF8_ERR16 Overlong 3-byte sequence -PCRE2_ERROR_UTF8_ERR17 Overlong 4-byte sequence -PCRE2_ERROR_UTF8_ERR18 Overlong 5-byte sequence (won't ever occur) -PCRE2_ERROR_UTF8_ERR19 Overlong 6-byte sequence (won't ever occur) -PCRE2_ERROR_UTF8_ERR20 Isolated 0x80 byte (not within UTF-8 character) -PCRE2_ERROR_UTF8_ERR21 Byte with the illegal value 0xfe or 0xff -*/ - -for (p = string; length > 0; p++) - { - uint32_t ab, d; - - c = *p; - length--; - - if (c < 128) continue; /* ASCII character */ - - if (c < 0xc0) /* Isolated 10xx xxxx byte */ - { - *erroroffset = (PCRE2_SIZE)(p - string); - return PCRE2_ERROR_UTF8_ERR20; - } - - if (c >= 0xfe) /* Invalid 0xfe or 0xff bytes */ - { - *erroroffset = (PCRE2_SIZE)(p - string); - return PCRE2_ERROR_UTF8_ERR21; - } - - ab = PRIV(utf8_table4)[c & 0x3f]; /* Number of additional bytes (1-5) */ - if (length < ab) /* Missing bytes */ - { - *erroroffset = (PCRE2_SIZE)(p - string); - switch(ab - length) - { - case 1: return PCRE2_ERROR_UTF8_ERR1; - case 2: return PCRE2_ERROR_UTF8_ERR2; - case 3: return PCRE2_ERROR_UTF8_ERR3; - case 4: return PCRE2_ERROR_UTF8_ERR4; - case 5: return PCRE2_ERROR_UTF8_ERR5; - } - } - length -= ab; /* Length remaining */ - - /* Check top bits in the second byte */ - - if (((d = *(++p)) & 0xc0) != 0x80) - { - *erroroffset = (int)(p - string) - 1; - return PCRE2_ERROR_UTF8_ERR6; - } - - /* For each length, check that the remaining bytes start with the 0x80 bit - set and not the 0x40 bit. Then check for an overlong sequence, and for the - excluded range 0xd800 to 0xdfff. */ - - switch (ab) - { - /* 2-byte character. No further bytes to check for 0x80. Check first byte - for for xx00 000x (overlong sequence). */ - - case 1: if ((c & 0x3e) == 0) - { - *erroroffset = (int)(p - string) - 1; - return PCRE2_ERROR_UTF8_ERR15; - } - break; - - /* 3-byte character. Check third byte for 0x80. Then check first 2 bytes - for 1110 0000, xx0x xxxx (overlong sequence) or - 1110 1101, 1010 xxxx (0xd800 - 0xdfff) */ - - case 2: - if ((*(++p) & 0xc0) != 0x80) /* Third byte */ - { - *erroroffset = (int)(p - string) - 2; - return PCRE2_ERROR_UTF8_ERR7; - } - if (c == 0xe0 && (d & 0x20) == 0) - { - *erroroffset = (int)(p - string) - 2; - return PCRE2_ERROR_UTF8_ERR16; - } - if (c == 0xed && d >= 0xa0) - { - *erroroffset = (int)(p - string) - 2; - return PCRE2_ERROR_UTF8_ERR14; - } - break; - - /* 4-byte character. Check 3rd and 4th bytes for 0x80. Then check first 2 - bytes for for 1111 0000, xx00 xxxx (overlong sequence), then check for a - character greater than 0x0010ffff (f4 8f bf bf) */ - - case 3: - if ((*(++p) & 0xc0) != 0x80) /* Third byte */ - { - *erroroffset = (int)(p - string) - 2; - return PCRE2_ERROR_UTF8_ERR7; - } - if ((*(++p) & 0xc0) != 0x80) /* Fourth byte */ - { - *erroroffset = (int)(p - string) - 3; - return PCRE2_ERROR_UTF8_ERR8; - } - if (c == 0xf0 && (d & 0x30) == 0) - { - *erroroffset = (int)(p - string) - 3; - return PCRE2_ERROR_UTF8_ERR17; - } - if (c > 0xf4 || (c == 0xf4 && d > 0x8f)) - { - *erroroffset = (int)(p - string) - 3; - return PCRE2_ERROR_UTF8_ERR13; - } - break; - - /* 5-byte and 6-byte characters are not allowed by RFC 3629, and will be - rejected by the length test below. However, we do the appropriate tests - here so that overlong sequences get diagnosed, and also in case there is - ever an option for handling these larger code points. */ - - /* 5-byte character. Check 3rd, 4th, and 5th bytes for 0x80. Then check for - 1111 1000, xx00 0xxx */ - - case 4: - if ((*(++p) & 0xc0) != 0x80) /* Third byte */ - { - *erroroffset = (int)(p - string) - 2; - return PCRE2_ERROR_UTF8_ERR7; - } - if ((*(++p) & 0xc0) != 0x80) /* Fourth byte */ - { - *erroroffset = (int)(p - string) - 3; - return PCRE2_ERROR_UTF8_ERR8; - } - if ((*(++p) & 0xc0) != 0x80) /* Fifth byte */ - { - *erroroffset = (int)(p - string) - 4; - return PCRE2_ERROR_UTF8_ERR9; - } - if (c == 0xf8 && (d & 0x38) == 0) - { - *erroroffset = (int)(p - string) - 4; - return PCRE2_ERROR_UTF8_ERR18; - } - break; - - /* 6-byte character. Check 3rd-6th bytes for 0x80. Then check for - 1111 1100, xx00 00xx. */ - - case 5: - if ((*(++p) & 0xc0) != 0x80) /* Third byte */ - { - *erroroffset = (int)(p - string) - 2; - return PCRE2_ERROR_UTF8_ERR7; - } - if ((*(++p) & 0xc0) != 0x80) /* Fourth byte */ - { - *erroroffset = (int)(p - string) - 3; - return PCRE2_ERROR_UTF8_ERR8; - } - if ((*(++p) & 0xc0) != 0x80) /* Fifth byte */ - { - *erroroffset = (int)(p - string) - 4; - return PCRE2_ERROR_UTF8_ERR9; - } - if ((*(++p) & 0xc0) != 0x80) /* Sixth byte */ - { - *erroroffset = (int)(p - string) - 5; - return PCRE2_ERROR_UTF8_ERR10; - } - if (c == 0xfc && (d & 0x3c) == 0) - { - *erroroffset = (int)(p - string) - 5; - return PCRE2_ERROR_UTF8_ERR19; - } - break; - } - - /* Character is valid under RFC 2279, but 4-byte and 5-byte characters are - excluded by RFC 3629. The pointer p is currently at the last byte of the - character. */ - - if (ab > 3) - { - *erroroffset = (int)(p - string) - ab; - return (ab == 4)? PCRE2_ERROR_UTF8_ERR11 : PCRE2_ERROR_UTF8_ERR12; - } - } -return 0; - - -/* ----------------- Check a UTF-16 string ----------------- */ - -#elif PCRE2_CODE_UNIT_WIDTH == 16 - -/* There's not so much work, nor so many errors, for UTF-16. -PCRE2_ERROR_UTF16_ERR1 Missing low surrogate at the end of the string -PCRE2_ERROR_UTF16_ERR2 Invalid low surrogate -PCRE2_ERROR_UTF16_ERR3 Isolated low surrogate -*/ - -for (p = string; length > 0; p++) - { - c = *p; - length--; - - if ((c & 0xf800) != 0xd800) - { - /* Normal UTF-16 code point. Neither high nor low surrogate. */ - } - else if ((c & 0x0400) == 0) - { - /* High surrogate. Must be a followed by a low surrogate. */ - if (length == 0) - { - *erroroffset = p - string; - return PCRE2_ERROR_UTF16_ERR1; - } - p++; - length--; - if ((*p & 0xfc00) != 0xdc00) - { - *erroroffset = p - string - 1; - return PCRE2_ERROR_UTF16_ERR2; - } - } - else - { - /* Isolated low surrogate. Always an error. */ - *erroroffset = p - string; - return PCRE2_ERROR_UTF16_ERR3; - } - } -return 0; - - - -/* ----------------- Check a UTF-32 string ----------------- */ - -#else - -/* There is very little to do for a UTF-32 string. -PCRE2_ERROR_UTF32_ERR1 Surrogate character -PCRE2_ERROR_UTF32_ERR2 Character > 0x10ffff -*/ - -for (p = string; length > 0; length--, p++) - { - c = *p; - if ((c & 0xfffff800u) != 0xd800u) - { - /* Normal UTF-32 code point. Neither high nor low surrogate. */ - if (c > 0x10ffffu) - { - *erroroffset = p - string; - return PCRE2_ERROR_UTF32_ERR2; - } - } - else - { - /* A surrogate */ - *erroroffset = p - string; - return PCRE2_ERROR_UTF32_ERR1; - } - } -return 0; -#endif /* CODE_UNIT_WIDTH */ -} -#endif /* SUPPORT_UNICODE */ - -/* End of pcre2_valid_utf.c */ diff --git a/modules/regex/pcre2/src/pcre2_xclass.c b/modules/regex/pcre2/src/pcre2_xclass.c deleted file mode 100644 index bb57196..0000000 --- a/modules/regex/pcre2/src/pcre2_xclass.c +++ /dev/null @@ -1,289 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* PCRE is a library of functions to support regular expressions whose syntax -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-2022 University of Cambridge - ------------------------------------------------------------------------------ -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * 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. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 OWNER 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. ------------------------------------------------------------------------------ -*/ - -/* This module contains an internal function that is used to match an extended -class. It is used by pcre2_auto_possessify() and by both pcre2_match() and -pcre2_def_match(). */ - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - - -#include "pcre2_internal.h" - -/************************************************* -* Match character against an XCLASS * -*************************************************/ - -/* This function is called to match a character against an extended class that -might contain codepoints above 255 and/or Unicode properties. - -Arguments: - c the character - data points to the flag code unit of the XCLASS data - utf TRUE if in UTF mode - -Returns: TRUE if character matches, else FALSE -*/ - -BOOL -PRIV(xclass)(uint32_t c, PCRE2_SPTR data, BOOL utf) -{ -PCRE2_UCHAR t; -BOOL negated = (*data & XCL_NOT) != 0; - -#if PCRE2_CODE_UNIT_WIDTH == 8 -/* In 8 bit mode, this must always be TRUE. Help the compiler to know that. */ -utf = TRUE; -#endif - -/* Code points < 256 are matched against a bitmap, if one is present. If not, -we still carry on, because there may be ranges that start below 256 in the -additional data. */ - -if (c < 256) - { - if ((*data & XCL_HASPROP) == 0) - { - if ((*data & XCL_MAP) == 0) return negated; - return (((uint8_t *)(data + 1))[c/8] & (1u << (c&7))) != 0; - } - if ((*data & XCL_MAP) != 0 && - (((uint8_t *)(data + 1))[c/8] & (1u << (c&7))) != 0) - return !negated; /* char found */ - } - -/* First skip the bit map if present. Then match against the list of Unicode -properties or large chars or ranges that end with a large char. We won't ever -encounter XCL_PROP or XCL_NOTPROP when UTF support is not compiled. */ - -if ((*data++ & XCL_MAP) != 0) data += 32 / sizeof(PCRE2_UCHAR); - -while ((t = *data++) != XCL_END) - { - uint32_t x, y; - if (t == XCL_SINGLE) - { -#ifdef SUPPORT_UNICODE - if (utf) - { - GETCHARINC(x, data); /* macro generates multiple statements */ - } - else -#endif - x = *data++; - if (c == x) return !negated; - } - else if (t == XCL_RANGE) - { -#ifdef SUPPORT_UNICODE - if (utf) - { - GETCHARINC(x, data); /* macro generates multiple statements */ - GETCHARINC(y, data); /* macro generates multiple statements */ - } - else -#endif - { - x = *data++; - y = *data++; - } - if (c >= x && c <= y) return !negated; - } - -#ifdef SUPPORT_UNICODE - else /* XCL_PROP & XCL_NOTPROP */ - { - const ucd_record *prop = GET_UCD(c); - BOOL isprop = t == XCL_PROP; - BOOL ok; - - switch(*data) - { - case PT_ANY: - if (isprop) return !negated; - break; - - case PT_LAMP: - if ((prop->chartype == ucp_Lu || prop->chartype == ucp_Ll || - prop->chartype == ucp_Lt) == isprop) return !negated; - break; - - case PT_GC: - if ((data[1] == PRIV(ucp_gentype)[prop->chartype]) == isprop) - return !negated; - break; - - case PT_PC: - if ((data[1] == prop->chartype) == isprop) return !negated; - break; - - case PT_SC: - if ((data[1] == prop->script) == isprop) return !negated; - break; - - case PT_SCX: - ok = (data[1] == prop->script || - MAPBIT(PRIV(ucd_script_sets) + UCD_SCRIPTX_PROP(prop), data[1]) != 0); - if (ok == isprop) return !negated; - break; - - case PT_ALNUM: - if ((PRIV(ucp_gentype)[prop->chartype] == ucp_L || - PRIV(ucp_gentype)[prop->chartype] == ucp_N) == isprop) - return !negated; - break; - - /* Perl space used to exclude VT, but from Perl 5.18 it is included, - which means that Perl space and POSIX space are now identical. PCRE - was changed at release 8.34. */ - - case PT_SPACE: /* Perl space */ - case PT_PXSPACE: /* POSIX space */ - switch(c) - { - HSPACE_CASES: - VSPACE_CASES: - if (isprop) return !negated; - break; - - default: - if ((PRIV(ucp_gentype)[prop->chartype] == ucp_Z) == isprop) - return !negated; - break; - } - break; - - case PT_WORD: - if ((PRIV(ucp_gentype)[prop->chartype] == ucp_L || - PRIV(ucp_gentype)[prop->chartype] == ucp_N || c == CHAR_UNDERSCORE) - == isprop) - return !negated; - break; - - case PT_UCNC: - if (c < 0xa0) - { - if ((c == CHAR_DOLLAR_SIGN || c == CHAR_COMMERCIAL_AT || - c == CHAR_GRAVE_ACCENT) == isprop) - return !negated; - } - else - { - if ((c < 0xd800 || c > 0xdfff) == isprop) - return !negated; - } - break; - - case PT_BIDICL: - if ((UCD_BIDICLASS_PROP(prop) == data[1]) == isprop) - return !negated; - break; - - case PT_BOOL: - ok = MAPBIT(PRIV(ucd_boolprop_sets) + - UCD_BPROPS_PROP(prop), data[1]) != 0; - if (ok == isprop) return !negated; - break; - - /* The following three properties can occur only in an XCLASS, as there - is no \p or \P coding for them. */ - - /* Graphic character. Implement this as not Z (space or separator) and - not C (other), except for Cf (format) with a few exceptions. This seems - to be what Perl does. The exceptional characters are: - - U+061C Arabic Letter Mark - U+180E Mongolian Vowel Separator - U+2066 - U+2069 Various "isolate"s - */ - - case PT_PXGRAPH: - if ((PRIV(ucp_gentype)[prop->chartype] != ucp_Z && - (PRIV(ucp_gentype)[prop->chartype] != ucp_C || - (prop->chartype == ucp_Cf && - c != 0x061c && c != 0x180e && (c < 0x2066 || c > 0x2069)) - )) == isprop) - return !negated; - break; - - /* Printable character: same as graphic, with the addition of Zs, i.e. - not Zl and not Zp, and U+180E. */ - - case PT_PXPRINT: - if ((prop->chartype != ucp_Zl && - prop->chartype != ucp_Zp && - (PRIV(ucp_gentype)[prop->chartype] != ucp_C || - (prop->chartype == ucp_Cf && - c != 0x061c && (c < 0x2066 || c > 0x2069)) - )) == isprop) - return !negated; - break; - - /* Punctuation: all Unicode punctuation, plus ASCII characters that - Unicode treats as symbols rather than punctuation, for Perl - compatibility (these are $+<=>^`|~). */ - - case PT_PXPUNCT: - if ((PRIV(ucp_gentype)[prop->chartype] == ucp_P || - (c < 128 && PRIV(ucp_gentype)[prop->chartype] == ucp_S)) == isprop) - return !negated; - break; - - /* This should never occur, but compilers may mutter if there is no - default. */ - - default: - return FALSE; - } - - data += 2; - } -#else - (void)utf; /* Avoid compiler warning */ -#endif /* SUPPORT_UNICODE */ - } - -return negated; /* char did not match */ -} - -/* End of pcre2_xclass.c */ diff --git a/modules/regex/pcre2/src/sljit/sljitConfig.h b/modules/regex/pcre2/src/sljit/sljitConfig.h deleted file mode 100644 index 5fba7aa..0000000 --- a/modules/regex/pcre2/src/sljit/sljitConfig.h +++ /dev/null @@ -1,162 +0,0 @@ -/* - * 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. - */ - -#ifndef SLJIT_CONFIG_H_ -#define SLJIT_CONFIG_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -/* - This file contains the basic configuration options for the SLJIT compiler - and their default values. These options can be overridden in the - sljitConfigPre.h header file when SLJIT_HAVE_CONFIG_PRE is set to a - non-zero value. -*/ - -/* --------------------------------------------------------------------- */ -/* Architecture */ -/* --------------------------------------------------------------------- */ - -/* Architecture selection. */ -/* #define SLJIT_CONFIG_X86_32 1 */ -/* #define SLJIT_CONFIG_X86_64 1 */ -/* #define SLJIT_CONFIG_ARM_V5 1 */ -/* #define SLJIT_CONFIG_ARM_V7 1 */ -/* #define SLJIT_CONFIG_ARM_THUMB2 1 */ -/* #define SLJIT_CONFIG_ARM_64 1 */ -/* #define SLJIT_CONFIG_PPC_32 1 */ -/* #define SLJIT_CONFIG_PPC_64 1 */ -/* #define SLJIT_CONFIG_MIPS_32 1 */ -/* #define SLJIT_CONFIG_MIPS_64 1 */ -/* #define SLJIT_CONFIG_RISCV_32 1 */ -/* #define SLJIT_CONFIG_RISCV_64 1 */ -/* #define SLJIT_CONFIG_S390X 1 */ - -/* #define SLJIT_CONFIG_AUTO 1 */ -/* #define SLJIT_CONFIG_UNSUPPORTED 1 */ - -/* --------------------------------------------------------------------- */ -/* Utilities */ -/* --------------------------------------------------------------------- */ - -/* Implements a stack like data structure (by using mmap / VirtualAlloc */ -/* or a custom allocator). */ -#ifndef SLJIT_UTIL_STACK -/* Enabled by default */ -#define SLJIT_UTIL_STACK 1 -#endif - -/* Uses user provided allocator to allocate the stack (see SLJIT_UTIL_STACK) */ -#ifndef SLJIT_UTIL_SIMPLE_STACK_ALLOCATION -/* Disabled by default */ -#define SLJIT_UTIL_SIMPLE_STACK_ALLOCATION 0 -#endif - -/* Single threaded application. Does not require any locks. */ -#ifndef SLJIT_SINGLE_THREADED -/* Disabled by default. */ -#define SLJIT_SINGLE_THREADED 0 -#endif - -/* --------------------------------------------------------------------- */ -/* Configuration */ -/* --------------------------------------------------------------------- */ - -/* If SLJIT_STD_MACROS_DEFINED is not defined, the application should - define SLJIT_MALLOC, SLJIT_FREE, SLJIT_MEMCPY, and NULL. */ -#ifndef SLJIT_STD_MACROS_DEFINED -/* Disabled by default. */ -#define SLJIT_STD_MACROS_DEFINED 0 -#endif - -/* Executable code allocation: - If SLJIT_EXECUTABLE_ALLOCATOR is not defined, the application should - define SLJIT_MALLOC_EXEC, SLJIT_FREE_EXEC, and SLJIT_EXEC_OFFSET. */ -#ifndef SLJIT_EXECUTABLE_ALLOCATOR -/* Enabled by default. */ -#define SLJIT_EXECUTABLE_ALLOCATOR 1 - -/* When SLJIT_PROT_EXECUTABLE_ALLOCATOR is enabled SLJIT uses - an allocator which does not set writable and executable - permission flags at the same time. - Instead, it creates a shared memory segment (usually backed by a file) - and maps it twice, with different permissions, depending on the use - case. - The trade-off is increased use of virtual memory, incompatibility with - fork(), and some possible additional security risks by the use of - publicly accessible files for the generated code. */ -#ifndef SLJIT_PROT_EXECUTABLE_ALLOCATOR -/* Disabled by default. */ -#define SLJIT_PROT_EXECUTABLE_ALLOCATOR 0 -#endif - -/* When SLJIT_WX_EXECUTABLE_ALLOCATOR is enabled SLJIT uses an - allocator which does not set writable and executable permission - flags at the same time. - Instead, it creates a new independent map on each invocation and - switches permissions at the underlying pages as needed. - The trade-off is increased memory use and degraded performance. */ -#ifndef SLJIT_WX_EXECUTABLE_ALLOCATOR -/* Disabled by default. */ -#define SLJIT_WX_EXECUTABLE_ALLOCATOR 0 -#endif - -#endif /* !SLJIT_EXECUTABLE_ALLOCATOR */ - -/* Return with error when an invalid argument is passed. */ -#ifndef SLJIT_ARGUMENT_CHECKS -/* Disabled by default */ -#define SLJIT_ARGUMENT_CHECKS 0 -#endif - -/* Debug checks (assertions, etc.). */ -#ifndef SLJIT_DEBUG -/* Enabled by default */ -#define SLJIT_DEBUG 1 -#endif - -/* Verbose operations. */ -#ifndef SLJIT_VERBOSE -/* Enabled by default */ -#define SLJIT_VERBOSE 1 -#endif - -/* - SLJIT_IS_FPU_AVAILABLE - The availability of the FPU can be controlled by SLJIT_IS_FPU_AVAILABLE. - zero value - FPU is NOT present. - nonzero value - FPU is present. -*/ - -/* For further configurations, see the beginning of sljitConfigInternal.h */ - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* SLJIT_CONFIG_H_ */ diff --git a/modules/regex/pcre2/src/sljit/sljitConfigInternal.h b/modules/regex/pcre2/src/sljit/sljitConfigInternal.h deleted file mode 100644 index cd3ce69..0000000 --- a/modules/regex/pcre2/src/sljit/sljitConfigInternal.h +++ /dev/null @@ -1,851 +0,0 @@ -/* - * 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. - */ - -#ifndef SLJIT_CONFIG_INTERNAL_H_ -#define SLJIT_CONFIG_INTERNAL_H_ - -#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \ - || (defined SLJIT_DEBUG && SLJIT_DEBUG && (!defined(SLJIT_ASSERT) || !defined(SLJIT_UNREACHABLE))) -#include -#endif - -#if (defined SLJIT_DEBUG && SLJIT_DEBUG \ - && (!defined(SLJIT_ASSERT) || !defined(SLJIT_UNREACHABLE) || !defined(SLJIT_HALT_PROCESS))) -#include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* - SLJIT defines the following architecture dependent types and macros: - - Types: - sljit_s8, sljit_u8 : signed and unsigned 8 bit integer type - 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_f32 : 32 bit single precision floating point value - sljit_f64 : 64 bit double precision floating point value - - Macros for feature detection (boolean): - SLJIT_32BIT_ARCHITECTURE : 32 bit architecture - SLJIT_64BIT_ARCHITECTURE : 64 bit architecture - SLJIT_LITTLE_ENDIAN : little endian architecture - SLJIT_BIG_ENDIAN : big endian architecture - SLJIT_UNALIGNED : unaligned memory accesses for non-fpu operations are supported - SLJIT_FPU_UNALIGNED : unaligned memory accesses for fpu operations are supported - SLJIT_INDIRECT_CALL : see SLJIT_FUNC_ADDR() for more information - - Constants: - SLJIT_NUMBER_OF_REGISTERS : number of available registers - SLJIT_NUMBER_OF_SCRATCH_REGISTERS : number of available scratch registers - SLJIT_NUMBER_OF_SAVED_REGISTERS : number of available saved registers - SLJIT_NUMBER_OF_FLOAT_REGISTERS : number of available floating point registers - SLJIT_NUMBER_OF_SCRATCH_FLOAT_REGISTERS : number of available floating point scratch registers - SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS : number of available floating point saved registers - SLJIT_WORD_SHIFT : the shift required to apply when accessing a sljit_sw/sljit_uw array by index - SLJIT_F32_SHIFT : the shift required to apply when accessing - a single precision floating point array by index - SLJIT_F64_SHIFT : the shift required to apply when accessing - a double precision floating point array by index - SLJIT_PREF_SHIFT_REG : x86 systems prefers ecx for shifting by register - the scratch register index of ecx is stored in this variable - SLJIT_LOCALS_OFFSET : local space starting offset (SLJIT_SP + SLJIT_LOCALS_OFFSET) - SLJIT_RETURN_ADDRESS_OFFSET : a return instruction always adds this offset to the return address - - Other macros: - 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) -*/ - -/*****************/ -/* Sanity check. */ -/*****************/ - -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) \ - + (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) \ - + (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) \ - + (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) \ - + (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2) \ - + (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) \ - + (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) \ - + (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) \ - + (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) \ - + (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) \ - + (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) \ - + (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64) \ - + (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X) \ - + (defined SLJIT_CONFIG_AUTO && SLJIT_CONFIG_AUTO) \ - + (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED) >= 2 -#error "Multiple architectures are selected" -#endif - -#if !(defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) \ - && !(defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) \ - && !(defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) \ - && !(defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) \ - && !(defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2) \ - && !(defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) \ - && !(defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) \ - && !(defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) \ - && !(defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) \ - && !(defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) \ - && !(defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) \ - && !(defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64) \ - && !(defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X) \ - && !(defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED) \ - && !(defined SLJIT_CONFIG_AUTO && SLJIT_CONFIG_AUTO) -#if defined SLJIT_CONFIG_AUTO && !SLJIT_CONFIG_AUTO -#error "An architecture must be selected" -#else /* SLJIT_CONFIG_AUTO */ -#define SLJIT_CONFIG_AUTO 1 -#endif /* !SLJIT_CONFIG_AUTO */ -#endif /* !SLJIT_CONFIG */ - -/********************************************************/ -/* Automatic CPU detection (requires compiler support). */ -/********************************************************/ - -#if (defined SLJIT_CONFIG_AUTO && SLJIT_CONFIG_AUTO) - -#ifndef _WIN32 - -#if defined(__i386__) || defined(__i386) -#define SLJIT_CONFIG_X86_32 1 -#elif defined(__x86_64__) -#define SLJIT_CONFIG_X86_64 1 -#elif defined(__arm__) || defined(__ARM__) -#ifdef __thumb2__ -#define SLJIT_CONFIG_ARM_THUMB2 1 -#elif defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) -#define SLJIT_CONFIG_ARM_V7 1 -#else -#define SLJIT_CONFIG_ARM_V5 1 -#endif -#elif defined (__aarch64__) -#define SLJIT_CONFIG_ARM_64 1 -#elif defined(__ppc64__) || defined(__powerpc64__) || (defined(_ARCH_PPC64) && defined(__64BIT__)) || (defined(_POWER) && defined(__64BIT__)) -#define SLJIT_CONFIG_PPC_64 1 -#elif defined(__ppc__) || defined(__powerpc__) || defined(_ARCH_PPC) || defined(_ARCH_PWR) || defined(_ARCH_PWR2) || defined(_POWER) -#define SLJIT_CONFIG_PPC_32 1 -#elif defined(__mips__) && !defined(_LP64) -#define SLJIT_CONFIG_MIPS_32 1 -#elif defined(__mips64) -#define SLJIT_CONFIG_MIPS_64 1 -#elif defined (__riscv_xlen) && (__riscv_xlen == 32) -#define SLJIT_CONFIG_RISCV_32 1 -#elif defined (__riscv_xlen) && (__riscv_xlen == 64) -#define SLJIT_CONFIG_RISCV_64 1 -#elif defined(__s390x__) -#define SLJIT_CONFIG_S390X 1 -#else -/* Unsupported architecture */ -#define SLJIT_CONFIG_UNSUPPORTED 1 -#endif - -#else /* _WIN32 */ - -#if defined(_M_X64) || defined(__x86_64__) -#define SLJIT_CONFIG_X86_64 1 -#elif (defined(_M_ARM) && _M_ARM >= 7 && defined(_M_ARMT)) || defined(__thumb2__) -#define SLJIT_CONFIG_ARM_THUMB2 1 -#elif (defined(_M_ARM) && _M_ARM >= 7) -#define SLJIT_CONFIG_ARM_V7 1 -#elif defined(_ARM_) -#define SLJIT_CONFIG_ARM_V5 1 -#elif defined(_M_ARM64) || defined(__aarch64__) -#define SLJIT_CONFIG_ARM_64 1 -#else -#define SLJIT_CONFIG_X86_32 1 -#endif - -#endif /* !_WIN32 */ -#endif /* SLJIT_CONFIG_AUTO */ - -#if (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED) -#undef SLJIT_EXECUTABLE_ALLOCATOR -#endif - -/******************************/ -/* CPU family type detection. */ -/******************************/ - -#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) || (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) \ - || (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2) -#define SLJIT_CONFIG_ARM_32 1 -#endif - -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) || (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) -#define SLJIT_CONFIG_X86 1 -#elif (defined SLJIT_CONFIG_ARM_32 && SLJIT_CONFIG_ARM_32) || (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) -#define SLJIT_CONFIG_ARM 1 -#elif (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) || (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) -#define SLJIT_CONFIG_PPC 1 -#elif (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) || (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) -#define SLJIT_CONFIG_MIPS 1 -#elif (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) || (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64) -#define SLJIT_CONFIG_RISCV 1 -#endif - -/***********************************************************/ -/* Intel Control-flow Enforcement Technology (CET) spport. */ -/***********************************************************/ - -#ifdef SLJIT_CONFIG_X86 - -#if defined(__CET__) && !(defined SLJIT_CONFIG_X86_CET && SLJIT_CONFIG_X86_CET) -#define SLJIT_CONFIG_X86_CET 1 -#endif - -#if (defined SLJIT_CONFIG_X86_CET && SLJIT_CONFIG_X86_CET) && defined(__GNUC__) -#include -#endif - -#endif /* SLJIT_CONFIG_X86 */ - -/**********************************/ -/* External function definitions. */ -/**********************************/ - -/* General macros: - Note: SLJIT is designed to be independent from them as possible. - - In release mode (SLJIT_DEBUG is not defined) only the following - external functions are needed: -*/ - -#ifndef SLJIT_MALLOC -#define SLJIT_MALLOC(size, allocator_data) malloc(size) -#endif - -#ifndef SLJIT_FREE -#define SLJIT_FREE(ptr, allocator_data) free(ptr) -#endif - -#ifndef SLJIT_MEMCPY -#define SLJIT_MEMCPY(dest, src, len) memcpy(dest, src, len) -#endif - -#ifndef SLJIT_MEMMOVE -#define SLJIT_MEMMOVE(dest, src, len) memmove(dest, src, len) -#endif - -#ifndef SLJIT_ZEROMEM -#define SLJIT_ZEROMEM(dest, len) memset(dest, 0, len) -#endif - -/***************************/ -/* Compiler helper macros. */ -/***************************/ - -#if !defined(SLJIT_LIKELY) && !defined(SLJIT_UNLIKELY) - -#if defined(__GNUC__) && (__GNUC__ >= 3) -#define SLJIT_LIKELY(x) __builtin_expect((x), 1) -#define SLJIT_UNLIKELY(x) __builtin_expect((x), 0) -#else -#define SLJIT_LIKELY(x) (x) -#define SLJIT_UNLIKELY(x) (x) -#endif - -#endif /* !defined(SLJIT_LIKELY) && !defined(SLJIT_UNLIKELY) */ - -#ifndef SLJIT_INLINE -/* Inline functions. Some old compilers do not support them. */ -#ifdef __SUNPRO_C -#if __SUNPRO_C < 0x560 -#define SLJIT_INLINE -#else -#define SLJIT_INLINE inline -#endif /* __SUNPRO_C */ -#else -#define SLJIT_INLINE __inline -#endif -#endif /* !SLJIT_INLINE */ - -#ifndef SLJIT_NOINLINE -/* Not inline functions. */ -#if defined(__GNUC__) -#define SLJIT_NOINLINE __attribute__ ((noinline)) -#else -#define SLJIT_NOINLINE -#endif -#endif /* !SLJIT_INLINE */ - -#ifndef SLJIT_UNUSED_ARG -/* Unused arguments. */ -#define SLJIT_UNUSED_ARG(arg) (void)arg -#endif - -/*********************************/ -/* Type of public API functions. */ -/*********************************/ - -#ifndef SLJIT_API_FUNC_ATTRIBUTE -#if (defined SLJIT_CONFIG_STATIC && SLJIT_CONFIG_STATIC) -/* Static ABI functions. For all-in-one programs. */ - -#if defined(__GNUC__) -/* Disable unused warnings in gcc. */ -#define SLJIT_API_FUNC_ATTRIBUTE static __attribute__((unused)) -#else -#define SLJIT_API_FUNC_ATTRIBUTE static -#endif - -#else -#define SLJIT_API_FUNC_ATTRIBUTE -#endif /* (defined SLJIT_CONFIG_STATIC && SLJIT_CONFIG_STATIC) */ -#endif /* defined SLJIT_API_FUNC_ATTRIBUTE */ - -/****************************/ -/* Instruction cache flush. */ -/****************************/ - -/* - * TODO: - * - * clang >= 15 could be safe to enable below - * older versions are known to abort in some targets - * https://github.com/PhilipHazel/pcre2/issues/92 - * - * beware some vendors (ex: Microsoft, Apple) are known to have - * removed the code to support this builtin even if the call for - * __has_builtin reports it is available. - * - * make sure linking doesn't fail because __clear_cache() is - * missing before changing it or add an exception so that the - * system provided method that should be defined below is used - * instead. - */ -#if (!defined SLJIT_CACHE_FLUSH && defined __has_builtin) -#if __has_builtin(__builtin___clear_cache) && !defined(__clang__) - -/* - * https://gcc.gnu.org/bugzilla//show_bug.cgi?id=91248 - * https://gcc.gnu.org/bugzilla//show_bug.cgi?id=93811 - * gcc's clear_cache builtin for power is broken - */ -#if !defined(SLJIT_CONFIG_PPC) -#define SLJIT_CACHE_FLUSH(from, to) \ - __builtin___clear_cache((char*)(from), (char*)(to)) -#endif - -#endif /* gcc >= 10 */ -#endif /* (!defined SLJIT_CACHE_FLUSH && defined __has_builtin) */ - -#ifndef SLJIT_CACHE_FLUSH - -#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) \ - || (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X) - -/* Not required to implement on archs with unified caches. */ -#define SLJIT_CACHE_FLUSH(from, to) - -#elif defined __APPLE__ - -/* Supported by all macs since Mac OS 10.5. - However, it does not work on non-jailbroken iOS devices, - although the compilation is successful. */ -#include -#define SLJIT_CACHE_FLUSH(from, to) \ - sys_icache_invalidate((void*)(from), (size_t)((char*)(to) - (char*)(from))) - -#elif (defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC) - -/* The __clear_cache() implementation of GCC is a dummy function on PowerPC. */ -#define SLJIT_CACHE_FLUSH(from, to) \ - ppc_cache_flush((from), (to)) -#define SLJIT_CACHE_FLUSH_OWN_IMPL 1 - -#elif defined(_WIN32) - -#define SLJIT_CACHE_FLUSH(from, to) \ - FlushInstructionCache(GetCurrentProcess(), (void*)(from), (char*)(to) - (char*)(from)) - -#elif (defined(__GNUC__) && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))) || defined(__clang__) - -#define SLJIT_CACHE_FLUSH(from, to) \ - __builtin___clear_cache((char*)(from), (char*)(to)) - -#elif defined __ANDROID__ - -/* Android ARMv7 with gcc lacks __clear_cache; use cacheflush instead. */ -#include -#define SLJIT_CACHE_FLUSH(from, to) \ - cacheflush((long)(from), (long)(to), 0) - -#else - -/* Call __ARM_NR_cacheflush on ARM-Linux or the corresponding MIPS syscall. */ -#define SLJIT_CACHE_FLUSH(from, to) \ - __clear_cache((char*)(from), (char*)(to)) - -#endif - -#endif /* !SLJIT_CACHE_FLUSH */ - -/******************************************************/ -/* Integer and floating point type definitions. */ -/******************************************************/ - -/* 8 bit byte type. */ -typedef unsigned char sljit_u8; -typedef signed char sljit_s8; - -/* 16 bit half-word type. */ -typedef unsigned short int sljit_u16; -typedef signed short int sljit_s16; - -/* 32 bit integer type. */ -typedef unsigned int sljit_u32; -typedef signed int sljit_s32; - -/* Machine word type. Enough for storing a pointer. - 32 bit for 32 bit machines. - 64 bit for 64 bit machines. */ -#if (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED) -/* Just to have something. */ -#define SLJIT_WORD_SHIFT 0 -typedef unsigned long int sljit_uw; -typedef long int sljit_sw; -#elif !(defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) \ - && !(defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) \ - && !(defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) \ - && !(defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) \ - && !(defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64) \ - && !(defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X) -#define SLJIT_32BIT_ARCHITECTURE 1 -#define SLJIT_WORD_SHIFT 2 -typedef unsigned int sljit_uw; -typedef int sljit_sw; -#else -#define SLJIT_64BIT_ARCHITECTURE 1 -#define SLJIT_WORD_SHIFT 3 -#ifdef _WIN32 -#ifdef __GNUC__ -/* These types do not require windows.h */ -typedef unsigned long long sljit_uw; -typedef long long sljit_sw; -#else -typedef unsigned __int64 sljit_uw; -typedef __int64 sljit_sw; -#endif -#else /* !_WIN32 */ -typedef unsigned long int sljit_uw; -typedef long int sljit_sw; -#endif /* _WIN32 */ -#endif - -typedef sljit_uw sljit_p; - -/* Floating point types. */ -typedef float sljit_f32; -typedef double sljit_f64; - -/* Shift for pointer sized data. */ -#define SLJIT_POINTER_SHIFT SLJIT_WORD_SHIFT - -/* Shift for double precision sized data. */ -#define SLJIT_F32_SHIFT 2 -#define SLJIT_F64_SHIFT 3 - -#ifndef SLJIT_W - -/* Defining long constants. */ -#if (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED) -#define SLJIT_W(w) (w##l) -#elif (defined SLJIT_64BIT_ARCHITECTURE && SLJIT_64BIT_ARCHITECTURE) -#ifdef _WIN64 -#define SLJIT_W(w) (w##ll) -#else /* !windows */ -#define SLJIT_W(w) (w##l) -#endif /* windows */ -#else /* 32 bit */ -#define SLJIT_W(w) (w) -#endif /* unknown */ - -#endif /* !SLJIT_W */ - -/*************************/ -/* Endianness detection. */ -/*************************/ - -#if !defined(SLJIT_BIG_ENDIAN) && !defined(SLJIT_LITTLE_ENDIAN) - -/* These macros are mostly useful for the applications. */ -#if (defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC) - -#ifdef __LITTLE_ENDIAN__ -#define SLJIT_LITTLE_ENDIAN 1 -#else -#define SLJIT_BIG_ENDIAN 1 -#endif - -#elif (defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS) - -#ifdef __MIPSEL__ -#define SLJIT_LITTLE_ENDIAN 1 -#else -#define SLJIT_BIG_ENDIAN 1 -#endif - -#ifndef SLJIT_MIPS_REV - -/* Auto detecting mips revision. */ -#if (defined __mips_isa_rev) && (__mips_isa_rev >= 6) -#define SLJIT_MIPS_REV 6 -#elif (defined __mips_isa_rev && __mips_isa_rev >= 1) \ - || (defined __clang__ && defined _MIPS_ARCH_OCTEON) \ - || (defined __clang__ && defined _MIPS_ARCH_P5600) -/* clang either forgets to define (clang-7) __mips_isa_rev at all - * or sets it to zero (clang-8,-9) for -march=octeon (MIPS64 R2+) - * and -march=p5600 (MIPS32 R5). - * It also sets the __mips macro to 64 or 32 for -mipsN when N <= 5 - * (should be set to N exactly) so we cannot rely on this too. - */ -#define SLJIT_MIPS_REV 1 -#endif - -#endif /* !SLJIT_MIPS_REV */ - -#elif (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X) - -#define SLJIT_BIG_ENDIAN 1 - -#else -#define SLJIT_LITTLE_ENDIAN 1 -#endif - -#endif /* !defined(SLJIT_BIG_ENDIAN) && !defined(SLJIT_LITTLE_ENDIAN) */ - -/* Sanity check. */ -#if (defined SLJIT_BIG_ENDIAN && SLJIT_BIG_ENDIAN) && (defined SLJIT_LITTLE_ENDIAN && SLJIT_LITTLE_ENDIAN) -#error "Exactly one endianness must be selected" -#endif - -#if !(defined SLJIT_BIG_ENDIAN && SLJIT_BIG_ENDIAN) && !(defined SLJIT_LITTLE_ENDIAN && SLJIT_LITTLE_ENDIAN) -#error "Exactly one endianness must be selected" -#endif - -#ifndef SLJIT_UNALIGNED - -#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) \ - || (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) \ - || (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2) \ - || (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) \ - || (defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC) \ - || (defined SLJIT_CONFIG_RISCV && SLJIT_CONFIG_RISCV) \ - || (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X) -#define SLJIT_UNALIGNED 1 -#endif - -#endif /* !SLJIT_UNALIGNED */ - -#ifndef SLJIT_FPU_UNALIGNED - -#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) \ - || (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) \ - || (defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC) \ - || (defined SLJIT_CONFIG_RISCV && SLJIT_CONFIG_RISCV) \ - || (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X) -#define SLJIT_FPU_UNALIGNED 1 -#endif - -#endif /* !SLJIT_FPU_UNALIGNED */ - -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) -/* Auto detect SSE2 support using CPUID. - On 64 bit x86 cpus, sse2 must be present. */ -#define SLJIT_DETECT_SSE2 1 -#endif - -/*****************************************************************************************/ -/* Calling convention of functions generated by SLJIT or called from the generated code. */ -/*****************************************************************************************/ - -#ifndef SLJIT_FUNC -#define SLJIT_FUNC -#endif /* !SLJIT_FUNC */ - -#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) -/* It seems certain ppc compilers use an indirect addressing for functions - which makes things complicated. */ -#define SLJIT_INDIRECT_CALL 1 -#endif -#endif /* SLJIT_INDIRECT_CALL */ - -/* The offset which needs to be subtracted from the return address to -determine the next executed instruction after return. */ -#ifndef SLJIT_RETURN_ADDRESS_OFFSET -#define SLJIT_RETURN_ADDRESS_OFFSET 0 -#endif /* SLJIT_RETURN_ADDRESS_OFFSET */ - -/***************************************************/ -/* Functions of the built-in executable allocator. */ -/***************************************************/ - -#if (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR) -SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size); -SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr); -SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void); -#define SLJIT_BUILTIN_MALLOC_EXEC(size, exec_allocator_data) sljit_malloc_exec(size) -#define SLJIT_BUILTIN_FREE_EXEC(ptr, exec_allocator_data) sljit_free_exec(ptr) - -#ifndef SLJIT_MALLOC_EXEC -#define SLJIT_MALLOC_EXEC(size, exec_allocator_data) SLJIT_BUILTIN_MALLOC_EXEC((size), (exec_allocator_data)) -#endif /* SLJIT_MALLOC_EXEC */ - -#ifndef SLJIT_FREE_EXEC -#define SLJIT_FREE_EXEC(ptr, exec_allocator_data) SLJIT_BUILTIN_FREE_EXEC((ptr), (exec_allocator_data)) -#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) -#else -#define SLJIT_EXEC_OFFSET(ptr) 0 -#endif - -#endif /* SLJIT_EXECUTABLE_ALLOCATOR */ - -/**********************************************/ -/* Registers and locals offset determination. */ -/**********************************************/ - -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - -#define SLJIT_NUMBER_OF_REGISTERS 12 -#define SLJIT_NUMBER_OF_SAVED_REGISTERS 7 -#define SLJIT_NUMBER_OF_FLOAT_REGISTERS 7 -#define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 0 -#define SLJIT_LOCALS_OFFSET_BASE (8 * SSIZE_OF(sw)) -#define SLJIT_PREF_SHIFT_REG SLJIT_R2 - -#elif (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - -#define SLJIT_NUMBER_OF_REGISTERS 13 -#define SLJIT_NUMBER_OF_FLOAT_REGISTERS 15 -#ifndef _WIN64 -#define SLJIT_NUMBER_OF_SAVED_REGISTERS 6 -#define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 0 -#define SLJIT_LOCALS_OFFSET_BASE 0 -#else /* _WIN64 */ -#define SLJIT_NUMBER_OF_SAVED_REGISTERS 8 -#define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 10 -#define SLJIT_LOCALS_OFFSET_BASE (4 * SSIZE_OF(sw)) -#endif /* !_WIN64 */ -#define SLJIT_PREF_SHIFT_REG SLJIT_R3 - -#elif (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) || (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) - -#define SLJIT_NUMBER_OF_REGISTERS 12 -#define SLJIT_NUMBER_OF_SAVED_REGISTERS 8 -#define SLJIT_NUMBER_OF_FLOAT_REGISTERS 14 -#define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 8 -#define SLJIT_LOCALS_OFFSET_BASE 0 - -#elif (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2) - -#define SLJIT_NUMBER_OF_REGISTERS 12 -#define SLJIT_NUMBER_OF_SAVED_REGISTERS 8 -#define SLJIT_NUMBER_OF_FLOAT_REGISTERS 14 -#define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 8 -#define SLJIT_LOCALS_OFFSET_BASE 0 - -#elif (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) - -#define SLJIT_NUMBER_OF_REGISTERS 26 -#define SLJIT_NUMBER_OF_SAVED_REGISTERS 10 -#define SLJIT_NUMBER_OF_FLOAT_REGISTERS 30 -#define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 8 -#define SLJIT_LOCALS_OFFSET_BASE (2 * (sljit_s32)sizeof(sljit_sw)) - -#elif (defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC) - -#define SLJIT_NUMBER_OF_REGISTERS 23 -#define SLJIT_NUMBER_OF_SAVED_REGISTERS 17 -#define SLJIT_NUMBER_OF_FLOAT_REGISTERS 30 -#define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 18 -#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) -/* Add +1 for double alignment. */ -#define SLJIT_LOCALS_OFFSET_BASE ((3 + 1) * (sljit_s32)sizeof(sljit_sw)) -#else -#define SLJIT_LOCALS_OFFSET_BASE (3 * (sljit_s32)sizeof(sljit_sw)) -#endif /* SLJIT_CONFIG_PPC_64 || _AIX */ - -#elif (defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS) - -#define SLJIT_NUMBER_OF_REGISTERS 21 -#define SLJIT_NUMBER_OF_SAVED_REGISTERS 8 -#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) -#define SLJIT_LOCALS_OFFSET_BASE (4 * (sljit_s32)sizeof(sljit_sw)) -#define SLJIT_NUMBER_OF_FLOAT_REGISTERS 13 -#define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 6 -#else -#define SLJIT_LOCALS_OFFSET_BASE 0 -#define SLJIT_NUMBER_OF_FLOAT_REGISTERS 29 -#define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 8 -#endif - -#elif (defined SLJIT_CONFIG_RISCV && SLJIT_CONFIG_RISCV) - -#define SLJIT_NUMBER_OF_REGISTERS 23 -#define SLJIT_NUMBER_OF_SAVED_REGISTERS 12 -#define SLJIT_LOCALS_OFFSET_BASE 0 -#define SLJIT_NUMBER_OF_FLOAT_REGISTERS 30 -#define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 12 - -#elif (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X) - -/* - * https://refspecs.linuxbase.org/ELF/zSeries/lzsabi0_zSeries.html#STACKFRAME - * - * 160 - * .. FR6 - * .. FR4 - * .. FR2 - * 128 FR0 - * 120 R15 (used for SP) - * 112 R14 - * 104 R13 - * 96 R12 - * .. - * 48 R6 - * .. - * 16 R2 - * 8 RESERVED - * 0 SP - */ -#define SLJIT_S390X_DEFAULT_STACK_FRAME_SIZE 160 - -#define SLJIT_NUMBER_OF_REGISTERS 12 -#define SLJIT_NUMBER_OF_SAVED_REGISTERS 8 -#define SLJIT_NUMBER_OF_FLOAT_REGISTERS 15 -#define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 8 -#define SLJIT_LOCALS_OFFSET_BASE SLJIT_S390X_DEFAULT_STACK_FRAME_SIZE - -#elif (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED) - -#define SLJIT_NUMBER_OF_REGISTERS 0 -#define SLJIT_NUMBER_OF_SAVED_REGISTERS 0 -#define SLJIT_NUMBER_OF_FLOAT_REGISTERS 0 -#define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 0 -#define SLJIT_LOCALS_OFFSET_BASE 0 - -#endif - -#define SLJIT_LOCALS_OFFSET (SLJIT_LOCALS_OFFSET_BASE) - -#define SLJIT_NUMBER_OF_SCRATCH_REGISTERS \ - (SLJIT_NUMBER_OF_REGISTERS - SLJIT_NUMBER_OF_SAVED_REGISTERS) - -#define SLJIT_NUMBER_OF_SCRATCH_FLOAT_REGISTERS \ - (SLJIT_NUMBER_OF_FLOAT_REGISTERS - SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS) - -/********************************/ -/* CPU status flags management. */ -/********************************/ - -#if (defined SLJIT_CONFIG_ARM && SLJIT_CONFIG_ARM) \ - || (defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC) \ - || (defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS) \ - || (defined SLJIT_CONFIG_RISCV && SLJIT_CONFIG_RISCV) \ - || (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X) -#define SLJIT_HAS_STATUS_FLAGS_STATE 1 -#endif - -/*************************************/ -/* Debug and verbose related macros. */ -/*************************************/ - -#if (defined SLJIT_DEBUG && SLJIT_DEBUG) - -#if !defined(SLJIT_ASSERT) || !defined(SLJIT_UNREACHABLE) - -/* SLJIT_HALT_PROCESS must halt the process. */ -#ifndef SLJIT_HALT_PROCESS -#define SLJIT_HALT_PROCESS() \ - abort(); -#endif /* !SLJIT_HALT_PROCESS */ - -#endif /* !SLJIT_ASSERT || !SLJIT_UNREACHABLE */ - -/* Feel free to redefine these two macros. */ -#ifndef SLJIT_ASSERT - -#define SLJIT_ASSERT(x) \ - do { \ - if (SLJIT_UNLIKELY(!(x))) { \ - printf("Assertion failed at " __FILE__ ":%d\n", __LINE__); \ - SLJIT_HALT_PROCESS(); \ - } \ - } while (0) - -#endif /* !SLJIT_ASSERT */ - -#ifndef SLJIT_UNREACHABLE - -#define SLJIT_UNREACHABLE() \ - do { \ - printf("Should never been reached " __FILE__ ":%d\n", __LINE__); \ - SLJIT_HALT_PROCESS(); \ - } while (0) - -#endif /* !SLJIT_UNREACHABLE */ - -#else /* (defined SLJIT_DEBUG && SLJIT_DEBUG) */ - -/* Forcing empty, but valid statements. */ -#undef SLJIT_ASSERT -#undef SLJIT_UNREACHABLE - -#define SLJIT_ASSERT(x) \ - do { } while (0) -#define SLJIT_UNREACHABLE() \ - do { } while (0) - -#endif /* (defined SLJIT_DEBUG && SLJIT_DEBUG) */ - -#ifndef SLJIT_COMPILE_ASSERT - -#define SLJIT_COMPILE_ASSERT(x, description) \ - switch(0) { case 0: case ((x) ? 1 : 0): break; } - -#endif /* !SLJIT_COMPILE_ASSERT */ - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* SLJIT_CONFIG_INTERNAL_H_ */ diff --git a/modules/regex/pcre2/src/sljit/sljitExecAllocator.c b/modules/regex/pcre2/src/sljit/sljitExecAllocator.c deleted file mode 100644 index 92d940d..0000000 --- a/modules/regex/pcre2/src/sljit/sljitExecAllocator.c +++ /dev/null @@ -1,411 +0,0 @@ -/* - * 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. - */ - -/* - This file contains a simple executable memory allocator - - It is assumed, that executable code blocks are usually medium (or sometimes - large) memory blocks, and the allocator is not too frequently called (less - optimized than other allocators). Thus, using it as a generic allocator is - not suggested. - - How does it work: - Memory is allocated in continuous memory areas called chunks by alloc_chunk() - Chunk format: - [ block ][ block ] ... [ block ][ block terminator ] - - All blocks and the block terminator is started with block_header. The block - header contains the size of the previous and the next block. These sizes - can also contain special values. - Block size: - 0 - The block is a free_block, with a different size member. - 1 - The block is a block terminator. - n - The block is used at the moment, and the value contains its size. - Previous block size: - 0 - This is the first block of the memory chunk. - n - The size of the previous block. - - Using these size values we can go forward or backward on the block chain. - The unused blocks are stored in a chain list pointed by free_blocks. This - list is useful if we need to find a suitable memory area when the allocator - is called. - - When a block is freed, the new free block is connected to its adjacent free - blocks if possible. - - [ free block ][ used block ][ free block ] - and "used block" is freed, the three blocks are connected together: - [ one big free block ] -*/ - -/* --------------------------------------------------------------------- */ -/* System (OS) functions */ -/* --------------------------------------------------------------------- */ - -/* 64 KByte. */ -#define CHUNK_SIZE (sljit_uw)0x10000u - -/* - alloc_chunk / free_chunk : - * allocate executable system memory chunks - * the size is always divisible by CHUNK_SIZE - SLJIT_ALLOCATOR_LOCK / SLJIT_ALLOCATOR_UNLOCK : - * provided as part of sljitUtils - * only the allocator requires this lock, sljit is fully thread safe - as it only uses local variables -*/ - -#ifdef _WIN32 -#define SLJIT_UPDATE_WX_FLAGS(from, to, enable_exec) - -static SLJIT_INLINE void* alloc_chunk(sljit_uw size) -{ - return VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); -} - -static SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size) -{ - SLJIT_UNUSED_ARG(size); - VirtualFree(chunk, 0, MEM_RELEASE); -} - -#else /* POSIX */ - -#if defined(__APPLE__) && defined(MAP_JIT) -/* - On macOS systems, returns MAP_JIT if it is defined _and_ we're running on a - version where it's OK to have more than one JIT block or where MAP_JIT is - required. - On non-macOS systems, returns MAP_JIT if it is defined. -*/ -#include -#if TARGET_OS_OSX -#if defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86 -#ifdef MAP_ANON -#include -#include - -#define SLJIT_MAP_JIT (get_map_jit_flag()) - -static SLJIT_INLINE int get_map_jit_flag() -{ - size_t page_size; - void *ptr; - struct utsname name; - static int map_jit_flag = -1; - - if (map_jit_flag < 0) { - map_jit_flag = 0; - uname(&name); - - /* Kernel version for 10.14.0 (Mojave) or later */ - if (atoi(name.release) >= 18) { - page_size = get_page_alignment() + 1; - /* Only use MAP_JIT if a hardened runtime is used */ - ptr = mmap(NULL, page_size, PROT_WRITE | PROT_EXEC, - MAP_PRIVATE | MAP_ANON, -1, 0); - - if (ptr != MAP_FAILED) - munmap(ptr, page_size); - else - map_jit_flag = MAP_JIT; - } - } - return map_jit_flag; -} -#endif /* MAP_ANON */ -#else /* !SLJIT_CONFIG_X86 */ -#if !(defined SLJIT_CONFIG_ARM && SLJIT_CONFIG_ARM) -#error "Unsupported architecture" -#endif /* SLJIT_CONFIG_ARM */ -#include -#include - -#define SLJIT_MAP_JIT (MAP_JIT) -#define SLJIT_UPDATE_WX_FLAGS(from, to, enable_exec) \ - apple_update_wx_flags(enable_exec) - -static SLJIT_INLINE void apple_update_wx_flags(sljit_s32 enable_exec) -{ -#if MAC_OS_X_VERSION_MIN_REQUIRED >= 110000 - pthread_jit_write_protect_np(enable_exec); -#else -#error "Must target Big Sur or newer" -#endif /* BigSur */ -} -#endif /* SLJIT_CONFIG_X86 */ -#else /* !TARGET_OS_OSX */ -#define SLJIT_MAP_JIT (MAP_JIT) -#endif /* TARGET_OS_OSX */ -#endif /* __APPLE__ && MAP_JIT */ -#ifndef SLJIT_UPDATE_WX_FLAGS -#define SLJIT_UPDATE_WX_FLAGS(from, to, enable_exec) -#endif /* !SLJIT_UPDATE_WX_FLAGS */ -#ifndef SLJIT_MAP_JIT -#define SLJIT_MAP_JIT (0) -#endif /* !SLJIT_MAP_JIT */ - -static SLJIT_INLINE void* alloc_chunk(sljit_uw size) -{ - void *retval; - int prot = PROT_READ | PROT_WRITE | PROT_EXEC; - int flags = MAP_PRIVATE; - int fd = -1; - -#ifdef PROT_MAX - prot |= PROT_MAX(prot); -#endif - -#ifdef MAP_ANON - flags |= MAP_ANON | SLJIT_MAP_JIT; -#else /* !MAP_ANON */ - if (SLJIT_UNLIKELY((dev_zero < 0) && open_dev_zero())) - return NULL; - - fd = dev_zero; -#endif /* MAP_ANON */ - - retval = mmap(NULL, size, prot, flags, fd, 0); - if (retval == MAP_FAILED) - return NULL; - -#ifdef __FreeBSD__ - /* HardenedBSD's mmap lies, so check permissions again */ - if (mprotect(retval, size, PROT_READ | PROT_WRITE | PROT_EXEC) < 0) { - munmap(retval, size); - return NULL; - } -#endif /* FreeBSD */ - - SLJIT_UPDATE_WX_FLAGS(retval, (uint8_t *)retval + size, 0); - - return retval; -} - -static SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size) -{ - munmap(chunk, size); -} - -#endif /* windows */ - -/* --------------------------------------------------------------------- */ -/* Common functions */ -/* --------------------------------------------------------------------- */ - -#define CHUNK_MASK (~(CHUNK_SIZE - 1)) - -struct block_header { - sljit_uw size; - sljit_uw prev_size; -}; - -struct free_block { - struct block_header header; - struct free_block *next; - struct free_block *prev; - sljit_uw size; -}; - -#define AS_BLOCK_HEADER(base, offset) \ - ((struct block_header*)(((sljit_u8*)base) + offset)) -#define AS_FREE_BLOCK(base, offset) \ - ((struct free_block*)(((sljit_u8*)base) + offset)) -#define MEM_START(base) ((void*)(((sljit_u8*)base) + sizeof(struct block_header))) -#define ALIGN_SIZE(size) (((size) + sizeof(struct block_header) + 7u) & ~(sljit_uw)7) - -static struct free_block* free_blocks; -static sljit_uw allocated_size; -static sljit_uw total_size; - -static SLJIT_INLINE void sljit_insert_free_block(struct free_block *free_block, sljit_uw size) -{ - free_block->header.size = 0; - free_block->size = size; - - free_block->next = free_blocks; - free_block->prev = NULL; - if (free_blocks) - free_blocks->prev = free_block; - free_blocks = free_block; -} - -static SLJIT_INLINE void sljit_remove_free_block(struct free_block *free_block) -{ - if (free_block->next) - free_block->next->prev = free_block->prev; - - if (free_block->prev) - free_block->prev->next = free_block->next; - else { - SLJIT_ASSERT(free_blocks == free_block); - free_blocks = free_block->next; - } -} - -SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size) -{ - struct block_header *header; - struct block_header *next_header; - struct free_block *free_block; - sljit_uw chunk_size; - - SLJIT_ALLOCATOR_LOCK(); - if (size < (64 - sizeof(struct block_header))) - size = (64 - sizeof(struct block_header)); - size = ALIGN_SIZE(size); - - free_block = free_blocks; - while (free_block) { - if (free_block->size >= size) { - chunk_size = free_block->size; - SLJIT_UPDATE_WX_FLAGS(NULL, NULL, 0); - if (chunk_size > size + 64) { - /* We just cut a block from the end of the free block. */ - chunk_size -= size; - free_block->size = chunk_size; - header = AS_BLOCK_HEADER(free_block, chunk_size); - header->prev_size = chunk_size; - AS_BLOCK_HEADER(header, size)->prev_size = size; - } - else { - sljit_remove_free_block(free_block); - header = (struct block_header*)free_block; - size = chunk_size; - } - allocated_size += size; - header->size = size; - SLJIT_ALLOCATOR_UNLOCK(); - return MEM_START(header); - } - free_block = free_block->next; - } - - chunk_size = (size + sizeof(struct block_header) + CHUNK_SIZE - 1) & CHUNK_MASK; - header = (struct block_header*)alloc_chunk(chunk_size); - if (!header) { - SLJIT_ALLOCATOR_UNLOCK(); - return NULL; - } - - chunk_size -= sizeof(struct block_header); - total_size += chunk_size; - - header->prev_size = 0; - if (chunk_size > size + 64) { - /* Cut the allocated space into a free and a used block. */ - allocated_size += size; - header->size = size; - chunk_size -= size; - - free_block = AS_FREE_BLOCK(header, size); - free_block->header.prev_size = size; - sljit_insert_free_block(free_block, chunk_size); - next_header = AS_BLOCK_HEADER(free_block, chunk_size); - } - else { - /* All space belongs to this allocation. */ - allocated_size += chunk_size; - header->size = chunk_size; - next_header = AS_BLOCK_HEADER(header, chunk_size); - } - next_header->size = 1; - next_header->prev_size = chunk_size; - SLJIT_ALLOCATOR_UNLOCK(); - return MEM_START(header); -} - -SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr) -{ - struct block_header *header; - struct free_block* free_block; - - SLJIT_ALLOCATOR_LOCK(); - header = AS_BLOCK_HEADER(ptr, -(sljit_sw)sizeof(struct block_header)); - allocated_size -= header->size; - - /* Connecting free blocks together if possible. */ - SLJIT_UPDATE_WX_FLAGS(NULL, NULL, 0); - - /* If header->prev_size == 0, free_block will equal to header. - In this case, free_block->header.size will be > 0. */ - free_block = AS_FREE_BLOCK(header, -(sljit_sw)header->prev_size); - if (SLJIT_UNLIKELY(!free_block->header.size)) { - free_block->size += header->size; - header = AS_BLOCK_HEADER(free_block, free_block->size); - header->prev_size = free_block->size; - } - else { - free_block = (struct free_block*)header; - sljit_insert_free_block(free_block, header->size); - } - - header = AS_BLOCK_HEADER(free_block, free_block->size); - if (SLJIT_UNLIKELY(!header->size)) { - free_block->size += ((struct free_block*)header)->size; - sljit_remove_free_block((struct free_block*)header); - header = AS_BLOCK_HEADER(free_block, free_block->size); - header->prev_size = free_block->size; - } - - /* The whole chunk is free. */ - if (SLJIT_UNLIKELY(!free_block->header.prev_size && header->size == 1)) { - /* If this block is freed, we still have (allocated_size / 2) free space. */ - if (total_size - free_block->size > (allocated_size * 3 / 2)) { - total_size -= free_block->size; - sljit_remove_free_block(free_block); - free_chunk(free_block, free_block->size + sizeof(struct block_header)); - } - } - - SLJIT_UPDATE_WX_FLAGS(NULL, NULL, 1); - SLJIT_ALLOCATOR_UNLOCK(); -} - -SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void) -{ - struct free_block* free_block; - struct free_block* next_free_block; - - SLJIT_ALLOCATOR_LOCK(); - SLJIT_UPDATE_WX_FLAGS(NULL, NULL, 0); - - free_block = free_blocks; - while (free_block) { - next_free_block = free_block->next; - if (!free_block->header.prev_size && - AS_BLOCK_HEADER(free_block, free_block->size)->size == 1) { - total_size -= free_block->size; - sljit_remove_free_block(free_block); - free_chunk(free_block, free_block->size + sizeof(struct block_header)); - } - free_block = next_free_block; - } - - SLJIT_ASSERT((total_size && free_blocks) || (!total_size && !free_blocks)); - SLJIT_UPDATE_WX_FLAGS(NULL, NULL, 1); - SLJIT_ALLOCATOR_UNLOCK(); -} diff --git a/modules/regex/pcre2/src/sljit/sljitLir.c b/modules/regex/pcre2/src/sljit/sljitLir.c deleted file mode 100644 index abafe1a..0000000 --- a/modules/regex/pcre2/src/sljit/sljitLir.c +++ /dev/null @@ -1,3136 +0,0 @@ -/* - * 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. - */ - -#include "sljitLir.h" - -#ifdef _WIN32 - -#include - -#endif /* _WIN32 */ - -#if !(defined SLJIT_STD_MACROS_DEFINED && SLJIT_STD_MACROS_DEFINED) - -/* These libraries are needed for the macros below. */ -#include -#include - -#endif /* SLJIT_STD_MACROS_DEFINED */ - -#define CHECK_ERROR() \ - do { \ - if (SLJIT_UNLIKELY(compiler->error)) \ - return compiler->error; \ - } while (0) - -#define CHECK_ERROR_PTR() \ - do { \ - if (SLJIT_UNLIKELY(compiler->error)) \ - return NULL; \ - } while (0) - -#define FAIL_IF(expr) \ - do { \ - if (SLJIT_UNLIKELY(expr)) \ - return compiler->error; \ - } while (0) - -#define PTR_FAIL_IF(expr) \ - do { \ - if (SLJIT_UNLIKELY(expr)) \ - return NULL; \ - } while (0) - -#define FAIL_IF_NULL(ptr) \ - do { \ - if (SLJIT_UNLIKELY(!(ptr))) { \ - compiler->error = SLJIT_ERR_ALLOC_FAILED; \ - return SLJIT_ERR_ALLOC_FAILED; \ - } \ - } while (0) - -#define PTR_FAIL_IF_NULL(ptr) \ - do { \ - if (SLJIT_UNLIKELY(!(ptr))) { \ - compiler->error = SLJIT_ERR_ALLOC_FAILED; \ - return NULL; \ - } \ - } while (0) - -#define PTR_FAIL_WITH_EXEC_IF(ptr) \ - do { \ - if (SLJIT_UNLIKELY(!(ptr))) { \ - compiler->error = SLJIT_ERR_EX_ALLOC_FAILED; \ - return NULL; \ - } \ - } while (0) - -#if !(defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED) - -#define SSIZE_OF(type) ((sljit_s32)sizeof(sljit_ ## type)) - -#define VARIABLE_FLAG_SHIFT (10) -#define VARIABLE_FLAG_MASK (0x3f << VARIABLE_FLAG_SHIFT) -#define GET_FLAG_TYPE(op) ((op) >> VARIABLE_FLAG_SHIFT) - -#define GET_OPCODE(op) \ - ((op) & ~(SLJIT_32 | SLJIT_SET_Z | VARIABLE_FLAG_MASK)) - -#define HAS_FLAGS(op) \ - ((op) & (SLJIT_SET_Z | VARIABLE_FLAG_MASK)) - -#define GET_ALL_FLAGS(op) \ - ((op) & (SLJIT_32 | SLJIT_SET_Z | VARIABLE_FLAG_MASK)) - -#if (defined SLJIT_64BIT_ARCHITECTURE && SLJIT_64BIT_ARCHITECTURE) -#define TYPE_CAST_NEEDED(op) \ - ((op) >= SLJIT_MOV_U8 && (op) <= SLJIT_MOV_S32) -#else /* !SLJIT_64BIT_ARCHITECTURE */ -#define TYPE_CAST_NEEDED(op) \ - ((op) >= SLJIT_MOV_U8 && (op) <= SLJIT_MOV_S16) -#endif /* SLJIT_64BIT_ARCHITECTURE */ - -#define BUF_SIZE 4096 - -#if (defined SLJIT_32BIT_ARCHITECTURE && SLJIT_32BIT_ARCHITECTURE) -#define ABUF_SIZE 2048 -#else -#define ABUF_SIZE 4096 -#endif - -/* Parameter parsing. */ -#define REG_MASK 0x3f -#define OFFS_REG(reg) (((reg) >> 8) & REG_MASK) -#define OFFS_REG_MASK (REG_MASK << 8) -#define TO_OFFS_REG(reg) ((reg) << 8) -/* When reg cannot be unused. */ -#define FAST_IS_REG(reg) ((reg) <= REG_MASK) - -/* Mask for argument types. */ -#define SLJIT_ARG_MASK 0x7 -#define SLJIT_ARG_FULL_MASK (SLJIT_ARG_MASK | SLJIT_ARG_TYPE_SCRATCH_REG) - -/* Mask for sljit_emit_mem. */ -#define REG_PAIR_MASK 0xff00 -#define REG_PAIR_FIRST(reg) ((reg) & 0xff) -#define REG_PAIR_SECOND(reg) ((reg) >> 8) - -/* Mask for sljit_emit_enter. */ -#define SLJIT_KEPT_SAVEDS_COUNT(options) ((options) & 0x3) - -/* Jump flags. */ -#define JUMP_LABEL 0x1 -#define JUMP_ADDR 0x2 -/* SLJIT_REWRITABLE_JUMP is 0x1000. */ - -#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) -# define PATCH_MB 0x4 -# define PATCH_MW 0x8 -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) -# define PATCH_MD 0x10 -#endif -# define TYPE_SHIFT 13 -#endif /* SLJIT_CONFIG_X86 */ - -#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) || (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) -# define IS_BL 0x4 -# define PATCH_B 0x8 -#endif /* SLJIT_CONFIG_ARM_V5 || SLJIT_CONFIG_ARM_V7 */ - -#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) -# define CPOOL_SIZE 512 -#endif /* SLJIT_CONFIG_ARM_V5 */ - -#if (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2) -# define IS_COND 0x04 -# define IS_BL 0x08 - /* conditional + imm8 */ -# define PATCH_TYPE1 0x10 - /* conditional + imm20 */ -# define PATCH_TYPE2 0x20 - /* IT + imm24 */ -# define PATCH_TYPE3 0x30 - /* imm11 */ -# define PATCH_TYPE4 0x40 - /* imm24 */ -# define PATCH_TYPE5 0x50 - /* BL + imm24 */ -# define PATCH_BL 0x60 - /* 0xf00 cc code for branches */ -#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 -#endif /* SLJIT_CONFIG_ARM_64 */ - -#if (defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC) -# define IS_COND 0x004 -# define IS_CALL 0x008 -# define PATCH_B 0x010 -# define PATCH_ABS_B 0x020 -#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) -# define PATCH_ABS32 0x040 -# define PATCH_ABS48 0x080 -#endif /* SLJIT_CONFIG_PPC_64 */ -# define REMOVE_COND 0x100 -#endif /* SLJIT_CONFIG_PPC */ - -#if (defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS) -# define IS_MOVABLE 0x004 -# define IS_JAL 0x008 -# define IS_CALL 0x010 -# define IS_BIT26_COND 0x020 -# define IS_BIT16_COND 0x040 -# define IS_BIT23_COND 0x080 - -# define IS_COND (IS_BIT26_COND | IS_BIT16_COND | IS_BIT23_COND) - -# define PATCH_B 0x100 -# define PATCH_J 0x200 - -#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) -# define PATCH_ABS32 0x400 -# define PATCH_ABS48 0x800 -#endif /* SLJIT_CONFIG_MIPS_64 */ - - /* instruction types */ -# define MOVABLE_INS 0 - /* 1 - 31 last destination register */ - /* no destination (i.e: store) */ -# define UNMOVABLE_INS 32 - /* FPU status register */ -# define FCSR_FCC 33 -#endif /* SLJIT_CONFIG_MIPS */ - -#if (defined SLJIT_CONFIG_RISCV && SLJIT_CONFIG_RISCV) -# define IS_COND 0x004 -# define IS_CALL 0x008 - -# define PATCH_B 0x010 -# define PATCH_J 0x020 - -#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64) -# define PATCH_REL32 0x040 -# define PATCH_ABS32 0x080 -# define PATCH_ABS44 0x100 -# define PATCH_ABS52 0x200 -#else /* !SLJIT_CONFIG_RISCV_64 */ -# define PATCH_REL32 0x0 -#endif /* SLJIT_CONFIG_RISCV_64 */ -#endif /* SLJIT_CONFIG_RISCV */ - -/* Stack management. */ - -#define GET_SAVED_REGISTERS_SIZE(scratches, saveds, extra) \ - (((scratches < SLJIT_NUMBER_OF_SCRATCH_REGISTERS ? 0 : (scratches - SLJIT_NUMBER_OF_SCRATCH_REGISTERS)) + \ - (saveds) + (sljit_s32)(extra)) * (sljit_s32)sizeof(sljit_sw)) - -#define GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, size) \ - (((fscratches < SLJIT_NUMBER_OF_SCRATCH_FLOAT_REGISTERS ? 0 : (fscratches - SLJIT_NUMBER_OF_SCRATCH_FLOAT_REGISTERS)) + \ - (fsaveds)) * (sljit_s32)(size)) - -#define ADJUST_LOCAL_OFFSET(p, i) \ - if ((p) == (SLJIT_MEM1(SLJIT_SP))) \ - (i) += SLJIT_LOCALS_OFFSET; - -#endif /* !(defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED) */ - -/* Utils can still be used even if SLJIT_CONFIG_UNSUPPORTED is set. */ -#include "sljitUtils.c" - -#if !(defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED) - -#if (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR) - -#if (defined SLJIT_PROT_EXECUTABLE_ALLOCATOR && SLJIT_PROT_EXECUTABLE_ALLOCATOR) -#include "sljitProtExecAllocator.c" -#elif (defined SLJIT_WX_EXECUTABLE_ALLOCATOR && SLJIT_WX_EXECUTABLE_ALLOCATOR) -#include "sljitWXExecAllocator.c" -#else -#include "sljitExecAllocator.c" -#endif - -#endif - -#if (defined SLJIT_PROT_EXECUTABLE_ALLOCATOR && SLJIT_PROT_EXECUTABLE_ALLOCATOR) -#define SLJIT_ADD_EXEC_OFFSET(ptr, exec_offset) ((sljit_u8 *)(ptr) + (exec_offset)) -#else -#define SLJIT_ADD_EXEC_OFFSET(ptr, exec_offset) ((sljit_u8 *)(ptr)) -#endif - -#ifndef SLJIT_UPDATE_WX_FLAGS -#define SLJIT_UPDATE_WX_FLAGS(from, to, enable_exec) -#endif - -/* Argument checking features. */ - -#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) - -/* Returns with error when an invalid argument is passed. */ - -#define CHECK_ARGUMENT(x) \ - do { \ - if (SLJIT_UNLIKELY(!(x))) \ - return 1; \ - } while (0) - -#define CHECK_RETURN_TYPE sljit_s32 -#define CHECK_RETURN_OK return 0 - -#define CHECK(x) \ - do { \ - if (SLJIT_UNLIKELY(x)) { \ - compiler->error = SLJIT_ERR_BAD_ARGUMENT; \ - return SLJIT_ERR_BAD_ARGUMENT; \ - } \ - } while (0) - -#define CHECK_PTR(x) \ - do { \ - if (SLJIT_UNLIKELY(x)) { \ - compiler->error = SLJIT_ERR_BAD_ARGUMENT; \ - return NULL; \ - } \ - } while (0) - -#define CHECK_REG_INDEX(x) \ - do { \ - if (SLJIT_UNLIKELY(x)) { \ - return -2; \ - } \ - } while (0) - -#elif (defined SLJIT_DEBUG && SLJIT_DEBUG) - -/* Assertion failure occures if an invalid argument is passed. */ -#undef SLJIT_ARGUMENT_CHECKS -#define SLJIT_ARGUMENT_CHECKS 1 - -#define CHECK_ARGUMENT(x) SLJIT_ASSERT(x) -#define CHECK_RETURN_TYPE void -#define CHECK_RETURN_OK return -#define CHECK(x) x -#define CHECK_PTR(x) x -#define CHECK_REG_INDEX(x) x - -#elif (defined SLJIT_VERBOSE && SLJIT_VERBOSE) - -/* Arguments are not checked. */ -#define CHECK_RETURN_TYPE void -#define CHECK_RETURN_OK return -#define CHECK(x) x -#define CHECK_PTR(x) x -#define CHECK_REG_INDEX(x) x - -#else - -/* Arguments are not checked. */ -#define CHECK(x) -#define CHECK_PTR(x) -#define CHECK_REG_INDEX(x) - -#endif /* SLJIT_ARGUMENT_CHECKS */ - -/* --------------------------------------------------------------------- */ -/* Public functions */ -/* --------------------------------------------------------------------- */ - -#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) -#define SLJIT_NEEDS_COMPILER_INIT 1 -static sljit_s32 compiler_initialized = 0; -/* A thread safe initialization. */ -static void init_compiler(void); -#endif - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_compiler* sljit_create_compiler(void *allocator_data, void *exec_allocator_data) -{ - struct sljit_compiler *compiler = (struct sljit_compiler*)SLJIT_MALLOC(sizeof(struct sljit_compiler), allocator_data); - if (!compiler) - return NULL; - SLJIT_ZEROMEM(compiler, sizeof(struct sljit_compiler)); - - SLJIT_COMPILE_ASSERT( - 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_sw) == 4 || sizeof(sljit_sw) == 8) - && (sizeof(sljit_uw) == 4 || sizeof(sljit_uw) == 8), - invalid_integer_types); - SLJIT_COMPILE_ASSERT(SLJIT_REWRITABLE_JUMP != SLJIT_32, - rewritable_jump_and_single_op_must_not_be_the_same); - SLJIT_COMPILE_ASSERT(!(SLJIT_EQUAL & 0x1) && !(SLJIT_LESS & 0x1) && !(SLJIT_F_EQUAL & 0x1) && !(SLJIT_JUMP & 0x1), - conditional_flags_must_be_even_numbers); - - /* Only the non-zero members must be set. */ - 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); - - if (!compiler->buf || !compiler->abuf) { - if (compiler->buf) - SLJIT_FREE(compiler->buf, allocator_data); - if (compiler->abuf) - SLJIT_FREE(compiler->abuf, allocator_data); - SLJIT_FREE(compiler, allocator_data); - return NULL; - } - - compiler->buf->next = NULL; - compiler->buf->used_size = 0; - compiler->abuf->next = NULL; - compiler->abuf->used_size = 0; - - compiler->scratches = -1; - compiler->saveds = -1; - compiler->fscratches = -1; - compiler->fsaveds = -1; - compiler->local_size = -1; - -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - compiler->args_size = -1; -#endif - -#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) - compiler->cpool = (sljit_uw*)SLJIT_MALLOC(CPOOL_SIZE * sizeof(sljit_uw) - + CPOOL_SIZE * sizeof(sljit_u8), allocator_data); - if (!compiler->cpool) { - SLJIT_FREE(compiler->buf, allocator_data); - SLJIT_FREE(compiler->abuf, allocator_data); - SLJIT_FREE(compiler, allocator_data); - return NULL; - } - compiler->cpool_unique = (sljit_u8*)(compiler->cpool + CPOOL_SIZE); - compiler->cpool_diff = 0xffffffff; -#endif - -#if (defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS) - compiler->delay_slot = UNMOVABLE_INS; -#endif - -#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) \ - || (defined SLJIT_DEBUG && SLJIT_DEBUG) - compiler->last_flags = 0; - compiler->last_return = -1; - compiler->logical_local_size = 0; -#endif - -#if (defined SLJIT_NEEDS_COMPILER_INIT && SLJIT_NEEDS_COMPILER_INIT) - if (!compiler_initialized) { - init_compiler(); - compiler_initialized = 1; - } -#endif - - return compiler; -} - -SLJIT_API_FUNC_ATTRIBUTE void sljit_free_compiler(struct sljit_compiler *compiler) -{ - struct sljit_memory_fragment *buf; - struct sljit_memory_fragment *curr; - void *allocator_data = compiler->allocator_data; - SLJIT_UNUSED_ARG(allocator_data); - - buf = compiler->buf; - while (buf) { - curr = buf; - buf = buf->next; - SLJIT_FREE(curr, allocator_data); - } - - buf = compiler->abuf; - while (buf) { - curr = buf; - buf = buf->next; - SLJIT_FREE(curr, allocator_data); - } - -#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) - SLJIT_FREE(compiler->cpool, allocator_data); -#endif - SLJIT_FREE(compiler, allocator_data); -} - -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_compiler_memory_error(struct sljit_compiler *compiler) -{ - if (compiler->error == SLJIT_SUCCESS) - 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); -} -#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; - } -} - -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) - -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_current_flags(struct sljit_compiler *compiler, sljit_s32 current_flags) -{ - SLJIT_UNUSED_ARG(compiler); - SLJIT_UNUSED_ARG(current_flags); - -#if (defined SLJIT_HAS_STATUS_FLAGS_STATE && SLJIT_HAS_STATUS_FLAGS_STATE) - compiler->status_flags_state = current_flags; -#endif - -#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) - compiler->last_flags = 0; - if ((current_flags & ~(VARIABLE_FLAG_MASK | SLJIT_SET_Z | SLJIT_CURRENT_FLAGS_ALL)) == 0) { - compiler->last_flags = GET_FLAG_TYPE(current_flags) | (current_flags & (SLJIT_32 | SLJIT_SET_Z)); - } -#endif -} - -/* --------------------------------------------------------------------- */ -/* Private functions */ -/* --------------------------------------------------------------------- */ - -static void* ensure_buf(struct sljit_compiler *compiler, sljit_uw size) -{ - sljit_u8 *ret; - struct sljit_memory_fragment *new_frag; - - SLJIT_ASSERT(size <= 256); - if (compiler->buf->used_size + size <= (BUF_SIZE - (sljit_uw)SLJIT_OFFSETOF(struct sljit_memory_fragment, memory))) { - ret = compiler->buf->memory + compiler->buf->used_size; - compiler->buf->used_size += size; - return ret; - } - new_frag = (struct sljit_memory_fragment*)SLJIT_MALLOC(BUF_SIZE, compiler->allocator_data); - PTR_FAIL_IF_NULL(new_frag); - new_frag->next = compiler->buf; - compiler->buf = new_frag; - new_frag->used_size = size; - return new_frag->memory; -} - -static void* ensure_abuf(struct sljit_compiler *compiler, sljit_uw size) -{ - sljit_u8 *ret; - struct sljit_memory_fragment *new_frag; - - SLJIT_ASSERT(size <= 256); - if (compiler->abuf->used_size + size <= (ABUF_SIZE - (sljit_uw)SLJIT_OFFSETOF(struct sljit_memory_fragment, memory))) { - ret = compiler->abuf->memory + compiler->abuf->used_size; - compiler->abuf->used_size += size; - return ret; - } - new_frag = (struct sljit_memory_fragment*)SLJIT_MALLOC(ABUF_SIZE, compiler->allocator_data); - PTR_FAIL_IF_NULL(new_frag); - new_frag->next = compiler->abuf; - compiler->abuf = new_frag; - new_frag->used_size = size; - return new_frag->memory; -} - -SLJIT_API_FUNC_ATTRIBUTE void* sljit_alloc_memory(struct sljit_compiler *compiler, sljit_s32 size) -{ - CHECK_ERROR_PTR(); - -#if (defined SLJIT_64BIT_ARCHITECTURE && SLJIT_64BIT_ARCHITECTURE) - if (size <= 0 || size > 128) - return NULL; - size = (size + 7) & ~7; -#else - if (size <= 0 || size > 64) - return NULL; - size = (size + 3) & ~3; -#endif - return ensure_abuf(compiler, (sljit_uw)size); -} - -static SLJIT_INLINE void reverse_buf(struct sljit_compiler *compiler) -{ - struct sljit_memory_fragment *buf = compiler->buf; - struct sljit_memory_fragment *prev = NULL; - struct sljit_memory_fragment *tmp; - - do { - tmp = buf->next; - buf->next = prev; - prev = buf; - buf = tmp; - } while (buf != NULL); - - 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) -{ - sljit_uw result = ~(sljit_uw)0; - - if (label) - result = label->size; - - if (jump && jump->addr < result) - result = jump->addr; - - if (const_ && const_->addr < result) - result = const_->addr; - - if (put_label && put_label->addr < result) - result = put_label->addr; - - return result; -} - -#endif /* !SLJIT_CONFIG_X86 && !SLJIT_CONFIG_S390X */ - -static SLJIT_INLINE void set_emit_enter(struct sljit_compiler *compiler, - sljit_s32 options, sljit_s32 args, sljit_s32 scratches, sljit_s32 saveds, - sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size) -{ - SLJIT_UNUSED_ARG(args); - SLJIT_UNUSED_ARG(local_size); - - compiler->options = options; - compiler->scratches = scratches; - compiler->saveds = saveds; - compiler->fscratches = fscratches; - compiler->fsaveds = fsaveds; -#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) - compiler->last_return = args & SLJIT_ARG_MASK; - compiler->logical_local_size = local_size; -#endif -} - -static SLJIT_INLINE void set_set_context(struct sljit_compiler *compiler, - sljit_s32 options, sljit_s32 args, sljit_s32 scratches, sljit_s32 saveds, - sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size) -{ - SLJIT_UNUSED_ARG(args); - SLJIT_UNUSED_ARG(local_size); - - compiler->options = options; - compiler->scratches = scratches; - compiler->saveds = saveds; - compiler->fscratches = fscratches; - compiler->fsaveds = fsaveds; -#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) - compiler->last_return = args & SLJIT_ARG_MASK; - compiler->logical_local_size = local_size; -#endif -} - -static SLJIT_INLINE void set_label(struct sljit_label *label, struct sljit_compiler *compiler) -{ - label->next = NULL; - label->size = compiler->size; - if (compiler->last_label) - compiler->last_label->next = label; - else - compiler->labels = label; - compiler->last_label = label; -} - -static SLJIT_INLINE void set_jump(struct sljit_jump *jump, struct sljit_compiler *compiler, sljit_u32 flags) -{ - jump->next = NULL; - jump->flags = flags; - if (compiler->last_jump) - compiler->last_jump->next = jump; - else - compiler->jumps = jump; - compiler->last_jump = jump; -} - -static SLJIT_INLINE void set_const(struct sljit_const *const_, struct sljit_compiler *compiler) -{ - const_->next = NULL; - const_->addr = compiler->size; - if (compiler->last_const) - 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)) - -#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) - -static sljit_s32 function_check_arguments(sljit_s32 arg_types, sljit_s32 scratches, sljit_s32 saveds, sljit_s32 fscratches) -{ - sljit_s32 word_arg_count, scratch_arg_end, saved_arg_count, float_arg_count, curr_type; - - curr_type = (arg_types & SLJIT_ARG_FULL_MASK); - - if (curr_type >= SLJIT_ARG_TYPE_F64) { - if (curr_type > SLJIT_ARG_TYPE_F32 || fscratches == 0) - return 0; - } else if (curr_type >= SLJIT_ARG_TYPE_W) { - if (scratches == 0) - return 0; - } - - arg_types >>= SLJIT_ARG_SHIFT; - - word_arg_count = 0; - scratch_arg_end = 0; - saved_arg_count = 0; - float_arg_count = 0; - while (arg_types != 0) { - if (word_arg_count + float_arg_count >= 4) - return 0; - - curr_type = (arg_types & SLJIT_ARG_MASK); - - if (arg_types & SLJIT_ARG_TYPE_SCRATCH_REG) { - if (saveds == -1 || curr_type < SLJIT_ARG_TYPE_W || curr_type > SLJIT_ARG_TYPE_P) - return 0; - - word_arg_count++; - scratch_arg_end = word_arg_count; - } else { - if (curr_type < SLJIT_ARG_TYPE_W || curr_type > SLJIT_ARG_TYPE_F32) - return 0; - - if (curr_type < SLJIT_ARG_TYPE_F64) { - word_arg_count++; - saved_arg_count++; - } else - float_arg_count++; - } - - arg_types >>= SLJIT_ARG_SHIFT; - } - - if (saveds == -1) - return (word_arg_count <= scratches && float_arg_count <= fscratches); - - return (saved_arg_count <= saveds && scratch_arg_end <= scratches && float_arg_count <= fscratches); -} - -#define FUNCTION_CHECK_IS_REG(r) \ - (((r) >= SLJIT_R0 && (r) < (SLJIT_R0 + compiler->scratches)) \ - || ((r) > (SLJIT_S0 - compiler->saveds) && (r) <= SLJIT_S0)) - -#define FUNCTION_CHECK_IS_FREG(fr) \ - (((fr) >= SLJIT_FR0 && (fr) < (SLJIT_FR0 + compiler->fscratches)) \ - || ((fr) > (SLJIT_FS0 - compiler->fsaveds) && (fr) <= SLJIT_FS0)) - -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) -#define CHECK_IF_VIRTUAL_REGISTER(p) ((p) <= SLJIT_S3 && (p) >= SLJIT_S8) -#else -#define CHECK_IF_VIRTUAL_REGISTER(p) 0 -#endif - -static sljit_s32 function_check_src_mem(struct sljit_compiler *compiler, sljit_s32 p, sljit_sw i) -{ - if (compiler->scratches == -1 || compiler->saveds == -1) - return 0; - - if (!(p & SLJIT_MEM)) - return 0; - - if (p == SLJIT_MEM1(SLJIT_SP)) - return (i >= 0 && i < compiler->logical_local_size); - - if (!(!(p & REG_MASK) || FUNCTION_CHECK_IS_REG(p & REG_MASK))) - return 0; - - if (CHECK_IF_VIRTUAL_REGISTER(p & REG_MASK)) - return 0; - - if (p & OFFS_REG_MASK) { - if (!(p & REG_MASK)) - return 0; - - if (!(FUNCTION_CHECK_IS_REG(OFFS_REG(p)))) - return 0; - - if (CHECK_IF_VIRTUAL_REGISTER(OFFS_REG(p))) - return 0; - - if ((i & ~0x3) != 0) - return 0; - } - - return (p & ~(SLJIT_MEM | REG_MASK | OFFS_REG_MASK)) == 0; -} - -#define FUNCTION_CHECK_SRC_MEM(p, i) \ - CHECK_ARGUMENT(function_check_src_mem(compiler, p, i)); - -static sljit_s32 function_check_src(struct sljit_compiler *compiler, sljit_s32 p, sljit_sw i) -{ - if (compiler->scratches == -1 || compiler->saveds == -1) - return 0; - - if (FUNCTION_CHECK_IS_REG(p)) - return (i == 0); - - if (p == SLJIT_IMM) - return 1; - - return function_check_src_mem(compiler, p, i); -} - -#define FUNCTION_CHECK_SRC(p, i) \ - CHECK_ARGUMENT(function_check_src(compiler, p, i)); - -static sljit_s32 function_check_dst(struct sljit_compiler *compiler, sljit_s32 p, sljit_sw i) -{ - if (compiler->scratches == -1 || compiler->saveds == -1) - return 0; - - if (FUNCTION_CHECK_IS_REG(p)) - return (i == 0); - - return function_check_src_mem(compiler, p, i); -} - -#define FUNCTION_CHECK_DST(p, i) \ - CHECK_ARGUMENT(function_check_dst(compiler, p, i)); - -static sljit_s32 function_fcheck(struct sljit_compiler *compiler, sljit_s32 p, sljit_sw i) -{ - if (compiler->scratches == -1 || compiler->saveds == -1) - return 0; - - if (FUNCTION_CHECK_IS_FREG(p)) - return (i == 0); - - return function_check_src_mem(compiler, p, i); -} - -#define FUNCTION_FCHECK(p, i) \ - CHECK_ARGUMENT(function_fcheck(compiler, p, i)); - -#endif /* SLJIT_ARGUMENT_CHECKS */ - -#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) - -SLJIT_API_FUNC_ATTRIBUTE void sljit_compiler_verbose(struct sljit_compiler *compiler, FILE* verbose) -{ - compiler->verbose = verbose; -} - -#if (defined SLJIT_64BIT_ARCHITECTURE && SLJIT_64BIT_ARCHITECTURE) -#ifdef _WIN64 -#ifdef __GNUC__ -# define SLJIT_PRINT_D "ll" -#else -# define SLJIT_PRINT_D "I64" -#endif -#else -# define SLJIT_PRINT_D "l" -#endif -#else -# define SLJIT_PRINT_D "" -#endif - -static void sljit_verbose_reg(struct sljit_compiler *compiler, sljit_s32 r) -{ - if (r < (SLJIT_R0 + compiler->scratches)) - fprintf(compiler->verbose, "r%d", r - SLJIT_R0); - else if (r != SLJIT_SP) - fprintf(compiler->verbose, "s%d", SLJIT_NUMBER_OF_REGISTERS - r); - else - fprintf(compiler->verbose, "sp"); -} - -static void sljit_verbose_freg(struct sljit_compiler *compiler, sljit_s32 r) -{ - if (r < (SLJIT_FR0 + compiler->fscratches)) - fprintf(compiler->verbose, "fr%d", r - SLJIT_FR0); - else - fprintf(compiler->verbose, "fs%d", SLJIT_NUMBER_OF_FLOAT_REGISTERS - r); -} - -static void sljit_verbose_param(struct sljit_compiler *compiler, sljit_s32 p, sljit_sw i) -{ - if ((p) & SLJIT_IMM) - fprintf(compiler->verbose, "#%" SLJIT_PRINT_D "d", (i)); - else if ((p) & SLJIT_MEM) { - if ((p) & REG_MASK) { - fputc('[', compiler->verbose); - sljit_verbose_reg(compiler, (p) & REG_MASK); - if ((p) & OFFS_REG_MASK) { - fprintf(compiler->verbose, " + "); - sljit_verbose_reg(compiler, OFFS_REG(p)); - if (i) - fprintf(compiler->verbose, " * %d", 1 << (i)); - } - else if (i) - fprintf(compiler->verbose, " + %" SLJIT_PRINT_D "d", (i)); - fputc(']', compiler->verbose); - } - else - fprintf(compiler->verbose, "[#%" SLJIT_PRINT_D "d]", (i)); - } else - sljit_verbose_reg(compiler, p); -} - -static void sljit_verbose_fparam(struct sljit_compiler *compiler, sljit_s32 p, sljit_sw i) -{ - if ((p) & SLJIT_MEM) { - if ((p) & REG_MASK) { - fputc('[', compiler->verbose); - sljit_verbose_reg(compiler, (p) & REG_MASK); - if ((p) & OFFS_REG_MASK) { - fprintf(compiler->verbose, " + "); - sljit_verbose_reg(compiler, OFFS_REG(p)); - if (i) - fprintf(compiler->verbose, "%d", 1 << (i)); - } - else if (i) - fprintf(compiler->verbose, " + %" SLJIT_PRINT_D "d", (i)); - fputc(']', compiler->verbose); - } - else - fprintf(compiler->verbose, "[#%" SLJIT_PRINT_D "d]", (i)); - } - else - sljit_verbose_freg(compiler, p); -} - -static const char* op0_names[] = { - "breakpoint", "nop", "lmul.uw", "lmul.sw", - "divmod.u", "divmod.s", "div.u", "div.s", - "endbr", "skip_frames_before_return" -}; - -static const char* op1_names[] = { - "", ".u8", ".s8", ".u16", - ".s16", ".u32", ".s32", "32", - ".p", "not", "clz", "ctz" -}; - -static const char* op2_names[] = { - "add", "addc", "sub", "subc", - "mul", "and", "or", "xor", - "shl", "mshl", "lshr", "mlshr", - "ashr", "mashr", "rotl", "rotr" -}; - -static const char* op_src_names[] = { - "fast_return", "skip_frames_before_fast_return", - "prefetch_l1", "prefetch_l2", - "prefetch_l3", "prefetch_once", -}; - -static const char* fop1_names[] = { - "mov", "conv", "conv", "conv", - "conv", "conv", "cmp", "neg", - "abs", -}; - -static const char* fop2_names[] = { - "add", "sub", "mul", "div" -}; - -static const char* jump_names[] = { - "equal", "not_equal", - "less", "greater_equal", - "greater", "less_equal", - "sig_less", "sig_greater_equal", - "sig_greater", "sig_less_equal", - "overflow", "not_overflow", - "carry", "", - "f_equal", "f_not_equal", - "f_less", "f_greater_equal", - "f_greater", "f_less_equal", - "unordered", "ordered", - "ordered_equal", "unordered_or_not_equal", - "ordered_less", "unordered_or_greater_equal", - "ordered_greater", "unordered_or_less_equal", - "unordered_or_equal", "ordered_not_equal", - "unordered_or_less", "ordered_greater_equal", - "unordered_or_greater", "ordered_less_equal", - "jump", "fast_call", - "call", "call_reg_arg" -}; - -static const char* call_arg_names[] = { - "void", "w", "32", "p", "f64", "f32" -}; - -#endif /* SLJIT_VERBOSE */ - -/* --------------------------------------------------------------------- */ -/* Arch dependent */ -/* --------------------------------------------------------------------- */ - -#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) \ - || (defined SLJIT_VERBOSE && SLJIT_VERBOSE) - -#define SLJIT_SKIP_CHECKS(compiler) (compiler)->skip_checks = 1 - -static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_generate_code(struct sljit_compiler *compiler) -{ -#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) - struct sljit_jump *jump; -#endif - - SLJIT_UNUSED_ARG(compiler); - -#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) - CHECK_ARGUMENT(compiler->size > 0); - jump = compiler->jumps; - while (jump) { - /* All jumps have target. */ - CHECK_ARGUMENT(jump->flags & (JUMP_LABEL | JUMP_ADDR)); - jump = jump->next; - } -#endif - CHECK_RETURN_OK; -} - -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) -{ - SLJIT_UNUSED_ARG(compiler); - -#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) - if (options & SLJIT_ENTER_REG_ARG) { - CHECK_ARGUMENT(!(options & ~(0x3 | SLJIT_ENTER_REG_ARG))); - } else { - CHECK_ARGUMENT(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); - CHECK_ARGUMENT(saveds >= 0 && saveds <= SLJIT_NUMBER_OF_SAVED_REGISTERS); - CHECK_ARGUMENT(scratches + saveds <= SLJIT_NUMBER_OF_REGISTERS); - CHECK_ARGUMENT(fscratches >= 0 && fscratches <= SLJIT_NUMBER_OF_FLOAT_REGISTERS); - CHECK_ARGUMENT(fsaveds >= 0 && fsaveds <= SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS); - CHECK_ARGUMENT(fscratches + fsaveds <= SLJIT_NUMBER_OF_FLOAT_REGISTERS); - CHECK_ARGUMENT(local_size >= 0 && local_size <= SLJIT_MAX_LOCAL_SIZE); - CHECK_ARGUMENT((arg_types & SLJIT_ARG_FULL_MASK) <= SLJIT_ARG_TYPE_F32); - CHECK_ARGUMENT(function_check_arguments(arg_types, scratches, (options & SLJIT_ENTER_REG_ARG) ? 0 : saveds, fscratches)); - - compiler->last_flags = 0; -#endif -#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) - if (SLJIT_UNLIKELY(!!compiler->verbose)) { - fprintf(compiler->verbose, " enter ret[%s", call_arg_names[arg_types & SLJIT_ARG_MASK]); - - arg_types >>= SLJIT_ARG_SHIFT; - if (arg_types) { - fprintf(compiler->verbose, "], args["); - do { - fprintf(compiler->verbose, "%s%s", call_arg_names[arg_types & SLJIT_ARG_MASK], - (arg_types & SLJIT_ARG_TYPE_SCRATCH_REG) ? "_r" : ""); - arg_types >>= SLJIT_ARG_SHIFT; - if (arg_types) - fprintf(compiler->verbose, ","); - } while (arg_types); - } - - 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, "scratches:%d, saveds:%d, fscratches:%d, fsaveds:%d, local_size:%d\n", - scratches, saveds, fscratches, fsaveds, local_size); - } -#endif - CHECK_RETURN_OK; -} - -static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_set_context(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) -{ - SLJIT_UNUSED_ARG(compiler); - -#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) - if (options & SLJIT_ENTER_REG_ARG) { - CHECK_ARGUMENT(!(options & ~(0x3 | SLJIT_ENTER_REG_ARG))); - } else { - CHECK_ARGUMENT(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); - CHECK_ARGUMENT(saveds >= 0 && saveds <= SLJIT_NUMBER_OF_SAVED_REGISTERS); - CHECK_ARGUMENT(scratches + saveds <= SLJIT_NUMBER_OF_REGISTERS); - CHECK_ARGUMENT(fscratches >= 0 && fscratches <= SLJIT_NUMBER_OF_FLOAT_REGISTERS); - CHECK_ARGUMENT(fsaveds >= 0 && fsaveds <= SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS); - CHECK_ARGUMENT(fscratches + fsaveds <= SLJIT_NUMBER_OF_FLOAT_REGISTERS); - CHECK_ARGUMENT(local_size >= 0 && local_size <= SLJIT_MAX_LOCAL_SIZE); - CHECK_ARGUMENT((arg_types & SLJIT_ARG_FULL_MASK) < SLJIT_ARG_TYPE_F64); - CHECK_ARGUMENT(function_check_arguments(arg_types, scratches, (options & SLJIT_ENTER_REG_ARG) ? 0 : saveds, fscratches)); - - compiler->last_flags = 0; -#endif -#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) - if (SLJIT_UNLIKELY(!!compiler->verbose)) { - fprintf(compiler->verbose, " set_context ret[%s", call_arg_names[arg_types & SLJIT_ARG_MASK]); - - arg_types >>= SLJIT_ARG_SHIFT; - if (arg_types) { - fprintf(compiler->verbose, "], args["); - do { - fprintf(compiler->verbose, "%s%s", call_arg_names[arg_types & SLJIT_ARG_MASK], - (arg_types & SLJIT_ARG_TYPE_SCRATCH_REG) ? "_r" : ""); - arg_types >>= SLJIT_ARG_SHIFT; - if (arg_types) - fprintf(compiler->verbose, ","); - } while (arg_types); - } - - 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, " scratches:%d, saveds:%d, fscratches:%d, fsaveds:%d, local_size:%d\n", - scratches, saveds, fscratches, fsaveds, local_size); - } -#endif - CHECK_RETURN_OK; -} - -static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_return_void(struct sljit_compiler *compiler) -{ - if (SLJIT_UNLIKELY(compiler->skip_checks)) { - compiler->skip_checks = 0; - CHECK_RETURN_OK; - } - -#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) - CHECK_ARGUMENT(compiler->last_return == SLJIT_ARG_TYPE_VOID); -#endif - -#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) - if (SLJIT_UNLIKELY(!!compiler->verbose)) { - fprintf(compiler->verbose, " return_void\n"); - } -#endif - CHECK_RETURN_OK; -} - -static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_return(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw) -{ -#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) - CHECK_ARGUMENT(compiler->scratches >= 0); - - switch (compiler->last_return) { - case SLJIT_ARG_TYPE_W: - CHECK_ARGUMENT(op >= SLJIT_MOV && op <= SLJIT_MOV_S32); - break; - case SLJIT_ARG_TYPE_32: - CHECK_ARGUMENT(op == SLJIT_MOV32 || (op >= SLJIT_MOV32_U8 && op <= SLJIT_MOV32_S16)); - break; - case SLJIT_ARG_TYPE_P: - CHECK_ARGUMENT(op == SLJIT_MOV_P); - break; - case SLJIT_ARG_TYPE_F64: - CHECK_ARGUMENT(sljit_has_cpu_feature(SLJIT_HAS_FPU)); - CHECK_ARGUMENT(op == SLJIT_MOV_F64); - break; - case SLJIT_ARG_TYPE_F32: - CHECK_ARGUMENT(sljit_has_cpu_feature(SLJIT_HAS_FPU)); - CHECK_ARGUMENT(op == SLJIT_MOV_F32); - break; - default: - /* Context not initialized, void, etc. */ - CHECK_ARGUMENT(0); - break; - } - - if (GET_OPCODE(op) < SLJIT_MOV_F64) { - FUNCTION_CHECK_SRC(src, srcw); - } else { - FUNCTION_FCHECK(src, srcw); - } - compiler->last_flags = 0; -#endif -#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) - if (SLJIT_UNLIKELY(!!compiler->verbose)) { - if (GET_OPCODE(op) < SLJIT_MOV_F64) { - fprintf(compiler->verbose, " return%s%s ", !(op & SLJIT_32) ? "" : "32", - op1_names[GET_OPCODE(op) - SLJIT_OP1_BASE]); - sljit_verbose_param(compiler, src, srcw); - } else { - fprintf(compiler->verbose, " return%s ", !(op & SLJIT_32) ? ".f64" : ".f32"); - sljit_verbose_fparam(compiler, src, srcw); - } - fprintf(compiler->verbose, "\n"); - } -#endif - CHECK_RETURN_OK; -} - -static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_return_to(struct sljit_compiler *compiler, - sljit_s32 src, sljit_sw srcw) -{ -#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) - FUNCTION_CHECK_SRC(src, srcw); -#endif -#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) - if (SLJIT_UNLIKELY(!!compiler->verbose)) { - fprintf(compiler->verbose, " return_to "); - sljit_verbose_param(compiler, src, srcw); - fprintf(compiler->verbose, "\n"); - } -#endif - CHECK_RETURN_OK; -} - -static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw) -{ -#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) - FUNCTION_CHECK_DST(dst, dstw); - compiler->last_flags = 0; -#endif -#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) - if (SLJIT_UNLIKELY(!!compiler->verbose)) { - fprintf(compiler->verbose, " fast_enter "); - sljit_verbose_param(compiler, dst, dstw); - fprintf(compiler->verbose, "\n"); - } -#endif - CHECK_RETURN_OK; -} - -static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op0(struct sljit_compiler *compiler, sljit_s32 op) -{ -#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) - CHECK_ARGUMENT((op >= SLJIT_BREAKPOINT && op <= SLJIT_LMUL_SW) - || ((op & ~SLJIT_32) >= SLJIT_DIVMOD_UW && (op & ~SLJIT_32) <= SLJIT_DIV_SW) - || (op >= SLJIT_ENDBR && op <= SLJIT_SKIP_FRAMES_BEFORE_RETURN)); - CHECK_ARGUMENT(GET_OPCODE(op) < SLJIT_LMUL_UW || GET_OPCODE(op) >= SLJIT_ENDBR || compiler->scratches >= 2); - if ((GET_OPCODE(op) >= SLJIT_LMUL_UW && GET_OPCODE(op) <= SLJIT_DIV_SW) || op == SLJIT_SKIP_FRAMES_BEFORE_RETURN) - compiler->last_flags = 0; -#endif -#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) - if (SLJIT_UNLIKELY(!!compiler->verbose)) - { - fprintf(compiler->verbose, " %s", op0_names[GET_OPCODE(op) - SLJIT_OP0_BASE]); - if (GET_OPCODE(op) >= SLJIT_DIVMOD_UW && GET_OPCODE(op) <= SLJIT_DIV_SW) { - fprintf(compiler->verbose, (op & SLJIT_32) ? "32" : "w"); - } - fprintf(compiler->verbose, "\n"); - } -#endif - CHECK_RETURN_OK; -} - -static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op1(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src, sljit_sw srcw) -{ - if (SLJIT_UNLIKELY(compiler->skip_checks)) { - compiler->skip_checks = 0; - CHECK_RETURN_OK; - } - -#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) - CHECK_ARGUMENT(GET_OPCODE(op) >= SLJIT_MOV && GET_OPCODE(op) <= SLJIT_CTZ); - - switch (GET_OPCODE(op)) { - case SLJIT_NOT: - /* Only SLJIT_32 and SLJIT_SET_Z are allowed. */ - CHECK_ARGUMENT(!(op & VARIABLE_FLAG_MASK)); - break; - case SLJIT_MOV: - case SLJIT_MOV_U32: - case SLJIT_MOV_P: - /* Nothing allowed */ - CHECK_ARGUMENT(!(op & (SLJIT_32 | SLJIT_SET_Z | VARIABLE_FLAG_MASK))); - break; - default: - /* Only SLJIT_32 is allowed. */ - CHECK_ARGUMENT(!(op & (SLJIT_SET_Z | VARIABLE_FLAG_MASK))); - break; - } - - FUNCTION_CHECK_DST(dst, dstw); - FUNCTION_CHECK_SRC(src, srcw); - - if (GET_OPCODE(op) >= SLJIT_NOT) { - CHECK_ARGUMENT(src != SLJIT_IMM); - compiler->last_flags = GET_FLAG_TYPE(op) | (op & (SLJIT_32 | SLJIT_SET_Z)); - } -#endif -#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) - if (SLJIT_UNLIKELY(!!compiler->verbose)) { - if (GET_OPCODE(op) <= SLJIT_MOV_P) - { - fprintf(compiler->verbose, " mov%s%s ", !(op & SLJIT_32) ? "" : "32", - op1_names[GET_OPCODE(op) - SLJIT_OP1_BASE]); - } - else - { - fprintf(compiler->verbose, " %s%s%s%s%s ", op1_names[GET_OPCODE(op) - SLJIT_OP1_BASE], !(op & SLJIT_32) ? "" : "32", - !(op & SLJIT_SET_Z) ? "" : ".z", !(op & VARIABLE_FLAG_MASK) ? "" : ".", - !(op & VARIABLE_FLAG_MASK) ? "" : jump_names[GET_FLAG_TYPE(op)]); - } - - sljit_verbose_param(compiler, dst, dstw); - fprintf(compiler->verbose, ", "); - sljit_verbose_param(compiler, src, srcw); - fprintf(compiler->verbose, "\n"); - } -#endif - CHECK_RETURN_OK; -} - -static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op2(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 unset, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - if (SLJIT_UNLIKELY(compiler->skip_checks)) { - compiler->skip_checks = 0; - CHECK_RETURN_OK; - } - -#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) - CHECK_ARGUMENT(GET_OPCODE(op) >= SLJIT_ADD && GET_OPCODE(op) <= SLJIT_ROTR); - - switch (GET_OPCODE(op)) { - case SLJIT_AND: - case SLJIT_OR: - case SLJIT_XOR: - case SLJIT_SHL: - case SLJIT_MSHL: - case SLJIT_LSHR: - case SLJIT_MLSHR: - case SLJIT_ASHR: - case SLJIT_MASHR: - CHECK_ARGUMENT(!(op & VARIABLE_FLAG_MASK)); - break; - case SLJIT_MUL: - CHECK_ARGUMENT(!(op & SLJIT_SET_Z)); - CHECK_ARGUMENT(!(op & VARIABLE_FLAG_MASK) - || GET_FLAG_TYPE(op) == SLJIT_OVERFLOW); - break; - case SLJIT_ADD: - CHECK_ARGUMENT(!(op & VARIABLE_FLAG_MASK) - || GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY) - || GET_FLAG_TYPE(op) == SLJIT_OVERFLOW); - break; - case SLJIT_SUB: - CHECK_ARGUMENT(!(op & VARIABLE_FLAG_MASK) - || (GET_FLAG_TYPE(op) >= SLJIT_LESS && GET_FLAG_TYPE(op) <= SLJIT_OVERFLOW) - || GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY)); - break; - case SLJIT_ADDC: - case SLJIT_SUBC: - CHECK_ARGUMENT(!(op & VARIABLE_FLAG_MASK) - || GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY)); - CHECK_ARGUMENT((compiler->last_flags & 0xff) == GET_FLAG_TYPE(SLJIT_SET_CARRY)); - CHECK_ARGUMENT((op & SLJIT_32) == (compiler->last_flags & SLJIT_32)); - break; - case SLJIT_ROTL: - case SLJIT_ROTR: - CHECK_ARGUMENT(!(op & (SLJIT_SET_Z | VARIABLE_FLAG_MASK))); - break; - default: - SLJIT_UNREACHABLE(); - break; - } - - if (unset) { - CHECK_ARGUMENT(HAS_FLAGS(op)); - } else { - FUNCTION_CHECK_DST(dst, dstw); - } - FUNCTION_CHECK_SRC(src1, src1w); - FUNCTION_CHECK_SRC(src2, src2w); - compiler->last_flags = GET_FLAG_TYPE(op) | (op & (SLJIT_32 | SLJIT_SET_Z)); -#endif -#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) - if (SLJIT_UNLIKELY(!!compiler->verbose)) { - fprintf(compiler->verbose, " %s%s%s%s%s ", op2_names[GET_OPCODE(op) - SLJIT_OP2_BASE], !(op & SLJIT_32) ? "" : "32", - !(op & SLJIT_SET_Z) ? "" : ".z", !(op & VARIABLE_FLAG_MASK) ? "" : ".", - !(op & VARIABLE_FLAG_MASK) ? "" : jump_names[GET_FLAG_TYPE(op)]); - if (unset) - fprintf(compiler->verbose, "unset"); - else - sljit_verbose_param(compiler, dst, dstw); - 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 src_dst, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ -#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) - CHECK_ARGUMENT(GET_OPCODE(op) == SLJIT_SHL || GET_OPCODE(op) == SLJIT_LSHR - || GET_OPCODE(op) == SLJIT_MSHL || GET_OPCODE(op) == SLJIT_MLSHR); - CHECK_ARGUMENT((op & ~(0xff | SLJIT_32 | SLJIT_SHIFT_INTO_NON_ZERO)) == 0); - CHECK_ARGUMENT(FUNCTION_CHECK_IS_REG(src_dst)); - FUNCTION_CHECK_SRC(src1, src1w); - FUNCTION_CHECK_SRC(src2, src2w); -#endif -#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) - if (SLJIT_UNLIKELY(!!compiler->verbose)) { - fprintf(compiler->verbose, " %s%s.into%s ", op2_names[GET_OPCODE(op) - SLJIT_OP2_BASE], !(op & SLJIT_32) ? "" : "32", - (op & SLJIT_SHIFT_INTO_NON_ZERO) ? ".nz" : ""); - - sljit_verbose_reg(compiler, src_dst); - 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_op_src(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 src, sljit_sw srcw) -{ -#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) - CHECK_ARGUMENT(op >= SLJIT_FAST_RETURN && op <= SLJIT_PREFETCH_ONCE); - FUNCTION_CHECK_SRC(src, srcw); - - if (op == SLJIT_FAST_RETURN || op == SLJIT_SKIP_FRAMES_BEFORE_FAST_RETURN) - { - CHECK_ARGUMENT(src != SLJIT_IMM); - compiler->last_flags = 0; - } - else if (op >= SLJIT_PREFETCH_L1 && op <= SLJIT_PREFETCH_ONCE) - { - CHECK_ARGUMENT(src & SLJIT_MEM); - } -#endif -#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) - if (SLJIT_UNLIKELY(!!compiler->verbose)) { - fprintf(compiler->verbose, " %s ", op_src_names[op - SLJIT_OP_SRC_BASE]); - sljit_verbose_param(compiler, src, srcw); - fprintf(compiler->verbose, "\n"); - } -#endif - CHECK_RETURN_OK; -} - -static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_get_register_index(sljit_s32 reg) -{ - SLJIT_UNUSED_ARG(reg); -#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) - CHECK_ARGUMENT(reg > 0 && reg <= SLJIT_NUMBER_OF_REGISTERS); -#endif - CHECK_RETURN_OK; -} - -static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_get_float_register_index(sljit_s32 reg) -{ - SLJIT_UNUSED_ARG(reg); -#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) - CHECK_ARGUMENT(reg > 0 && reg <= SLJIT_NUMBER_OF_FLOAT_REGISTERS); -#endif - CHECK_RETURN_OK; -} - -static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op_custom(struct sljit_compiler *compiler, - void *instruction, sljit_u32 size) -{ -#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) - sljit_u32 i; -#endif - - SLJIT_UNUSED_ARG(compiler); - -#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) - CHECK_ARGUMENT(instruction); - -#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) - CHECK_ARGUMENT(size > 0 && size < 16); -#elif (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2) - CHECK_ARGUMENT((size == 2 && (((sljit_sw)instruction) & 0x1) == 0) - || (size == 4 && (((sljit_sw)instruction) & 0x3) == 0)); -#elif (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X) - CHECK_ARGUMENT(size == 2 || size == 4 || size == 6); -#else - CHECK_ARGUMENT(size == 4 && (((sljit_sw)instruction) & 0x3) == 0); -#endif - - compiler->last_flags = 0; -#endif -#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) - if (SLJIT_UNLIKELY(!!compiler->verbose)) { - fprintf(compiler->verbose, " op_custom"); - for (i = 0; i < size; i++) - fprintf(compiler->verbose, " 0x%x", ((sljit_u8*)instruction)[i]); - fprintf(compiler->verbose, "\n"); - } -#endif - CHECK_RETURN_OK; -} - -static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fop1(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src, sljit_sw srcw) -{ - if (SLJIT_UNLIKELY(compiler->skip_checks)) { - compiler->skip_checks = 0; - CHECK_RETURN_OK; - } - -#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) - CHECK_ARGUMENT(sljit_has_cpu_feature(SLJIT_HAS_FPU)); - CHECK_ARGUMENT(GET_OPCODE(op) >= SLJIT_MOV_F64 && GET_OPCODE(op) <= SLJIT_ABS_F64); - CHECK_ARGUMENT(!(op & (SLJIT_SET_Z | VARIABLE_FLAG_MASK))); - FUNCTION_FCHECK(src, srcw); - FUNCTION_FCHECK(dst, dstw); -#endif -#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) - if (SLJIT_UNLIKELY(!!compiler->verbose)) { - if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_F32) - fprintf(compiler->verbose, " %s%s ", fop1_names[SLJIT_CONV_F64_FROM_F32 - SLJIT_FOP1_BASE], - (op & SLJIT_32) ? ".f32.from.f64" : ".f64.from.f32"); - else - fprintf(compiler->verbose, " %s%s ", fop1_names[GET_OPCODE(op) - SLJIT_FOP1_BASE], - (op & SLJIT_32) ? ".f32" : ".f64"); - - sljit_verbose_fparam(compiler, dst, dstw); - fprintf(compiler->verbose, ", "); - sljit_verbose_fparam(compiler, src, srcw); - fprintf(compiler->verbose, "\n"); - } -#endif - CHECK_RETURN_OK; -} - -static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ -#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) - compiler->last_flags = GET_FLAG_TYPE(op) | (op & SLJIT_32); -#endif - - if (SLJIT_UNLIKELY(compiler->skip_checks)) { - compiler->skip_checks = 0; - CHECK_RETURN_OK; - } - -#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) - CHECK_ARGUMENT(sljit_has_cpu_feature(SLJIT_HAS_FPU)); - CHECK_ARGUMENT(GET_OPCODE(op) == SLJIT_CMP_F64); - CHECK_ARGUMENT(!(op & SLJIT_SET_Z)); - CHECK_ARGUMENT((op & VARIABLE_FLAG_MASK) - || (GET_FLAG_TYPE(op) >= SLJIT_F_EQUAL && GET_FLAG_TYPE(op) <= SLJIT_ORDERED_LESS_EQUAL)); - FUNCTION_FCHECK(src1, src1w); - FUNCTION_FCHECK(src2, src2w); -#endif -#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) - if (SLJIT_UNLIKELY(!!compiler->verbose)) { - fprintf(compiler->verbose, " %s%s", fop1_names[SLJIT_CMP_F64 - SLJIT_FOP1_BASE], (op & SLJIT_32) ? ".f32" : ".f64"); - if (op & VARIABLE_FLAG_MASK) { - fprintf(compiler->verbose, ".%s", jump_names[GET_FLAG_TYPE(op)]); - } - fprintf(compiler->verbose, " "); - sljit_verbose_fparam(compiler, src1, src1w); - fprintf(compiler->verbose, ", "); - sljit_verbose_fparam(compiler, src2, src2w); - fprintf(compiler->verbose, "\n"); - } -#endif - CHECK_RETURN_OK; -} - -static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fop1_conv_sw_from_f64(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src, sljit_sw srcw) -{ - if (SLJIT_UNLIKELY(compiler->skip_checks)) { - compiler->skip_checks = 0; - CHECK_RETURN_OK; - } - -#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) - CHECK_ARGUMENT(sljit_has_cpu_feature(SLJIT_HAS_FPU)); - CHECK_ARGUMENT(GET_OPCODE(op) >= SLJIT_CONV_SW_FROM_F64 && GET_OPCODE(op) <= SLJIT_CONV_S32_FROM_F64); - CHECK_ARGUMENT(!(op & (SLJIT_SET_Z | VARIABLE_FLAG_MASK))); - FUNCTION_FCHECK(src, srcw); - FUNCTION_CHECK_DST(dst, dstw); -#endif -#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) - if (SLJIT_UNLIKELY(!!compiler->verbose)) { - fprintf(compiler->verbose, " %s%s.from%s ", fop1_names[GET_OPCODE(op) - SLJIT_FOP1_BASE], - (GET_OPCODE(op) == SLJIT_CONV_S32_FROM_F64) ? ".s32" : ".sw", - (op & SLJIT_32) ? ".f32" : ".f64"); - sljit_verbose_param(compiler, dst, dstw); - fprintf(compiler->verbose, ", "); - sljit_verbose_fparam(compiler, src, srcw); - fprintf(compiler->verbose, "\n"); - } -#endif - CHECK_RETURN_OK; -} - -static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src, sljit_sw srcw) -{ - if (SLJIT_UNLIKELY(compiler->skip_checks)) { - compiler->skip_checks = 0; - CHECK_RETURN_OK; - } - -#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) - CHECK_ARGUMENT(sljit_has_cpu_feature(SLJIT_HAS_FPU)); - CHECK_ARGUMENT(GET_OPCODE(op) >= SLJIT_CONV_F64_FROM_SW && GET_OPCODE(op) <= SLJIT_CONV_F64_FROM_S32); - CHECK_ARGUMENT(!(op & (SLJIT_SET_Z | VARIABLE_FLAG_MASK))); - FUNCTION_CHECK_SRC(src, srcw); - FUNCTION_FCHECK(dst, dstw); -#endif -#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) - if (SLJIT_UNLIKELY(!!compiler->verbose)) { - fprintf(compiler->verbose, " %s%s.from%s ", fop1_names[GET_OPCODE(op) - SLJIT_FOP1_BASE], - (op & SLJIT_32) ? ".f32" : ".f64", - (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32) ? ".s32" : ".sw"); - sljit_verbose_fparam(compiler, dst, dstw); - fprintf(compiler->verbose, ", "); - sljit_verbose_param(compiler, src, srcw); - fprintf(compiler->verbose, "\n"); - } -#endif - CHECK_RETURN_OK; -} - -static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fop2(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ -#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) - CHECK_ARGUMENT(sljit_has_cpu_feature(SLJIT_HAS_FPU)); - CHECK_ARGUMENT(GET_OPCODE(op) >= SLJIT_ADD_F64 && GET_OPCODE(op) <= SLJIT_DIV_F64); - CHECK_ARGUMENT(!(op & (SLJIT_SET_Z | VARIABLE_FLAG_MASK))); - FUNCTION_FCHECK(src1, src1w); - FUNCTION_FCHECK(src2, src2w); - FUNCTION_FCHECK(dst, dstw); -#endif -#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) - if (SLJIT_UNLIKELY(!!compiler->verbose)) { - fprintf(compiler->verbose, " %s%s ", fop2_names[GET_OPCODE(op) - SLJIT_FOP2_BASE], (op & SLJIT_32) ? ".f32" : ".f64"); - sljit_verbose_fparam(compiler, dst, dstw); - fprintf(compiler->verbose, ", "); - sljit_verbose_fparam(compiler, src1, src1w); - fprintf(compiler->verbose, ", "); - sljit_verbose_fparam(compiler, src2, src2w); - fprintf(compiler->verbose, "\n"); - } -#endif - CHECK_RETURN_OK; -} - -static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_label(struct sljit_compiler *compiler) -{ - SLJIT_UNUSED_ARG(compiler); - - if (SLJIT_UNLIKELY(compiler->skip_checks)) { - compiler->skip_checks = 0; - CHECK_RETURN_OK; - } - -#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) - compiler->last_flags = 0; -#endif - -#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) - if (SLJIT_UNLIKELY(!!compiler->verbose)) - fprintf(compiler->verbose, "label:\n"); -#endif - CHECK_RETURN_OK; -} - -#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) -#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) \ - || (defined SLJIT_CONFIG_ARM && SLJIT_CONFIG_ARM) -#define CHECK_UNORDERED(type, last_flags) \ - ((((type) & 0xff) == SLJIT_UNORDERED || ((type) & 0xff) == SLJIT_ORDERED) && \ - ((last_flags) & 0xff) >= SLJIT_UNORDERED && ((last_flags) & 0xff) <= SLJIT_ORDERED_LESS_EQUAL) -#else -#define CHECK_UNORDERED(type, last_flags) 0 -#endif -#endif /* SLJIT_ARGUMENT_CHECKS */ - -static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type) -{ - if (SLJIT_UNLIKELY(compiler->skip_checks)) { - compiler->skip_checks = 0; - CHECK_RETURN_OK; - } - -#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) - CHECK_ARGUMENT(!(type & ~(0xff | SLJIT_REWRITABLE_JUMP))); - CHECK_ARGUMENT((type & 0xff) >= SLJIT_EQUAL && (type & 0xff) <= SLJIT_FAST_CALL); - - if ((type & 0xff) < SLJIT_JUMP) { - if ((type & 0xff) <= SLJIT_NOT_ZERO) - CHECK_ARGUMENT(compiler->last_flags & SLJIT_SET_Z); - else if ((compiler->last_flags & 0xff) == SLJIT_CARRY) { - CHECK_ARGUMENT((type & 0xff) == SLJIT_CARRY || (type & 0xff) == SLJIT_NOT_CARRY); - compiler->last_flags = 0; - } else - CHECK_ARGUMENT((type & 0xff) == (compiler->last_flags & 0xff) - || ((type & 0xff) == SLJIT_NOT_OVERFLOW && (compiler->last_flags & 0xff) == SLJIT_OVERFLOW) - || CHECK_UNORDERED(type, compiler->last_flags)); - } -#endif -#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) - if (SLJIT_UNLIKELY(!!compiler->verbose)) - fprintf(compiler->verbose, " jump%s %s\n", !(type & SLJIT_REWRITABLE_JUMP) ? "" : ".r", - jump_names[type & 0xff]); -#endif - CHECK_RETURN_OK; -} - -static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_call(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 arg_types) -{ -#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) - CHECK_ARGUMENT(!(type & ~(0xff | SLJIT_REWRITABLE_JUMP | SLJIT_CALL_RETURN))); - CHECK_ARGUMENT((type & 0xff) >= SLJIT_CALL && (type & 0xff) <= SLJIT_CALL_REG_ARG); - CHECK_ARGUMENT(function_check_arguments(arg_types, compiler->scratches, -1, compiler->fscratches)); - - if (type & SLJIT_CALL_RETURN) { - CHECK_ARGUMENT((arg_types & SLJIT_ARG_MASK) == compiler->last_return); - - if (compiler->options & SLJIT_ENTER_REG_ARG) { - CHECK_ARGUMENT((type & 0xff) == SLJIT_CALL_REG_ARG); - } else { - CHECK_ARGUMENT((type & 0xff) != SLJIT_CALL_REG_ARG); - } - } -#endif -#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) - if (SLJIT_UNLIKELY(!!compiler->verbose)) { - fprintf(compiler->verbose, " %s%s%s ret[%s", jump_names[type & 0xff], - !(type & SLJIT_REWRITABLE_JUMP) ? "" : ".r", - !(type & SLJIT_CALL_RETURN) ? "" : ".ret", - call_arg_names[arg_types & SLJIT_ARG_MASK]); - - arg_types >>= SLJIT_ARG_SHIFT; - if (arg_types) { - fprintf(compiler->verbose, "], args["); - do { - fprintf(compiler->verbose, "%s", call_arg_names[arg_types & SLJIT_ARG_MASK]); - arg_types >>= SLJIT_ARG_SHIFT; - if (arg_types) - fprintf(compiler->verbose, ","); - } while (arg_types); - } - fprintf(compiler->verbose, "]\n"); - } -#endif - CHECK_RETURN_OK; -} - -static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_cmp(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ -#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) - CHECK_ARGUMENT(!(type & ~(0xff | SLJIT_REWRITABLE_JUMP | SLJIT_32))); - CHECK_ARGUMENT((type & 0xff) >= SLJIT_EQUAL && (type & 0xff) <= SLJIT_SIG_LESS_EQUAL); - 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, " cmp%s%s %s, ", (type & SLJIT_32) ? "32" : "", - !(type & SLJIT_REWRITABLE_JUMP) ? "" : ".r", jump_names[type & 0xff]); - 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_fcmp(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ -#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) - CHECK_ARGUMENT(sljit_has_cpu_feature(SLJIT_HAS_FPU)); - CHECK_ARGUMENT(!(type & ~(0xff | SLJIT_REWRITABLE_JUMP | SLJIT_32))); - CHECK_ARGUMENT((type & 0xff) >= SLJIT_F_EQUAL && (type & 0xff) <= SLJIT_ORDERED_LESS_EQUAL - && ((type & 0xff) <= SLJIT_ORDERED || sljit_cmp_info(type & 0xff))); - FUNCTION_FCHECK(src1, src1w); - FUNCTION_FCHECK(src2, src2w); - compiler->last_flags = 0; -#endif -#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) - if (SLJIT_UNLIKELY(!!compiler->verbose)) { - fprintf(compiler->verbose, " fcmp%s%s %s, ", (type & SLJIT_32) ? ".f32" : ".f64", - !(type & SLJIT_REWRITABLE_JUMP) ? "" : ".r", jump_names[type & 0xff]); - sljit_verbose_fparam(compiler, src1, src1w); - fprintf(compiler->verbose, ", "); - sljit_verbose_fparam(compiler, src2, src2w); - fprintf(compiler->verbose, "\n"); - } -#endif - CHECK_RETURN_OK; -} - -static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_ijump(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 src, sljit_sw srcw) -{ - if (SLJIT_UNLIKELY(compiler->skip_checks)) { - compiler->skip_checks = 0; - CHECK_RETURN_OK; - } - -#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) - CHECK_ARGUMENT(type >= SLJIT_JUMP && type <= SLJIT_FAST_CALL); - FUNCTION_CHECK_SRC(src, srcw); -#endif -#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) - if (SLJIT_UNLIKELY(!!compiler->verbose)) { - fprintf(compiler->verbose, " ijump.%s ", jump_names[type]); - sljit_verbose_param(compiler, src, srcw); - fprintf(compiler->verbose, "\n"); - } -#endif - CHECK_RETURN_OK; -} - -static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_icall(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 arg_types, - sljit_s32 src, sljit_sw srcw) -{ -#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) - CHECK_ARGUMENT(!(type & ~(0xff | SLJIT_CALL_RETURN))); - CHECK_ARGUMENT((type & 0xff) >= SLJIT_CALL && (type & 0xff) <= SLJIT_CALL_REG_ARG); - CHECK_ARGUMENT(function_check_arguments(arg_types, compiler->scratches, -1, compiler->fscratches)); - FUNCTION_CHECK_SRC(src, srcw); - - if (type & SLJIT_CALL_RETURN) { - CHECK_ARGUMENT((arg_types & SLJIT_ARG_MASK) == compiler->last_return); - - if (compiler->options & SLJIT_ENTER_REG_ARG) { - CHECK_ARGUMENT((type & 0xff) == SLJIT_CALL_REG_ARG); - } else { - CHECK_ARGUMENT((type & 0xff) != SLJIT_CALL_REG_ARG); - } - } -#endif -#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) - if (SLJIT_UNLIKELY(!!compiler->verbose)) { - fprintf(compiler->verbose, " i%s%s ret[%s", jump_names[type & 0xff], - !(type & SLJIT_CALL_RETURN) ? "" : ".ret", - call_arg_names[arg_types & SLJIT_ARG_MASK]); - - arg_types >>= SLJIT_ARG_SHIFT; - if (arg_types) { - fprintf(compiler->verbose, "], args["); - do { - fprintf(compiler->verbose, "%s", call_arg_names[arg_types & SLJIT_ARG_MASK]); - arg_types >>= SLJIT_ARG_SHIFT; - if (arg_types) - fprintf(compiler->verbose, ","); - } while (arg_types); - } - fprintf(compiler->verbose, "], "); - sljit_verbose_param(compiler, src, srcw); - fprintf(compiler->verbose, "\n"); - } -#endif - CHECK_RETURN_OK; -} - -static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 type) -{ -#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) - CHECK_ARGUMENT(type >= SLJIT_EQUAL && type <= SLJIT_ORDERED_LESS_EQUAL); - CHECK_ARGUMENT(op == SLJIT_MOV || op == SLJIT_MOV32 - || (GET_OPCODE(op) >= SLJIT_AND && GET_OPCODE(op) <= SLJIT_XOR)); - CHECK_ARGUMENT(!(op & VARIABLE_FLAG_MASK)); - - if (type <= SLJIT_NOT_ZERO) - CHECK_ARGUMENT(compiler->last_flags & SLJIT_SET_Z); - else - CHECK_ARGUMENT(type == (compiler->last_flags & 0xff) - || (type == SLJIT_NOT_CARRY && (compiler->last_flags & 0xff) == SLJIT_CARRY) - || (type == SLJIT_NOT_OVERFLOW && (compiler->last_flags & 0xff) == SLJIT_OVERFLOW) - || CHECK_UNORDERED(type, compiler->last_flags)); - - FUNCTION_CHECK_DST(dst, dstw); - - if (GET_OPCODE(op) >= SLJIT_ADD) - compiler->last_flags = GET_FLAG_TYPE(op) | (op & (SLJIT_32 | SLJIT_SET_Z)); -#endif -#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) - if (SLJIT_UNLIKELY(!!compiler->verbose)) { - fprintf(compiler->verbose, " flags.%s%s%s ", - GET_OPCODE(op) < SLJIT_OP2_BASE ? "mov" : op2_names[GET_OPCODE(op) - SLJIT_OP2_BASE], - GET_OPCODE(op) < SLJIT_OP2_BASE ? op1_names[GET_OPCODE(op) - SLJIT_OP1_BASE] : ((op & SLJIT_32) ? "32" : ""), - !(op & SLJIT_SET_Z) ? "" : ".z"); - sljit_verbose_param(compiler, dst, dstw); - fprintf(compiler->verbose, ", %s\n", jump_names[type]); - } -#endif - CHECK_RETURN_OK; -} - -static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_cmov(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 dst_reg, - sljit_s32 src, sljit_sw srcw) -{ -#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) - sljit_s32 cond = type & ~SLJIT_32; - - CHECK_ARGUMENT(cond >= SLJIT_EQUAL && cond <= SLJIT_ORDERED_LESS_EQUAL); - - CHECK_ARGUMENT(compiler->scratches != -1 && compiler->saveds != -1); - CHECK_ARGUMENT(FUNCTION_CHECK_IS_REG(dst_reg)); - if (src != SLJIT_IMM) { - CHECK_ARGUMENT(FUNCTION_CHECK_IS_REG(src)); - CHECK_ARGUMENT(srcw == 0); - } - - if (cond <= SLJIT_NOT_ZERO) - CHECK_ARGUMENT(compiler->last_flags & SLJIT_SET_Z); - else - CHECK_ARGUMENT(cond == (compiler->last_flags & 0xff) - || (cond == SLJIT_NOT_CARRY && (compiler->last_flags & 0xff) == SLJIT_CARRY) - || (cond == SLJIT_NOT_OVERFLOW && (compiler->last_flags & 0xff) == SLJIT_OVERFLOW) - || CHECK_UNORDERED(cond, compiler->last_flags)); -#endif -#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) - if (SLJIT_UNLIKELY(!!compiler->verbose)) { - fprintf(compiler->verbose, " cmov%s %s, ", - !(type & SLJIT_32) ? "" : "32", - jump_names[type & ~SLJIT_32]); - sljit_verbose_reg(compiler, dst_reg); - fprintf(compiler->verbose, ", "); - sljit_verbose_param(compiler, src, srcw); - fprintf(compiler->verbose, "\n"); - } -#endif - CHECK_RETURN_OK; -} - -static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_mem(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 reg, - sljit_s32 mem, sljit_sw memw) -{ - if (SLJIT_UNLIKELY(compiler->skip_checks)) { - compiler->skip_checks = 0; - CHECK_RETURN_OK; - } - -#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) - sljit_s32 allowed_flags; - - if (type & SLJIT_MEM_UNALIGNED) { - CHECK_ARGUMENT(!(type & (SLJIT_MEM_UNALIGNED_16 | SLJIT_MEM_UNALIGNED_32))); - } else if (type & SLJIT_MEM_UNALIGNED_16) { - CHECK_ARGUMENT(!(type & SLJIT_MEM_UNALIGNED_32)); - } else { - CHECK_ARGUMENT((reg & REG_PAIR_MASK) || (type & SLJIT_MEM_UNALIGNED_32)); - } - - allowed_flags = SLJIT_MEM_UNALIGNED; - - switch (type & 0xff) { - case SLJIT_MOV_U32: - case SLJIT_MOV_S32: - case SLJIT_MOV32: - allowed_flags = SLJIT_MEM_UNALIGNED | SLJIT_MEM_UNALIGNED_16; - break; - case SLJIT_MOV: - case SLJIT_MOV_P: - allowed_flags = SLJIT_MEM_UNALIGNED | SLJIT_MEM_UNALIGNED_16 | SLJIT_MEM_UNALIGNED_32; - break; - } - - CHECK_ARGUMENT((type & ~(0xff | SLJIT_32 | SLJIT_MEM_STORE | allowed_flags)) == 0); - - if (reg & REG_PAIR_MASK) { - CHECK_ARGUMENT((type & 0xff) == SLJIT_MOV); - CHECK_ARGUMENT(FUNCTION_CHECK_IS_REG(REG_PAIR_FIRST(reg))); - CHECK_ARGUMENT(FUNCTION_CHECK_IS_REG(REG_PAIR_SECOND(reg))); - CHECK_ARGUMENT(REG_PAIR_FIRST(reg) != REG_PAIR_SECOND(reg)); - } else { - CHECK_ARGUMENT((type & 0xff) >= SLJIT_MOV && (type & 0xff) <= SLJIT_MOV_P); - CHECK_ARGUMENT(!(type & SLJIT_32) || ((type & 0xff) >= SLJIT_MOV_U8 && (type & 0xff) <= SLJIT_MOV_S16)); - CHECK_ARGUMENT(FUNCTION_CHECK_IS_REG(reg)); - } - - FUNCTION_CHECK_SRC_MEM(mem, memw); -#endif -#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) - if (SLJIT_UNLIKELY(!!compiler->verbose)) { - if ((type & 0xff) == SLJIT_MOV32) - fprintf(compiler->verbose, " %s32", - (type & SLJIT_MEM_STORE) ? "store" : "load"); - else - fprintf(compiler->verbose, " %s%s%s", - (type & SLJIT_MEM_STORE) ? "store" : "load", - !(type & SLJIT_32) ? "" : "32", - op1_names[(type & 0xff) - SLJIT_OP1_BASE]); - - if (type & SLJIT_MEM_UNALIGNED) - printf(".un"); - else if (type & SLJIT_MEM_UNALIGNED_16) - printf(".un16"); - else if (type & SLJIT_MEM_UNALIGNED_32) - printf(".un32"); - - if (reg & REG_PAIR_MASK) { - fprintf(compiler->verbose, " {"); - sljit_verbose_reg(compiler, REG_PAIR_FIRST(reg)); - fprintf(compiler->verbose, ", "); - sljit_verbose_reg(compiler, REG_PAIR_SECOND(reg)); - fprintf(compiler->verbose, "}, "); - } else { - fprintf(compiler->verbose, " "); - sljit_verbose_reg(compiler, reg); - fprintf(compiler->verbose, ", "); - } - sljit_verbose_param(compiler, mem, memw); - fprintf(compiler->verbose, "\n"); - } -#endif - CHECK_RETURN_OK; -} - -static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_mem_update(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 reg, - sljit_s32 mem, sljit_sw memw) -{ - if (SLJIT_UNLIKELY(compiler->skip_checks)) { - compiler->skip_checks = 0; - CHECK_RETURN_OK; - } - -#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) - CHECK_ARGUMENT((type & 0xff) >= SLJIT_MOV && (type & 0xff) <= SLJIT_MOV_P); - CHECK_ARGUMENT((type & ~(0xff | SLJIT_32 | SLJIT_MEM_STORE | SLJIT_MEM_SUPP | SLJIT_MEM_POST)) == 0); - CHECK_ARGUMENT((mem & REG_MASK) != 0 && (mem & REG_MASK) != reg); - - FUNCTION_CHECK_SRC_MEM(mem, memw); -#endif -#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) - if (SLJIT_UNLIKELY(!!compiler->verbose)) { - if (type & SLJIT_MEM_SUPP) - CHECK_RETURN_OK; - if (sljit_emit_mem_update(compiler, type | SLJIT_MEM_SUPP, reg, mem, memw) == SLJIT_ERR_UNSUPPORTED) { - fprintf(compiler->verbose, " # mem: unsupported form, no instructions are emitted\n"); - CHECK_RETURN_OK; - } - - if ((type & 0xff) == SLJIT_MOV32) - fprintf(compiler->verbose, " %s32.%s ", - (type & SLJIT_MEM_STORE) ? "store" : "load", - (type & SLJIT_MEM_POST) ? "post" : "pre"); - else - fprintf(compiler->verbose, " %s%s%s.%s ", - (type & SLJIT_MEM_STORE) ? "store" : "load", - !(type & SLJIT_32) ? "" : "32", - op1_names[(type & 0xff) - SLJIT_OP1_BASE], - (type & SLJIT_MEM_POST) ? "post" : "pre"); - - sljit_verbose_reg(compiler, reg); - fprintf(compiler->verbose, ", "); - sljit_verbose_param(compiler, mem, memw); - fprintf(compiler->verbose, "\n"); - } -#endif - CHECK_RETURN_OK; -} - -static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fmem(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 freg, - sljit_s32 mem, sljit_sw memw) -{ -#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) - CHECK_ARGUMENT((type & 0xff) == SLJIT_MOV_F64); - - if (type & SLJIT_MEM_UNALIGNED) { - CHECK_ARGUMENT(!(type & (SLJIT_MEM_UNALIGNED_16 | SLJIT_MEM_UNALIGNED_32))); - } else if (type & SLJIT_MEM_UNALIGNED_16) { - CHECK_ARGUMENT(!(type & SLJIT_MEM_UNALIGNED_32)); - } else { - CHECK_ARGUMENT(type & SLJIT_MEM_UNALIGNED_32); - CHECK_ARGUMENT(!(type & SLJIT_32)); - } - - CHECK_ARGUMENT(!(type & ~(0xff | SLJIT_32 | SLJIT_MEM_STORE | SLJIT_MEM_UNALIGNED | SLJIT_MEM_UNALIGNED_16 | SLJIT_MEM_UNALIGNED_32))); - CHECK_ARGUMENT(FUNCTION_CHECK_IS_FREG(freg)); - FUNCTION_CHECK_SRC_MEM(mem, memw); -#endif -#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) - if (SLJIT_UNLIKELY(!!compiler->verbose)) { - fprintf(compiler->verbose, " %s.%s", - (type & SLJIT_MEM_STORE) ? "store" : "load", - !(type & SLJIT_32) ? "f64" : "f32"); - - if (type & SLJIT_MEM_UNALIGNED) - printf(".un"); - else if (type & SLJIT_MEM_UNALIGNED_16) - printf(".un16"); - else if (type & SLJIT_MEM_UNALIGNED_32) - printf(".un32"); - - fprintf(compiler->verbose, " "); - sljit_verbose_freg(compiler, freg); - fprintf(compiler->verbose, ", "); - sljit_verbose_param(compiler, mem, memw); - fprintf(compiler->verbose, "\n"); - } -#endif - CHECK_RETURN_OK; -} - -static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fmem_update(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 freg, - sljit_s32 mem, sljit_sw memw) -{ -#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) - CHECK_ARGUMENT((type & 0xff) == SLJIT_MOV_F64); - CHECK_ARGUMENT((type & ~(0xff | SLJIT_32 | SLJIT_MEM_STORE | SLJIT_MEM_SUPP | SLJIT_MEM_POST)) == 0); - FUNCTION_CHECK_SRC_MEM(mem, memw); - CHECK_ARGUMENT(FUNCTION_CHECK_IS_FREG(freg)); -#endif -#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) - if (SLJIT_UNLIKELY(!!compiler->verbose)) { - if (type & SLJIT_MEM_SUPP) - CHECK_RETURN_OK; - if (sljit_emit_fmem_update(compiler, type | SLJIT_MEM_SUPP, freg, mem, memw) == SLJIT_ERR_UNSUPPORTED) { - fprintf(compiler->verbose, " # fmem: unsupported form, no instructions are emitted\n"); - CHECK_RETURN_OK; - } - - fprintf(compiler->verbose, " %s.%s.%s ", - (type & SLJIT_MEM_STORE) ? "store" : "load", - !(type & SLJIT_32) ? "f64" : "f32", - (type & SLJIT_MEM_POST) ? "post" : "pre"); - - sljit_verbose_freg(compiler, freg); - fprintf(compiler->verbose, ", "); - sljit_verbose_param(compiler, mem, memw); - fprintf(compiler->verbose, "\n"); - } -#endif - CHECK_RETURN_OK; - -} - -static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_get_local_base(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw offset) -{ - /* Any offset is allowed. */ - SLJIT_UNUSED_ARG(offset); - -#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, " local_base "); - sljit_verbose_param(compiler, dst, dstw); - fprintf(compiler->verbose, ", #%" SLJIT_PRINT_D "d\n", offset); - } -#endif - CHECK_RETURN_OK; -} - -static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value) -{ - SLJIT_UNUSED_ARG(init_value); - -#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) - FUNCTION_CHECK_DST(dst, dstw); -#endif -#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) - if (SLJIT_UNLIKELY(!!compiler->verbose)) { - fprintf(compiler->verbose, " const "); - sljit_verbose_param(compiler, dst, dstw); - fprintf(compiler->verbose, ", #%" SLJIT_PRINT_D "d\n", init_value); - } -#endif - CHECK_RETURN_OK; -} - -static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_put_label(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 "); - sljit_verbose_param(compiler, dst, dstw); - fprintf(compiler->verbose, "\n"); - } -#endif - CHECK_RETURN_OK; -} - -#else /* !SLJIT_ARGUMENT_CHECKS && !SLJIT_VERBOSE */ - -#define SLJIT_SKIP_CHECKS(compiler) - -#endif /* SLJIT_ARGUMENT_CHECKS || SLJIT_VERBOSE */ - -#define SELECT_FOP1_OPERATION_WITH_CHECKS(compiler, op, dst, dstw, src, srcw) \ - SLJIT_COMPILE_ASSERT(!(SLJIT_CONV_SW_FROM_F64 & 0x1) && !(SLJIT_CONV_F64_FROM_SW & 0x1), \ - invalid_float_opcodes); \ - if (GET_OPCODE(op) >= SLJIT_CONV_SW_FROM_F64 && GET_OPCODE(op) <= SLJIT_CMP_F64) { \ - if (GET_OPCODE(op) == SLJIT_CMP_F64) { \ - CHECK(check_sljit_emit_fop1_cmp(compiler, op, dst, dstw, src, srcw)); \ - ADJUST_LOCAL_OFFSET(dst, dstw); \ - ADJUST_LOCAL_OFFSET(src, srcw); \ - return sljit_emit_fop1_cmp(compiler, op, dst, dstw, src, srcw); \ - } \ - if ((GET_OPCODE(op) | 0x1) == SLJIT_CONV_S32_FROM_F64) { \ - CHECK(check_sljit_emit_fop1_conv_sw_from_f64(compiler, op, dst, dstw, src, srcw)); \ - ADJUST_LOCAL_OFFSET(dst, dstw); \ - ADJUST_LOCAL_OFFSET(src, srcw); \ - return sljit_emit_fop1_conv_sw_from_f64(compiler, op, dst, dstw, src, srcw); \ - } \ - CHECK(check_sljit_emit_fop1_conv_f64_from_sw(compiler, op, dst, dstw, src, srcw)); \ - ADJUST_LOCAL_OFFSET(dst, dstw); \ - ADJUST_LOCAL_OFFSET(src, srcw); \ - return sljit_emit_fop1_conv_f64_from_sw(compiler, op, dst, dstw, src, srcw); \ - } \ - CHECK(check_sljit_emit_fop1(compiler, op, dst, dstw, src, srcw)); \ - ADJUST_LOCAL_OFFSET(dst, dstw); \ - ADJUST_LOCAL_OFFSET(src, srcw); - -#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) \ - || (defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC) \ - || ((defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS) && !(defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1 && SLJIT_MIPS_REV < 6)) \ - || (defined SLJIT_CONFIG_RISCV && SLJIT_CONFIG_RISCV) \ - || (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X) - -static SLJIT_INLINE sljit_s32 sljit_emit_cmov_generic(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 dst_reg, - sljit_s32 src, sljit_sw srcw) -{ - struct sljit_label *label; - struct sljit_jump *jump; - sljit_s32 op = (type & SLJIT_32) ? SLJIT_MOV32 : SLJIT_MOV; - - SLJIT_SKIP_CHECKS(compiler); - jump = sljit_emit_jump(compiler, (type & ~SLJIT_32) ^ 0x1); - FAIL_IF(!jump); - - SLJIT_SKIP_CHECKS(compiler); - FAIL_IF(sljit_emit_op1(compiler, op, dst_reg, 0, src, srcw)); - - SLJIT_SKIP_CHECKS(compiler); - label = sljit_emit_label(compiler); - FAIL_IF(!label); - - sljit_set_label(jump, label); - return SLJIT_SUCCESS; -} - -#endif - -#if (!(defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS) || (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6)) \ - && !(defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) - -static sljit_s32 sljit_emit_mem_unaligned(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 reg, - sljit_s32 mem, sljit_sw memw) -{ - SLJIT_SKIP_CHECKS(compiler); - - if (type & SLJIT_MEM_STORE) - return sljit_emit_op1(compiler, type & (0xff | SLJIT_32), mem, memw, reg, 0); - return sljit_emit_op1(compiler, type & (0xff | SLJIT_32), reg, 0, mem, memw); -} - -#endif /* (!SLJIT_CONFIG_MIPS || SLJIT_MIPS_REV >= 6) && !SLJIT_CONFIG_ARM_V5 */ - -#if (!(defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS) || (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6)) \ - && !(defined SLJIT_CONFIG_ARM_32 && SLJIT_CONFIG_ARM_32) - -static sljit_s32 sljit_emit_fmem_unaligned(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 freg, - sljit_s32 mem, sljit_sw memw) -{ - SLJIT_SKIP_CHECKS(compiler); - - if (type & SLJIT_MEM_STORE) - return sljit_emit_fop1(compiler, type & (0xff | SLJIT_32), mem, memw, freg, 0); - return sljit_emit_fop1(compiler, type & (0xff | SLJIT_32), freg, 0, mem, memw); -} - -#endif /* (!SLJIT_CONFIG_MIPS || SLJIT_MIPS_REV >= 6) && !SLJIT_CONFIG_ARM */ - -/* CPU description section */ - -#if (defined SLJIT_32BIT_ARCHITECTURE && SLJIT_32BIT_ARCHITECTURE) -#define SLJIT_CPUINFO_PART1 " 32bit (" -#elif (defined SLJIT_64BIT_ARCHITECTURE && SLJIT_64BIT_ARCHITECTURE) -#define SLJIT_CPUINFO_PART1 " 64bit (" -#else -#error "Internal error: CPU type info missing" -#endif - -#if (defined SLJIT_LITTLE_ENDIAN && SLJIT_LITTLE_ENDIAN) -#define SLJIT_CPUINFO_PART2 "little endian + " -#elif (defined SLJIT_BIG_ENDIAN && SLJIT_BIG_ENDIAN) -#define SLJIT_CPUINFO_PART2 "big endian + " -#else -#error "Internal error: CPU type info missing" -#endif - -#if (defined SLJIT_UNALIGNED && SLJIT_UNALIGNED) -#define SLJIT_CPUINFO_PART3 "unaligned)" -#else -#define SLJIT_CPUINFO_PART3 "aligned)" -#endif - -#define SLJIT_CPUINFO SLJIT_CPUINFO_PART1 SLJIT_CPUINFO_PART2 SLJIT_CPUINFO_PART3 - -#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) -# include "sljitNativeX86_common.c" -#elif (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) -# include "sljitNativeARM_32.c" -#elif (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) -# include "sljitNativeARM_32.c" -#elif (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2) -# include "sljitNativeARM_T2_32.c" -#elif (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) -# include "sljitNativeARM_64.c" -#elif (defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC) -# include "sljitNativePPC_common.c" -#elif (defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS) -# include "sljitNativeMIPS_common.c" -#elif (defined SLJIT_CONFIG_RISCV && SLJIT_CONFIG_RISCV) -# include "sljitNativeRISCV_common.c" -#elif (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X) -# include "sljitNativeS390X.c" -#endif - -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) - /* At the moment the pointer size is always equal to sljit_sw. May be changed in the future. */ - if (src == SLJIT_RETURN_REG && (op == SLJIT_MOV || op == SLJIT_MOV_P)) - return SLJIT_SUCCESS; -#else - if (src == SLJIT_RETURN_REG && (op == SLJIT_MOV || op == SLJIT_MOV_U32 || op == SLJIT_MOV_S32 || op == SLJIT_MOV_P)) - return SLJIT_SUCCESS; -#endif - - SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_op1(compiler, op, SLJIT_RETURN_REG, 0, src, srcw); -} - -#if !(defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) \ - && !((defined SLJIT_CONFIG_ARM_32 && SLJIT_CONFIG_ARM_32) && defined __SOFTFP__) - -static SLJIT_INLINE sljit_s32 emit_fmov_before_return(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw) -{ - if (src == SLJIT_FR0) - return SLJIT_SUCCESS; - - SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_fop1(compiler, op, SLJIT_RETURN_FREG, 0, src, srcw); -} - -#endif /* !SLJIT_CONFIG_X86_32 && !(SLJIT_CONFIG_ARM_32 && __SOFTFP__) */ - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw) -{ - CHECK_ERROR(); - CHECK(check_sljit_emit_return(compiler, op, src, srcw)); - - if (GET_OPCODE(op) < SLJIT_MOV_F64) { - FAIL_IF(emit_mov_before_return(compiler, op, src, srcw)); - } else { - FAIL_IF(emit_fmov_before_return(compiler, op, src, srcw)); - } - - SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_return_void(compiler); -} - -#if !(defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS) \ - && !(defined SLJIT_CONFIG_RISCV && SLJIT_CONFIG_RISCV) - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - /* Default compare for most architectures. */ - sljit_s32 flags, tmp_src, condition; - sljit_sw tmp_srcw; - - CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_cmp(compiler, type, src1, src1w, src2, src2w)); - - condition = type & 0xff; -#if (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) - if ((condition == SLJIT_EQUAL || condition == SLJIT_NOT_EQUAL)) { - if ((src1 & SLJIT_IMM) && !src1w) { - src1 = src2; - src1w = src2w; - src2 = SLJIT_IMM; - src2w = 0; - } - if ((src2 & SLJIT_IMM) && !src2w) - return emit_cmp_to0(compiler, type, src1, src1w); - } -#endif - - if (SLJIT_UNLIKELY((src1 & SLJIT_IMM) && !(src2 & SLJIT_IMM))) { - /* Immediate is preferred as second argument by most architectures. */ - switch (condition) { - case SLJIT_LESS: - condition = SLJIT_GREATER; - break; - case SLJIT_GREATER_EQUAL: - condition = SLJIT_LESS_EQUAL; - break; - case SLJIT_GREATER: - condition = SLJIT_LESS; - break; - case SLJIT_LESS_EQUAL: - condition = SLJIT_GREATER_EQUAL; - break; - case SLJIT_SIG_LESS: - condition = SLJIT_SIG_GREATER; - break; - case SLJIT_SIG_GREATER_EQUAL: - condition = SLJIT_SIG_LESS_EQUAL; - break; - case SLJIT_SIG_GREATER: - condition = SLJIT_SIG_LESS; - break; - case SLJIT_SIG_LESS_EQUAL: - condition = SLJIT_SIG_GREATER_EQUAL; - break; - } - - type = condition | (type & (SLJIT_32 | SLJIT_REWRITABLE_JUMP)); - tmp_src = src1; - src1 = src2; - src2 = tmp_src; - tmp_srcw = src1w; - src1w = src2w; - src2w = tmp_srcw; - } - - if (condition <= SLJIT_NOT_ZERO) - flags = SLJIT_SET_Z; - else - flags = condition << VARIABLE_FLAG_SHIFT; - - SLJIT_SKIP_CHECKS(compiler); - PTR_FAIL_IF(sljit_emit_op2u(compiler, - SLJIT_SUB | flags | (type & SLJIT_32), src1, src1w, src2, src2w)); - - SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_jump(compiler, condition | (type & (SLJIT_REWRITABLE_JUMP | SLJIT_32))); -} - -#endif /* !SLJIT_CONFIG_MIPS */ - -#if (defined SLJIT_CONFIG_ARM && SLJIT_CONFIG_ARM) - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_cmp_info(sljit_s32 type) -{ - if (type < SLJIT_UNORDERED || type > SLJIT_ORDERED_LESS_EQUAL) - return 0; - - switch (type) { - case SLJIT_UNORDERED_OR_EQUAL: - case SLJIT_ORDERED_NOT_EQUAL: - return 0; - } - - return 1; -} - -#endif /* SLJIT_CONFIG_ARM */ - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_fcmp(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_fcmp(compiler, type, src1, src1w, src2, src2w)); - - SLJIT_SKIP_CHECKS(compiler); - sljit_emit_fop1(compiler, SLJIT_CMP_F64 | ((type & 0xff) << VARIABLE_FLAG_SHIFT) | (type & SLJIT_32), src1, src1w, src2, src2w); - - SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_jump(compiler, type); -} - -#if !(defined SLJIT_CONFIG_ARM && SLJIT_CONFIG_ARM) \ - && !(defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC) - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem_update(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 reg, - sljit_s32 mem, sljit_sw memw) -{ - CHECK_ERROR(); - CHECK(check_sljit_emit_mem_update(compiler, type, reg, mem, memw)); - SLJIT_UNUSED_ARG(type); - SLJIT_UNUSED_ARG(reg); - SLJIT_UNUSED_ARG(mem); - SLJIT_UNUSED_ARG(memw); - - return SLJIT_ERR_UNSUPPORTED; -} - -#endif /* !SLJIT_CONFIG_ARM && !SLJIT_CONFIG_PPC */ - -#if !(defined SLJIT_CONFIG_ARM_32 && SLJIT_CONFIG_ARM_32) \ - && !(defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS) - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fmem(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 freg, - sljit_s32 mem, sljit_sw memw) -{ - CHECK_ERROR(); - CHECK(check_sljit_emit_fmem(compiler, type, freg, mem, memw)); - - return sljit_emit_fmem_unaligned(compiler, type, freg, mem, memw); -} - -#endif /* !SLJIT_CONFIG_ARM_32 && !SLJIT_CONFIG_MIPS */ - -#if !(defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) \ - && !(defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC) - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fmem_update(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 freg, - sljit_s32 mem, sljit_sw memw) -{ - CHECK_ERROR(); - CHECK(check_sljit_emit_fmem_update(compiler, type, freg, mem, memw)); - SLJIT_UNUSED_ARG(type); - SLJIT_UNUSED_ARG(freg); - SLJIT_UNUSED_ARG(mem); - SLJIT_UNUSED_ARG(memw); - - return SLJIT_ERR_UNSUPPORTED; -} - -#endif /* !SLJIT_CONFIG_ARM_64 && !SLJIT_CONFIG_PPC */ - -#if !(defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) \ - && !(defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_local_base(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw offset) -{ - CHECK_ERROR(); - CHECK(check_sljit_get_local_base(compiler, dst, dstw, offset)); - - ADJUST_LOCAL_OFFSET(SLJIT_MEM1(SLJIT_SP), offset); - - SLJIT_SKIP_CHECKS(compiler); - - if (offset != 0) - return sljit_emit_op2(compiler, SLJIT_ADD, dst, dstw, SLJIT_SP, 0, SLJIT_IMM, offset); - return sljit_emit_op1(compiler, SLJIT_MOV, dst, dstw, SLJIT_SP, 0); -} - -#endif - -#else /* SLJIT_CONFIG_UNSUPPORTED */ - -/* Empty function bodies for those machines, which are not (yet) supported. */ - -SLJIT_API_FUNC_ATTRIBUTE const char* sljit_get_platform_name(void) -{ - return "unsupported"; -} - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_compiler* sljit_create_compiler(void *allocator_data, void *exec_allocator_data) -{ - SLJIT_UNUSED_ARG(allocator_data); - SLJIT_UNUSED_ARG(exec_allocator_data); - SLJIT_UNREACHABLE(); - return NULL; -} - -SLJIT_API_FUNC_ATTRIBUTE void sljit_free_compiler(struct sljit_compiler *compiler) -{ - SLJIT_UNUSED_ARG(compiler); - SLJIT_UNREACHABLE(); -} - -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_compiler_memory_error(struct sljit_compiler *compiler) -{ - SLJIT_UNUSED_ARG(compiler); - SLJIT_UNREACHABLE(); -} - -SLJIT_API_FUNC_ATTRIBUTE void* sljit_alloc_memory(struct sljit_compiler *compiler, sljit_s32 size) -{ - SLJIT_UNUSED_ARG(compiler); - SLJIT_UNUSED_ARG(size); - SLJIT_UNREACHABLE(); - return NULL; -} - -#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) -SLJIT_API_FUNC_ATTRIBUTE void sljit_compiler_verbose(struct sljit_compiler *compiler, FILE* verbose) -{ - SLJIT_UNUSED_ARG(compiler); - SLJIT_UNUSED_ARG(verbose); - SLJIT_UNREACHABLE(); -} -#endif - -SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler) -{ - SLJIT_UNUSED_ARG(compiler); - SLJIT_UNREACHABLE(); - return NULL; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type) -{ - SLJIT_UNUSED_ARG(feature_type); - SLJIT_UNREACHABLE(); - return 0; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_cmp_info(sljit_s32 type) -{ - SLJIT_UNUSED_ARG(type); - SLJIT_UNREACHABLE(); - return 0; -} - -SLJIT_API_FUNC_ATTRIBUTE void sljit_free_code(void* code, void *exec_allocator_data) -{ - SLJIT_UNUSED_ARG(code); - SLJIT_UNUSED_ARG(exec_allocator_data); - SLJIT_UNREACHABLE(); -} - -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, - sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size) -{ - SLJIT_UNUSED_ARG(compiler); - SLJIT_UNUSED_ARG(options); - SLJIT_UNUSED_ARG(arg_types); - SLJIT_UNUSED_ARG(scratches); - SLJIT_UNUSED_ARG(saveds); - SLJIT_UNUSED_ARG(fscratches); - SLJIT_UNUSED_ARG(fsaveds); - SLJIT_UNUSED_ARG(local_size); - SLJIT_UNREACHABLE(); - return SLJIT_ERR_UNSUPPORTED; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(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) -{ - SLJIT_UNUSED_ARG(compiler); - SLJIT_UNUSED_ARG(options); - SLJIT_UNUSED_ARG(arg_types); - SLJIT_UNUSED_ARG(scratches); - SLJIT_UNUSED_ARG(saveds); - SLJIT_UNUSED_ARG(fscratches); - SLJIT_UNUSED_ARG(fsaveds); - SLJIT_UNUSED_ARG(local_size); - SLJIT_UNREACHABLE(); - return SLJIT_ERR_UNSUPPORTED; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_void(struct sljit_compiler *compiler) -{ - SLJIT_UNUSED_ARG(compiler); - SLJIT_UNREACHABLE(); - return SLJIT_ERR_UNSUPPORTED; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw) -{ - SLJIT_UNUSED_ARG(compiler); - SLJIT_UNUSED_ARG(op); - SLJIT_UNUSED_ARG(src); - SLJIT_UNUSED_ARG(srcw); - SLJIT_UNREACHABLE(); - return SLJIT_ERR_UNSUPPORTED; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_to(struct sljit_compiler *compiler, sljit_s32 src, sljit_sw srcw) -{ - SLJIT_UNUSED_ARG(compiler); - SLJIT_UNUSED_ARG(src); - SLJIT_UNUSED_ARG(srcw); - SLJIT_UNREACHABLE(); - return SLJIT_ERR_UNSUPPORTED; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw) -{ - SLJIT_UNUSED_ARG(compiler); - SLJIT_UNUSED_ARG(dst); - SLJIT_UNUSED_ARG(dstw); - SLJIT_UNREACHABLE(); - return SLJIT_ERR_UNSUPPORTED; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compiler, sljit_s32 op) -{ - SLJIT_UNUSED_ARG(compiler); - SLJIT_UNUSED_ARG(op); - SLJIT_UNREACHABLE(); - return SLJIT_ERR_UNSUPPORTED; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src, sljit_sw srcw) -{ - SLJIT_UNUSED_ARG(compiler); - SLJIT_UNUSED_ARG(op); - SLJIT_UNUSED_ARG(dst); - SLJIT_UNUSED_ARG(dstw); - SLJIT_UNUSED_ARG(src); - SLJIT_UNUSED_ARG(srcw); - SLJIT_UNREACHABLE(); - return SLJIT_ERR_UNSUPPORTED; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - SLJIT_UNUSED_ARG(compiler); - SLJIT_UNUSED_ARG(op); - SLJIT_UNUSED_ARG(dst); - SLJIT_UNUSED_ARG(dstw); - SLJIT_UNUSED_ARG(src1); - SLJIT_UNUSED_ARG(src1w); - SLJIT_UNUSED_ARG(src2); - SLJIT_UNUSED_ARG(src2w); - SLJIT_UNREACHABLE(); - return SLJIT_ERR_UNSUPPORTED; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - SLJIT_UNUSED_ARG(compiler); - SLJIT_UNUSED_ARG(op); - SLJIT_UNUSED_ARG(src1); - SLJIT_UNUSED_ARG(src1w); - SLJIT_UNUSED_ARG(src2); - SLJIT_UNUSED_ARG(src2w); - SLJIT_UNREACHABLE(); - return SLJIT_ERR_UNSUPPORTED; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 src_dst, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - SLJIT_UNUSED_ARG(compiler); - SLJIT_UNUSED_ARG(op); - SLJIT_UNUSED_ARG(src_dst); - SLJIT_UNUSED_ARG(src1); - SLJIT_UNUSED_ARG(src1w); - SLJIT_UNUSED_ARG(src2); - SLJIT_UNUSED_ARG(src2w); - SLJIT_UNREACHABLE(); - return SLJIT_ERR_UNSUPPORTED; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 src, sljit_sw srcw) -{ - SLJIT_UNUSED_ARG(compiler); - SLJIT_UNUSED_ARG(op); - SLJIT_UNUSED_ARG(src); - SLJIT_UNUSED_ARG(srcw); - SLJIT_UNREACHABLE(); - return SLJIT_ERR_UNSUPPORTED; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 reg) -{ - SLJIT_UNREACHABLE(); - return reg; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler, - void *instruction, sljit_u32 size) -{ - SLJIT_UNUSED_ARG(compiler); - SLJIT_UNUSED_ARG(instruction); - SLJIT_UNUSED_ARG(size); - SLJIT_UNREACHABLE(); - return SLJIT_ERR_UNSUPPORTED; -} - -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_current_flags(struct sljit_compiler *compiler, sljit_s32 current_flags) -{ - SLJIT_UNUSED_ARG(compiler); - SLJIT_UNUSED_ARG(current_flags); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src, sljit_sw srcw) -{ - SLJIT_UNUSED_ARG(compiler); - SLJIT_UNUSED_ARG(op); - SLJIT_UNUSED_ARG(dst); - SLJIT_UNUSED_ARG(dstw); - SLJIT_UNUSED_ARG(src); - SLJIT_UNUSED_ARG(srcw); - SLJIT_UNREACHABLE(); - return SLJIT_ERR_UNSUPPORTED; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - SLJIT_UNUSED_ARG(compiler); - SLJIT_UNUSED_ARG(op); - SLJIT_UNUSED_ARG(dst); - SLJIT_UNUSED_ARG(dstw); - SLJIT_UNUSED_ARG(src1); - SLJIT_UNUSED_ARG(src1w); - SLJIT_UNUSED_ARG(src2); - SLJIT_UNUSED_ARG(src2w); - SLJIT_UNREACHABLE(); - return SLJIT_ERR_UNSUPPORTED; -} - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compiler *compiler) -{ - SLJIT_UNUSED_ARG(compiler); - SLJIT_UNREACHABLE(); - return NULL; -} - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type) -{ - SLJIT_UNUSED_ARG(compiler); - SLJIT_UNUSED_ARG(type); - SLJIT_UNREACHABLE(); - return NULL; -} - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_call(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 arg_types) -{ - SLJIT_UNUSED_ARG(compiler); - SLJIT_UNUSED_ARG(type); - SLJIT_UNUSED_ARG(arg_types); - SLJIT_UNREACHABLE(); - return NULL; -} - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - SLJIT_UNUSED_ARG(compiler); - SLJIT_UNUSED_ARG(type); - SLJIT_UNUSED_ARG(src1); - SLJIT_UNUSED_ARG(src1w); - SLJIT_UNUSED_ARG(src2); - SLJIT_UNUSED_ARG(src2w); - SLJIT_UNREACHABLE(); - return NULL; -} - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_fcmp(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - SLJIT_UNUSED_ARG(compiler); - SLJIT_UNUSED_ARG(type); - SLJIT_UNUSED_ARG(src1); - SLJIT_UNUSED_ARG(src1w); - SLJIT_UNUSED_ARG(src2); - SLJIT_UNUSED_ARG(src2w); - SLJIT_UNREACHABLE(); - return NULL; -} - -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_label(struct sljit_jump *jump, struct sljit_label* label) -{ - SLJIT_UNUSED_ARG(jump); - SLJIT_UNUSED_ARG(label); - SLJIT_UNREACHABLE(); -} - -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_target(struct sljit_jump *jump, sljit_uw target) -{ - SLJIT_UNUSED_ARG(jump); - SLJIT_UNUSED_ARG(target); - SLJIT_UNREACHABLE(); -} - -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_put_label(struct sljit_put_label *put_label, struct sljit_label *label) -{ - SLJIT_UNUSED_ARG(put_label); - SLJIT_UNUSED_ARG(label); - SLJIT_UNREACHABLE(); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 src, sljit_sw srcw) -{ - SLJIT_UNUSED_ARG(compiler); - SLJIT_UNUSED_ARG(type); - SLJIT_UNUSED_ARG(src); - SLJIT_UNUSED_ARG(srcw); - SLJIT_UNREACHABLE(); - return SLJIT_ERR_UNSUPPORTED; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 arg_types, - sljit_s32 src, sljit_sw srcw) -{ - SLJIT_UNUSED_ARG(compiler); - SLJIT_UNUSED_ARG(type); - SLJIT_UNUSED_ARG(arg_types); - SLJIT_UNUSED_ARG(src); - SLJIT_UNUSED_ARG(srcw); - SLJIT_UNREACHABLE(); - return SLJIT_ERR_UNSUPPORTED; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 type) -{ - SLJIT_UNUSED_ARG(compiler); - SLJIT_UNUSED_ARG(op); - SLJIT_UNUSED_ARG(dst); - SLJIT_UNUSED_ARG(dstw); - SLJIT_UNUSED_ARG(type); - SLJIT_UNREACHABLE(); - return SLJIT_ERR_UNSUPPORTED; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 dst_reg, - sljit_s32 src, sljit_sw srcw) -{ - SLJIT_UNUSED_ARG(compiler); - SLJIT_UNUSED_ARG(type); - SLJIT_UNUSED_ARG(dst_reg); - SLJIT_UNUSED_ARG(src); - SLJIT_UNUSED_ARG(srcw); - SLJIT_UNREACHABLE(); - return SLJIT_ERR_UNSUPPORTED; -} - -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) -{ - SLJIT_UNUSED_ARG(compiler); - SLJIT_UNUSED_ARG(type); - SLJIT_UNUSED_ARG(reg); - SLJIT_UNUSED_ARG(mem); - SLJIT_UNUSED_ARG(memw); - SLJIT_UNREACHABLE(); - return SLJIT_ERR_UNSUPPORTED; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem_update(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 reg, sljit_s32 mem, sljit_sw memw) -{ - SLJIT_UNUSED_ARG(compiler); - SLJIT_UNUSED_ARG(type); - SLJIT_UNUSED_ARG(reg); - SLJIT_UNUSED_ARG(mem); - SLJIT_UNUSED_ARG(memw); - SLJIT_UNREACHABLE(); - return SLJIT_ERR_UNSUPPORTED; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fmem(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 freg, sljit_s32 mem, sljit_sw memw) -{ - SLJIT_UNUSED_ARG(compiler); - SLJIT_UNUSED_ARG(type); - SLJIT_UNUSED_ARG(freg); - SLJIT_UNUSED_ARG(mem); - SLJIT_UNUSED_ARG(memw); - SLJIT_UNREACHABLE(); - return SLJIT_ERR_UNSUPPORTED; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fmem_update(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 freg, sljit_s32 mem, sljit_sw memw) -{ - SLJIT_UNUSED_ARG(compiler); - SLJIT_UNUSED_ARG(type); - SLJIT_UNUSED_ARG(freg); - SLJIT_UNUSED_ARG(mem); - SLJIT_UNUSED_ARG(memw); - SLJIT_UNREACHABLE(); - return SLJIT_ERR_UNSUPPORTED; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_local_base(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw offset) -{ - SLJIT_UNUSED_ARG(compiler); - SLJIT_UNUSED_ARG(dst); - SLJIT_UNUSED_ARG(dstw); - SLJIT_UNUSED_ARG(offset); - SLJIT_UNREACHABLE(); - return SLJIT_ERR_UNSUPPORTED; -} - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw initval) -{ - SLJIT_UNUSED_ARG(compiler); - SLJIT_UNUSED_ARG(dst); - SLJIT_UNUSED_ARG(dstw); - SLJIT_UNUSED_ARG(initval); - SLJIT_UNREACHABLE(); - return NULL; -} - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label* sljit_emit_put_label(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw) -{ - SLJIT_UNUSED_ARG(compiler); - SLJIT_UNUSED_ARG(dst); - SLJIT_UNUSED_ARG(dstw); - return NULL; -} - -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset) -{ - SLJIT_UNUSED_ARG(addr); - SLJIT_UNUSED_ARG(new_target); - SLJIT_UNUSED_ARG(executable_offset); - SLJIT_UNREACHABLE(); -} - -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset) -{ - SLJIT_UNUSED_ARG(addr); - SLJIT_UNUSED_ARG(new_constant); - SLJIT_UNUSED_ARG(executable_offset); - SLJIT_UNREACHABLE(); -} - -#endif /* !SLJIT_CONFIG_UNSUPPORTED */ diff --git a/modules/regex/pcre2/src/sljit/sljitLir.h b/modules/regex/pcre2/src/sljit/sljitLir.h deleted file mode 100644 index c6a0832..0000000 --- a/modules/regex/pcre2/src/sljit/sljitLir.h +++ /dev/null @@ -1,1823 +0,0 @@ -/* - * 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. - */ - -#ifndef SLJIT_LIR_H_ -#define SLJIT_LIR_H_ - -/* - ------------------------------------------------------------------------ - Stack-Less JIT compiler for multiple architectures (x86, ARM, PowerPC) - ------------------------------------------------------------------------ - - Short description - Advantages: - - The execution can be continued from any LIR instruction. In other - words, it is possible to jump to any label from anywhere, even from - a code fragment, which is compiled later, as long as the compiling - context is the same. See sljit_emit_enter for more details. - - Supports self modifying code: target of any jump and call - instructions and some constant values can be dynamically modified - during runtime. See SLJIT_REWRITABLE_JUMP. - - although it is not suggested to do it frequently - - can be used for inline caching: save an important value once - in the instruction stream - - A fixed stack space can be allocated for local variables - - The compiler is thread-safe - - The compiler is highly configurable through preprocessor macros. - You can disable unneeded features (multithreading in single - threaded applications), and you can use your own system functions - (including memory allocators). See sljitConfig.h. - Disadvantages: - - The compiler is more like a platform independent assembler, so - there is no built-in variable management. Registers and stack must - be managed manually (the name of the compiler refers to this). - In practice: - - This approach is very effective for interpreters - - One of the saved registers typically points to a stack interface - - It can jump to any exception handler anytime (even if it belongs - to another function) - - Hot paths can be modified during runtime reflecting the changes - of the fastest execution path of the dynamic language - - SLJIT supports complex memory addressing modes - - mainly position and context independent code (except some cases) - - For valgrind users: - - pass --smc-check=all argument to valgrind, since JIT is a "self-modifying code" -*/ - -#if (defined SLJIT_HAVE_CONFIG_PRE && SLJIT_HAVE_CONFIG_PRE) -#include "sljitConfigPre.h" -#endif /* SLJIT_HAVE_CONFIG_PRE */ - -#include "sljitConfig.h" - -/* The following header file defines useful macros for fine tuning -SLJIT based code generators. They are listed in the beginning -of sljitConfigInternal.h */ - -#include "sljitConfigInternal.h" - -#if (defined SLJIT_HAVE_CONFIG_POST && SLJIT_HAVE_CONFIG_POST) -#include "sljitConfigPost.h" -#endif /* SLJIT_HAVE_CONFIG_POST */ - -#ifdef __cplusplus -extern "C" { -#endif - -/* Version numbers. */ -#define SLJIT_MAJOR_VERSION 0 -#define SLJIT_MINOR_VERSION 95 - -/* --------------------------------------------------------------------- */ -/* Error codes */ -/* --------------------------------------------------------------------- */ - -/* Indicates no error. */ -#define SLJIT_SUCCESS 0 -/* After the call of sljit_generate_code(), the error code of the compiler - is set to this value to avoid further code generation. - The complier should be freed after sljit_generate_code(). */ -#define SLJIT_ERR_COMPILED 1 -/* Cannot allocate non-executable memory. */ -#define SLJIT_ERR_ALLOC_FAILED 2 -/* Cannot allocate executable memory. - Only sljit_generate_code() returns with this error code. */ -#define SLJIT_ERR_EX_ALLOC_FAILED 3 -/* Return value for SLJIT_CONFIG_UNSUPPORTED placeholder architecture. */ -#define SLJIT_ERR_UNSUPPORTED 4 -/* An ivalid argument is passed to any SLJIT function. */ -#define SLJIT_ERR_BAD_ARGUMENT 5 - -/* --------------------------------------------------------------------- */ -/* Registers */ -/* --------------------------------------------------------------------- */ - -/* - Scratch (R) registers: registers which may not preserve their values - across function calls. - - Saved (S) registers: registers which preserve their values across - function calls. - - The scratch and saved register sets overlap. The last scratch register - is the first saved register, the one before the last is the second saved - register, and so on. - - If an architecture provides two scratch and three saved registers, - its scratch and saved register sets are the following: - - R0 | | R0 is always a scratch register - R1 | | R1 is always a scratch register - [R2] | S2 | R2 and S2 represent the same physical register - [R3] | S1 | R3 and S1 represent the same physical register - [R4] | S0 | R4 and S0 represent the same physical register - - Note: SLJIT_NUMBER_OF_SCRATCH_REGISTERS would be 2 and - SLJIT_NUMBER_OF_SAVED_REGISTERS would be 3 for this architecture. - - Note: On all supported architectures SLJIT_NUMBER_OF_REGISTERS >= 12 - and SLJIT_NUMBER_OF_SAVED_REGISTERS >= 6. However, 6 registers - are virtual on x86-32. See below. - - The purpose of this definition is convenience: saved registers can - be used as extra scratch registers. For example four registers can - be specified as scratch registers and the fifth one as saved register - on the CPU above and any user code which requires four scratch - registers can run unmodified. The SLJIT compiler automatically saves - the content of the two extra scratch register on the stack. Scratch - registers can also be preserved by saving their value on the stack - but this needs to be done manually. - - Note: To emphasize that registers assigned to R2-R4 are saved - registers, they are enclosed by square brackets. - - Note: sljit_emit_enter and sljit_set_context defines whether a register - is S or R register. E.g: when 3 scratches and 1 saved is mapped - by sljit_emit_enter, the allowed register set will be: R0-R2 and - S0. Although S2 is mapped to the same position as R2, it does not - available in the current configuration. Furthermore the S1 register - is not available at all. -*/ - -/* Scratch registers. */ -#define SLJIT_R0 1 -#define SLJIT_R1 2 -#define SLJIT_R2 3 -/* Note: on x86-32, R3 - R6 (same as S3 - S6) are emulated (they - are allocated on the stack). These registers are called virtual - and cannot be used for memory addressing (cannot be part of - any SLJIT_MEM1, SLJIT_MEM2 construct). There is no such - limitation on other CPUs. See sljit_get_register_index(). */ -#define SLJIT_R3 4 -#define SLJIT_R4 5 -#define SLJIT_R5 6 -#define SLJIT_R6 7 -#define SLJIT_R7 8 -#define SLJIT_R8 9 -#define SLJIT_R9 10 -/* All R registers provided by the architecture can be accessed by SLJIT_R(i) - The i parameter must be >= 0 and < SLJIT_NUMBER_OF_REGISTERS. */ -#define SLJIT_R(i) (1 + (i)) - -/* Saved registers. */ -#define SLJIT_S0 (SLJIT_NUMBER_OF_REGISTERS) -#define SLJIT_S1 (SLJIT_NUMBER_OF_REGISTERS - 1) -#define SLJIT_S2 (SLJIT_NUMBER_OF_REGISTERS - 2) -/* Note: on x86-32, S3 - S6 (same as R3 - R6) are emulated (they - are allocated on the stack). These registers are called virtual - and cannot be used for memory addressing (cannot be part of - any SLJIT_MEM1, SLJIT_MEM2 construct). There is no such - limitation on other CPUs. See sljit_get_register_index(). */ -#define SLJIT_S3 (SLJIT_NUMBER_OF_REGISTERS - 3) -#define SLJIT_S4 (SLJIT_NUMBER_OF_REGISTERS - 4) -#define SLJIT_S5 (SLJIT_NUMBER_OF_REGISTERS - 5) -#define SLJIT_S6 (SLJIT_NUMBER_OF_REGISTERS - 6) -#define SLJIT_S7 (SLJIT_NUMBER_OF_REGISTERS - 7) -#define SLJIT_S8 (SLJIT_NUMBER_OF_REGISTERS - 8) -#define SLJIT_S9 (SLJIT_NUMBER_OF_REGISTERS - 9) -/* All S registers provided by the architecture can be accessed by SLJIT_S(i) - The i parameter must be >= 0 and < SLJIT_NUMBER_OF_SAVED_REGISTERS. */ -#define SLJIT_S(i) (SLJIT_NUMBER_OF_REGISTERS - (i)) - -/* Registers >= SLJIT_FIRST_SAVED_REG are saved registers. */ -#define SLJIT_FIRST_SAVED_REG (SLJIT_S0 - SLJIT_NUMBER_OF_SAVED_REGISTERS + 1) - -/* The SLJIT_SP provides direct access to the linear stack space allocated by - sljit_emit_enter. It can only be used in the following form: SLJIT_MEM1(SLJIT_SP). - The immediate offset is extended by the relative stack offset automatically. - The sljit_get_local_base can be used to obtain the real address of a value. */ -#define SLJIT_SP (SLJIT_NUMBER_OF_REGISTERS + 1) - -/* Return with machine word. */ - -#define SLJIT_RETURN_REG SLJIT_R0 - -/* --------------------------------------------------------------------- */ -/* Floating point registers */ -/* --------------------------------------------------------------------- */ - -/* Each floating point register can store a 32 or a 64 bit precision - value. The FR and FS register sets are overlap in the same way as R - and S register sets. See above. */ - -/* Floating point scratch registers. */ -#define SLJIT_FR0 1 -#define SLJIT_FR1 2 -#define SLJIT_FR2 3 -#define SLJIT_FR3 4 -#define SLJIT_FR4 5 -#define SLJIT_FR5 6 -/* All FR registers provided by the architecture can be accessed by SLJIT_FR(i) - The i parameter must be >= 0 and < SLJIT_NUMBER_OF_FLOAT_REGISTERS. */ -#define SLJIT_FR(i) (1 + (i)) - -/* Floating point saved registers. */ -#define SLJIT_FS0 (SLJIT_NUMBER_OF_FLOAT_REGISTERS) -#define SLJIT_FS1 (SLJIT_NUMBER_OF_FLOAT_REGISTERS - 1) -#define SLJIT_FS2 (SLJIT_NUMBER_OF_FLOAT_REGISTERS - 2) -#define SLJIT_FS3 (SLJIT_NUMBER_OF_FLOAT_REGISTERS - 3) -#define SLJIT_FS4 (SLJIT_NUMBER_OF_FLOAT_REGISTERS - 4) -#define SLJIT_FS5 (SLJIT_NUMBER_OF_FLOAT_REGISTERS - 5) -/* All S registers provided by the architecture can be accessed by SLJIT_FS(i) - The i parameter must be >= 0 and < SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS. */ -#define SLJIT_FS(i) (SLJIT_NUMBER_OF_FLOAT_REGISTERS - (i)) - -/* Float registers >= SLJIT_FIRST_SAVED_FLOAT_REG are saved registers. */ -#define SLJIT_FIRST_SAVED_FLOAT_REG (SLJIT_FS0 - SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS + 1) - -/* Return with floating point arg. */ - -#define SLJIT_RETURN_FREG SLJIT_FR0 - -/* --------------------------------------------------------------------- */ -/* Argument type definitions */ -/* --------------------------------------------------------------------- */ - -/* The following argument type definitions are used by sljit_emit_enter, - sljit_set_context, sljit_emit_call, and sljit_emit_icall functions. - - As for sljit_emit_call and sljit_emit_icall, the first integer argument - must be placed into SLJIT_R0, the second one into SLJIT_R1, and so on. - Similarly the first floating point argument must be placed into SLJIT_FR0, - the second one into SLJIT_FR1, and so on. - - As for sljit_emit_enter, the integer arguments can be stored in scratch - or saved registers. The first integer argument without _R postfix is - stored in SLJIT_S0, the next one in SLJIT_S1, and so on. The integer - arguments with _R postfix are placed into scratch registers. The index - of the scratch register is the count of the previous integer arguments - starting from SLJIT_R0. The floating point arguments are always placed - into SLJIT_FR0, SLJIT_FR1, and so on. - - Note: if a function is called by sljit_emit_call/sljit_emit_icall and - an argument is stored in a scratch register by sljit_emit_enter, - that argument uses the same scratch register index for both - integer and floating point arguments. - - Example function definition: - sljit_f32 SLJIT_FUNC example_c_callback(void *arg_a, - sljit_f64 arg_b, sljit_u32 arg_c, sljit_f32 arg_d); - - Argument type definition: - SLJIT_ARG_RETURN(SLJIT_ARG_TYPE_F32) - | SLJIT_ARG_VALUE(SLJIT_ARG_TYPE_P, 1) | SLJIT_ARG_VALUE(SLJIT_ARG_TYPE_F64, 2) - | SLJIT_ARG_VALUE(SLJIT_ARG_TYPE_32, 3) | SLJIT_ARG_VALUE(SLJIT_ARG_TYPE_F32, 4) - - Short form of argument type definition: - SLJIT_ARGS4(32, P, F64, 32, F32) - - Argument passing: - arg_a must be placed in SLJIT_R0 - arg_c must be placed in SLJIT_R1 - arg_b must be placed in SLJIT_FR0 - arg_d must be placed in SLJIT_FR1 - - Examples for argument processing by sljit_emit_enter: - SLJIT_ARGS4(VOID, P, 32_R, F32, W) - Arguments are placed into: SLJIT_S0, SLJIT_R1, SLJIT_FR0, SLJIT_S1 - - SLJIT_ARGS4(VOID, W, W_R, W, W_R) - Arguments are placed into: SLJIT_S0, SLJIT_R1, SLJIT_S1, SLJIT_R3 - - SLJIT_ARGS4(VOID, F64, W, F32, W_R) - Arguments are placed into: SLJIT_FR0, SLJIT_S0, SLJIT_FR1, SLJIT_R1 - - Note: it is recommended to pass the scratch arguments first - followed by the saved arguments: - - SLJIT_ARGS4(VOID, W_R, W_R, W, W) - Arguments are placed into: SLJIT_R0, SLJIT_R1, SLJIT_S0, SLJIT_S1 -*/ - -/* The following flag is only allowed for the integer arguments of - sljit_emit_enter. When the flag is set, the integer argument is - stored in a scratch register instead of a saved register. */ -#define SLJIT_ARG_TYPE_SCRATCH_REG 0x8 - -/* Void result, can only be used by SLJIT_ARG_RETURN. */ -#define SLJIT_ARG_TYPE_VOID 0 -/* Machine word sized integer argument or result. */ -#define SLJIT_ARG_TYPE_W 1 -#define SLJIT_ARG_TYPE_W_R (SLJIT_ARG_TYPE_W | SLJIT_ARG_TYPE_SCRATCH_REG) -/* 32 bit integer argument or result. */ -#define SLJIT_ARG_TYPE_32 2 -#define SLJIT_ARG_TYPE_32_R (SLJIT_ARG_TYPE_32 | SLJIT_ARG_TYPE_SCRATCH_REG) -/* Pointer sized integer argument or result. */ -#define SLJIT_ARG_TYPE_P 3 -#define SLJIT_ARG_TYPE_P_R (SLJIT_ARG_TYPE_P | SLJIT_ARG_TYPE_SCRATCH_REG) -/* 64 bit floating point argument or result. */ -#define SLJIT_ARG_TYPE_F64 4 -/* 32 bit floating point argument or result. */ -#define SLJIT_ARG_TYPE_F32 5 - -#define SLJIT_ARG_SHIFT 4 -#define SLJIT_ARG_RETURN(type) (type) -#define SLJIT_ARG_VALUE(type, idx) ((type) << ((idx) * SLJIT_ARG_SHIFT)) - -/* Simplified argument list definitions. - - The following definition: - SLJIT_ARG_RETURN(SLJIT_ARG_TYPE_W) | SLJIT_ARG_VALUE(SLJIT_ARG_TYPE_F32, 1) - - can be shortened to: - SLJIT_ARGS1(W, F32) -*/ - -#define SLJIT_ARG_TO_TYPE(type) SLJIT_ARG_TYPE_ ## type - -#define SLJIT_ARGS0(ret) \ - SLJIT_ARG_RETURN(SLJIT_ARG_TO_TYPE(ret)) - -#define SLJIT_ARGS1(ret, arg1) \ - (SLJIT_ARGS0(ret) | SLJIT_ARG_VALUE(SLJIT_ARG_TO_TYPE(arg1), 1)) - -#define SLJIT_ARGS2(ret, arg1, arg2) \ - (SLJIT_ARGS1(ret, arg1) | SLJIT_ARG_VALUE(SLJIT_ARG_TO_TYPE(arg2), 2)) - -#define SLJIT_ARGS3(ret, arg1, arg2, arg3) \ - (SLJIT_ARGS2(ret, arg1, arg2) | SLJIT_ARG_VALUE(SLJIT_ARG_TO_TYPE(arg3), 3)) - -#define SLJIT_ARGS4(ret, arg1, arg2, arg3, arg4) \ - (SLJIT_ARGS3(ret, arg1, arg2, arg3) | SLJIT_ARG_VALUE(SLJIT_ARG_TO_TYPE(arg4), 4)) - -/* --------------------------------------------------------------------- */ -/* Main structures and functions */ -/* --------------------------------------------------------------------- */ - -/* - The following structures are private, and can be changed in the - future. Keeping them here allows code inlining. -*/ - -struct sljit_memory_fragment { - struct sljit_memory_fragment *next; - sljit_uw used_size; - /* Must be aligned to sljit_sw. */ - sljit_u8 memory[1]; -}; - -struct sljit_label { - struct sljit_label *next; - sljit_uw addr; - /* The maximum size difference. */ - sljit_uw size; -}; - -struct sljit_jump { - struct sljit_jump *next; - sljit_uw addr; - /* Architecture dependent flags. */ - sljit_uw flags; - union { - sljit_uw target; - struct sljit_label *label; - } 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_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; - struct sljit_memory_fragment *buf; - struct sljit_memory_fragment *abuf; - - /* Available scratch registers. */ - sljit_s32 scratches; - /* Available saved registers. */ - sljit_s32 saveds; - /* Available float scratch registers. */ - sljit_s32 fscratches; - /* Available float saved registers. */ - sljit_s32 fsaveds; - /* Local stack size. */ - sljit_s32 local_size; - /* Maximum code size. */ - sljit_uw size; - /* Relative offset of the executable mapping from the writable mapping. */ - sljit_sw executable_offset; - /* Executable size for statistical purposes. */ - sljit_uw executable_size; - -#if (defined SLJIT_HAS_STATUS_FLAGS_STATE && SLJIT_HAS_STATUS_FLAGS_STATE) - sljit_s32 status_flags_state; -#endif - -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - sljit_s32 args_size; -#endif - -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - sljit_s32 mode32; -#endif - -#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) - /* Constant pool handling. */ - sljit_uw *cpool; - sljit_u8 *cpool_unique; - sljit_uw cpool_diff; - sljit_uw cpool_fill; - /* Other members. */ - /* Contains pointer, "ldr pc, [...]" pairs. */ - sljit_uw patches; -#endif - -#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) || (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) - /* Temporary fields. */ - sljit_uw shift_imm; -#endif /* SLJIT_CONFIG_ARM_V5 || SLJIT_CONFIG_ARM_V7 */ - -#if (defined SLJIT_CONFIG_ARM_32 && SLJIT_CONFIG_ARM_32) && (defined __SOFTFP__) - sljit_uw args_size; -#endif - -#if (defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC) - sljit_u32 imm; -#endif - -#if (defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS) - sljit_s32 delay_slot; - sljit_s32 cache_arg; - sljit_sw cache_argw; -#endif - -#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) - sljit_uw args_size; -#endif - -#if (defined SLJIT_CONFIG_RISCV && SLJIT_CONFIG_RISCV) - sljit_s32 cache_arg; - sljit_sw cache_argw; -#endif - -#if (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X) - /* Need to allocate register save area to make calls. */ - sljit_s32 mode; -#endif - -#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) - FILE* verbose; -#endif - -#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) \ - || (defined SLJIT_DEBUG && SLJIT_DEBUG) - /* Flags specified by the last arithmetic instruction. - It contains the type of the variable flag. */ - sljit_s32 last_flags; - /* Return value type set by entry functions. */ - sljit_s32 last_return; - /* Local size passed to entry functions. */ - sljit_s32 logical_local_size; -#endif - -#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) \ - || (defined SLJIT_DEBUG && SLJIT_DEBUG) \ - || (defined SLJIT_VERBOSE && SLJIT_VERBOSE) - /* Trust arguments when an API function is called. - Used internally for calling API functions. */ - sljit_s32 skip_checks; -#endif -}; - -/* --------------------------------------------------------------------- */ -/* Main functions */ -/* --------------------------------------------------------------------- */ - -/* Creates an SLJIT compiler. The allocator_data is required by some - 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. - - Returns NULL if failed. */ -SLJIT_API_FUNC_ATTRIBUTE struct sljit_compiler* sljit_create_compiler(void *allocator_data, void *exec_allocator_data); - -/* Frees everything except the compiled machine code. */ -SLJIT_API_FUNC_ATTRIBUTE void sljit_free_compiler(struct sljit_compiler *compiler); - -/* Returns the current error code. If an error occurres, future calls - which uses the same compiler argument returns early with the same - error code. Thus there is no need for checking the error after every - call, it is enough to do it after the code is compiled. Removing - these checks increases the performance of the compiling process. */ -static SLJIT_INLINE sljit_s32 sljit_get_compiler_error(struct sljit_compiler *compiler) { return compiler->error; } - -/* Sets the compiler error code to SLJIT_ERR_ALLOC_FAILED except - if an error was detected before. After the error code is set - the compiler behaves as if the allocation failure happened - during an SLJIT function call. This can greatly simplify error - checking, since it is enough to check the compiler status - after the code is compiled. */ -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_compiler_memory_error(struct sljit_compiler *compiler); - -/* - Allocate a small amount of memory. The size must be <= 64 bytes on 32 bit, - and <= 128 bytes on 64 bit architectures. The memory area is owned by the - compiler, and freed by sljit_free_compiler. The returned pointer is - sizeof(sljit_sw) aligned. Excellent for allocating small blocks during - compiling, and no need to worry about freeing them. The size is enough - to contain at most 16 pointers. If the size is outside of the range, - the function will return with NULL. However, this return value does not - indicate that there is no more memory (does not set the current error code - of the compiler to out-of-memory status). -*/ -SLJIT_API_FUNC_ATTRIBUTE void* sljit_alloc_memory(struct sljit_compiler *compiler, sljit_s32 size); - -#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 - -/* - 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. -*/ - -SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler); - -/* Free executable code. */ - -SLJIT_API_FUNC_ATTRIBUTE void sljit_free_code(void* code, void *exec_allocator_data); - -/* - When the protected executable allocator is used the JIT code is mapped - twice. The first mapping has read/write and the second mapping has read/exec - permissions. This function returns with the relative offset of the executable - mapping using the writable mapping as the base after the machine code is - successfully generated. The returned value is always 0 for the normal executable - allocator, since it uses only one mapping with read/write/exec permissions. - Dynamic code modifications requires this value. - - Before a successful code generation, this function returns with 0. -*/ -static SLJIT_INLINE sljit_sw sljit_get_executable_offset(struct sljit_compiler *compiler) { return compiler->executable_offset; } - -/* - The executable memory consumption of the generated code can be retrieved by - this function. The returned value can be used for statistical purposes. - - Before a successful code generation, this function returns with 0. -*/ -static SLJIT_INLINE sljit_uw sljit_get_generated_code_size(struct sljit_compiler *compiler) { return compiler->executable_size; } - -/* Returns with non-zero if the feature or limitation type passed as its - argument is present on the current CPU. The return value is one, if a - feature is fully supported, and it is two, if partially supported. - - Some features (e.g. floating point operations) require hardware (CPU) - support while others (e.g. move with update) are emulated if not available. - However, even when a feature is emulated, specialized code paths may be - faster than the emulation. Some limitations are emulated as well so their - general case is supported but it has extra performance costs. */ - -/* [Not emulated] Floating-point support is available. */ -#define SLJIT_HAS_FPU 0 -/* [Limitation] Some registers are virtual registers. */ -#define SLJIT_HAS_VIRTUAL_REGISTERS 1 -/* [Emulated] Has zero register (setting a memory location to zero is efficient). */ -#define SLJIT_HAS_ZERO_REGISTER 2 -/* [Emulated] Count leading zero is supported. */ -#define SLJIT_HAS_CLZ 3 -/* [Emulated] Count trailing zero is supported. */ -#define SLJIT_HAS_CTZ 4 -/* [Emulated] Rotate left/right is supported. */ -#define SLJIT_HAS_ROT 5 -/* [Emulated] Conditional move is supported. */ -#define SLJIT_HAS_CMOV 6 -/* [Emulated] Prefetch instruction is available (emulated as a nop). */ -#define SLJIT_HAS_PREFETCH 7 - -#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) -/* [Not emulated] SSE2 support is available on x86. */ -#define SLJIT_HAS_SSE2 100 -#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, - sljit_cmp_info returns one, if the cpu supports the passed floating - point comparison type. - - If type is SLJIT_UNORDERED or SLJIT_ORDERED, sljit_cmp_info returns - one, if the cpu supports checking the unordered comparison result - regardless of the comparison type passed to the comparison instruction. - The returned value is always one, if there is at least one type between - SLJIT_ORDERED_EQUAL and SLJIT_ORDERED_LESS_EQUAL where sljit_cmp_info - returns with a zero value. - - Otherwise it returns zero. */ -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_cmp_info(sljit_s32 type); - -/* The following functions generate machine code. If there is no - error, they return with SLJIT_SUCCESS, otherwise they return - with an error code. */ - -/* - The executable code is a function from the viewpoint of the C - language. The function calls must obey to the ABI (Application - Binary Interface) of the platform, which specify the purpose of - machine registers and stack handling among other things. The - sljit_emit_enter function emits the necessary instructions for - setting up a new context for the executable code. This is often - called as function prologue. Furthermore the options argument - can be used to pass configuration options to the compiler. The - available options are listed before sljit_emit_enter. - - The function argument list is specified by the SLJIT_ARGSx - (SLJIT_ARGS0 .. SLJIT_ARGS4) macros. Currently maximum four - arguments are supported. See the description of SLJIT_ARGSx - macros about argument passing. Furthermore the register set - used by the function must be declared as well. The number of - scratch and saved registers available to the function must - be passed to sljit_emit_enter. Only R registers between R0 - and "scratches" argument can be used later. E.g. if "scratches" - is set to two, the scratch register set will be limited to - SLJIT_R0 and SLJIT_R1. The S registers and the floating point - registers ("fscratches" and "fsaveds") are specified in a - similar manner. The sljit_emit_enter is also capable of - allocating a stack space for local data. The "local_size" - argument contains the size in bytes of this local area, and - it can be accessed using SLJIT_MEM1(SLJIT_SP). The memory - area between SLJIT_SP (inclusive) and SLJIT_SP + local_size - (exclusive) can be modified freely until the function returns. - The stack space is not initialized to zero. - - Note: the following conditions must met: - 0 <= scratches <= SLJIT_NUMBER_OF_REGISTERS - 0 <= saveds <= SLJIT_NUMBER_OF_SAVED_REGISTERS - scratches + saveds <= SLJIT_NUMBER_OF_REGISTERS - 0 <= fscratches <= SLJIT_NUMBER_OF_FLOAT_REGISTERS - 0 <= fsaveds <= SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS - fscratches + fsaveds <= SLJIT_NUMBER_OF_FLOAT_REGISTERS - - Note: the compiler can use saved registers as scratch registers, - but the opposite is not supported - - Note: every call of sljit_emit_enter and sljit_set_context - overwrites the previous context. -*/ - -/* Saved registers between SLJIT_S0 and SLJIT_S(n - 1) (inclusive) - are not saved / restored on function enter / return. Instead, - these registers can be used to pass / return data (such as - 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) - -/* 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 - -/* The local_size must be >= 0 and <= SLJIT_MAX_LOCAL_SIZE. */ -#define SLJIT_MAX_LOCAL_SIZE 65536 - -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, - sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size); - -/* The SLJIT compiler has a current context (which contains the local - stack space size, number of used registers, etc.) which is initialized - by sljit_emit_enter. Several functions (such as sljit_emit_return) - requires this context to be able to generate the appropriate code. - However, some code fragments (compiled separately) may have no - normal entry point so their context is unknown for the compiler. - - The sljit_set_context and sljit_emit_enter have the same arguments, - but sljit_set_context does not generate any machine code. - - Note: every call of sljit_emit_enter and sljit_set_context overwrites - the previous context. */ - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(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); - -/* Return to the caller function. The sljit_emit_return_void function - does not return with any value. The sljit_emit_return function returns - with a single value loaded from its source operand. The load operation - can be between SLJIT_MOV and SLJIT_MOV_P (see sljit_emit_op1) and - SLJIT_MOV_F32/SLJIT_MOV_F64 (see sljit_emit_fop1) depending on the - return value specified by sljit_emit_enter/sljit_set_context. */ - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_void(struct sljit_compiler *compiler); - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 src, sljit_sw srcw); - -/* Restores the saved registers and free the stack area, then the execution - continues from the address specified by the source operand. This - operation is similar to sljit_emit_return, but it ignores the return - address. The code where the exection continues should use the same context - as the caller function (see sljit_set_context). A word (pointer) value - can be passed in the SLJIT_RETURN_REG register. This function can be used - to jump to exception handlers. */ - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_to(struct sljit_compiler *compiler, - sljit_s32 src, sljit_sw srcw); - -/* Generating entry and exit points for fast call functions (see SLJIT_FAST_CALL). - Both sljit_emit_fast_enter and SLJIT_FAST_RETURN operations preserve the - values of all registers and stack frame. The return address is stored in the - dst argument of sljit_emit_fast_enter, and this return address can be passed - to SLJIT_FAST_RETURN to continue the execution after the fast call. - - Fast calls are cheap operations (usually only a single call instruction is - emitted) but they do not preserve any registers. However the callee function - can freely use / update any registers and the local area which can be - efficiently exploited by various optimizations. Registers can be saved - and restored manually if needed. - - Although returning to different address by SLJIT_FAST_RETURN is possible, - this address usually cannot be predicted by the return address predictor of - modern CPUs which may reduce performance. Furthermore certain security - enhancement technologies such as Intel Control-flow Enforcement Technology - (CET) may disallow returning to a different address. - - Flags: - (does not modify flags). */ - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw); - -/* - Source and destination operands for arithmetical instructions - imm - a simple immediate value (cannot be used as a destination) - reg - any of the available registers (immediate argument must be 0) - [imm] - absolute memory address - [reg+imm] - indirect memory address - [reg+(reg<> 1) >> (src2 ^ value_mask)) - SLJIT_MSHL or SLJIT_MSHL32: - src2 &= value_mask - perform the SLJIT_SHL or SLJIT_SHL32 operation - SLJIT_LSHR or SLJIT_LSHR32: - src_dst >>= src2 - src_dst |= ((src1 << 1) << (src2 ^ value_mask)) - SLJIT_MLSHR or SLJIT_MLSHR32: - src2 &= value_mask - perform the SLJIT_LSHR or SLJIT_LSHR32 operation - - op can be combined (or'ed) with SLJIT_SHIFT_INTO_NON_ZERO - - src_dst must be a register which content is updated after - the operation is completed - src1 / src1w contains the bits which shifted into src_dst - src2 / src2w contains the shift amount - - Note: a rotate operation can be performed if src_dst and - src1 are set to the same register - - Flags: - (may destroy flags) */ - -/* The src2 contains a non-zero value. Improves the generated - code on certain architectures, which provides a small - performance improvement. */ -#define SLJIT_SHIFT_INTO_NON_ZERO 0x200 - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 src_dst, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w); - -/* Starting index of opcodes for sljit_emit_op2. */ -#define SLJIT_OP_SRC_BASE 128 - -/* Note: src cannot be an immedate value - Flags: - (does not modify flags) */ -#define SLJIT_FAST_RETURN (SLJIT_OP_SRC_BASE + 0) -/* Skip stack frames before fast return. - Note: src cannot be an immedate value - Flags: may destroy flags. */ -#define SLJIT_SKIP_FRAMES_BEFORE_FAST_RETURN (SLJIT_OP_SRC_BASE + 1) -/* Prefetch value into the level 1 data cache - Note: if the target CPU does not support data prefetch, - no instructions are emitted. - Note: this instruction never fails, even if the memory address is invalid. - Flags: - (does not modify flags) */ -#define SLJIT_PREFETCH_L1 (SLJIT_OP_SRC_BASE + 2) -/* Prefetch value into the level 2 data cache - Note: same as SLJIT_PREFETCH_L1 if the target CPU - does not support this instruction form. - Note: this instruction never fails, even if the memory address is invalid. - Flags: - (does not modify flags) */ -#define SLJIT_PREFETCH_L2 (SLJIT_OP_SRC_BASE + 3) -/* Prefetch value into the level 3 data cache - Note: same as SLJIT_PREFETCH_L2 if the target CPU - does not support this instruction form. - Note: this instruction never fails, even if the memory address is invalid. - Flags: - (does not modify flags) */ -#define SLJIT_PREFETCH_L3 (SLJIT_OP_SRC_BASE + 4) -/* Prefetch a value which is only used once (and can be discarded afterwards) - Note: same as SLJIT_PREFETCH_L1 if the target CPU - does not support this instruction form. - Note: this instruction never fails, even if the memory address is invalid. - Flags: - (does not modify flags) */ -#define SLJIT_PREFETCH_ONCE (SLJIT_OP_SRC_BASE + 5) - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 src, sljit_sw srcw); - -/* Starting index of opcodes for sljit_emit_fop1. */ -#define SLJIT_FOP1_BASE 160 - -/* Flags: - (does not modify flags) */ -#define SLJIT_MOV_F64 (SLJIT_FOP1_BASE + 0) -#define SLJIT_MOV_F32 (SLJIT_MOV_F64 | SLJIT_32) -/* Convert opcodes: CONV[DST_TYPE].FROM[SRC_TYPE] - SRC/DST TYPE can be: F64, F32, S32, SW - Rounding mode when the destination is SW or S32: round towards zero. */ -/* Flags: - (may destroy flags) */ -#define SLJIT_CONV_F64_FROM_F32 (SLJIT_FOP1_BASE + 1) -#define SLJIT_CONV_F32_FROM_F64 (SLJIT_CONV_F64_FROM_F32 | SLJIT_32) -/* Flags: - (may destroy flags) */ -#define SLJIT_CONV_SW_FROM_F64 (SLJIT_FOP1_BASE + 2) -#define SLJIT_CONV_SW_FROM_F32 (SLJIT_CONV_SW_FROM_F64 | SLJIT_32) -/* Flags: - (may destroy flags) */ -#define SLJIT_CONV_S32_FROM_F64 (SLJIT_FOP1_BASE + 3) -#define SLJIT_CONV_S32_FROM_F32 (SLJIT_CONV_S32_FROM_F64 | SLJIT_32) -/* Flags: - (may destroy flags) */ -#define SLJIT_CONV_F64_FROM_SW (SLJIT_FOP1_BASE + 4) -#define SLJIT_CONV_F32_FROM_SW (SLJIT_CONV_F64_FROM_SW | SLJIT_32) -/* Flags: - (may destroy flags) */ -#define SLJIT_CONV_F64_FROM_S32 (SLJIT_FOP1_BASE + 5) -#define SLJIT_CONV_F32_FROM_S32 (SLJIT_CONV_F64_FROM_S32 | SLJIT_32) -/* Note: dst is the left and src is the right operand for SLJIT_CMP_F32/64. - Flags: EQUAL_F | LESS_F | GREATER_EQUAL_F | GREATER_F | LESS_EQUAL_F */ -#define SLJIT_CMP_F64 (SLJIT_FOP1_BASE + 6) -#define SLJIT_CMP_F32 (SLJIT_CMP_F64 | SLJIT_32) -/* Flags: - (may destroy flags) */ -#define SLJIT_NEG_F64 (SLJIT_FOP1_BASE + 7) -#define SLJIT_NEG_F32 (SLJIT_NEG_F64 | SLJIT_32) -/* Flags: - (may destroy flags) */ -#define SLJIT_ABS_F64 (SLJIT_FOP1_BASE + 8) -#define SLJIT_ABS_F32 (SLJIT_ABS_F64 | SLJIT_32) - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src, sljit_sw srcw); - -/* Starting index of opcodes for sljit_emit_fop2. */ -#define SLJIT_FOP2_BASE 192 - -/* Flags: - (may destroy flags) */ -#define SLJIT_ADD_F64 (SLJIT_FOP2_BASE + 0) -#define SLJIT_ADD_F32 (SLJIT_ADD_F64 | SLJIT_32) -/* Flags: - (may destroy flags) */ -#define SLJIT_SUB_F64 (SLJIT_FOP2_BASE + 1) -#define SLJIT_SUB_F32 (SLJIT_SUB_F64 | SLJIT_32) -/* Flags: - (may destroy flags) */ -#define SLJIT_MUL_F64 (SLJIT_FOP2_BASE + 2) -#define SLJIT_MUL_F32 (SLJIT_MUL_F64 | SLJIT_32) -/* Flags: - (may destroy flags) */ -#define SLJIT_DIV_F64 (SLJIT_FOP2_BASE + 3) -#define SLJIT_DIV_F32 (SLJIT_DIV_F64 | SLJIT_32) - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w); - -/* Label and jump instructions. */ - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compiler *compiler); - -/* Invert (negate) conditional type: xor (^) with 0x1 */ - -/* Integer comparison types. */ -#define SLJIT_EQUAL 0 -#define SLJIT_ZERO SLJIT_EQUAL -#define SLJIT_NOT_EQUAL 1 -#define SLJIT_NOT_ZERO SLJIT_NOT_EQUAL - -#define SLJIT_LESS 2 -#define SLJIT_SET_LESS SLJIT_SET(SLJIT_LESS) -#define SLJIT_GREATER_EQUAL 3 -#define SLJIT_SET_GREATER_EQUAL SLJIT_SET(SLJIT_GREATER_EQUAL) -#define SLJIT_GREATER 4 -#define SLJIT_SET_GREATER SLJIT_SET(SLJIT_GREATER) -#define SLJIT_LESS_EQUAL 5 -#define SLJIT_SET_LESS_EQUAL SLJIT_SET(SLJIT_LESS_EQUAL) -#define SLJIT_SIG_LESS 6 -#define SLJIT_SET_SIG_LESS SLJIT_SET(SLJIT_SIG_LESS) -#define SLJIT_SIG_GREATER_EQUAL 7 -#define SLJIT_SET_SIG_GREATER_EQUAL SLJIT_SET(SLJIT_SIG_GREATER_EQUAL) -#define SLJIT_SIG_GREATER 8 -#define SLJIT_SET_SIG_GREATER SLJIT_SET(SLJIT_SIG_GREATER) -#define SLJIT_SIG_LESS_EQUAL 9 -#define SLJIT_SET_SIG_LESS_EQUAL SLJIT_SET(SLJIT_SIG_LESS_EQUAL) - -#define SLJIT_OVERFLOW 10 -#define SLJIT_SET_OVERFLOW SLJIT_SET(SLJIT_OVERFLOW) -#define SLJIT_NOT_OVERFLOW 11 - -/* Unlike other flags, sljit_emit_jump may destroy the carry flag. */ -#define SLJIT_CARRY 12 -#define SLJIT_SET_CARRY SLJIT_SET(SLJIT_CARRY) -#define SLJIT_NOT_CARRY 13 - -/* Basic floating point comparison types. - - Note: when the comparison result is unordered, their behaviour is unspecified. */ - -#define SLJIT_F_EQUAL 14 -#define SLJIT_SET_F_EQUAL SLJIT_SET(SLJIT_F_EQUAL) -#define SLJIT_F_NOT_EQUAL 15 -#define SLJIT_SET_F_NOT_EQUAL SLJIT_SET(SLJIT_F_NOT_EQUAL) -#define SLJIT_F_LESS 16 -#define SLJIT_SET_F_LESS SLJIT_SET(SLJIT_F_LESS) -#define SLJIT_F_GREATER_EQUAL 17 -#define SLJIT_SET_F_GREATER_EQUAL SLJIT_SET(SLJIT_F_GREATER_EQUAL) -#define SLJIT_F_GREATER 18 -#define SLJIT_SET_F_GREATER SLJIT_SET(SLJIT_F_GREATER) -#define SLJIT_F_LESS_EQUAL 19 -#define SLJIT_SET_F_LESS_EQUAL SLJIT_SET(SLJIT_F_LESS_EQUAL) - -/* Jumps when either argument contains a NaN value. */ -#define SLJIT_UNORDERED 20 -#define SLJIT_SET_UNORDERED SLJIT_SET(SLJIT_UNORDERED) -/* Jumps when neither argument contains a NaN value. */ -#define SLJIT_ORDERED 21 -#define SLJIT_SET_ORDERED SLJIT_SET(SLJIT_ORDERED) - -/* Ordered / unordered floating point comparison types. - - Note: each comparison type has an ordered and unordered form. Some - architectures supports only either of them (see: sljit_cmp_info). */ - -#define SLJIT_ORDERED_EQUAL 22 -#define SLJIT_SET_ORDERED_EQUAL SLJIT_SET(SLJIT_ORDERED_EQUAL) -#define SLJIT_UNORDERED_OR_NOT_EQUAL 23 -#define SLJIT_SET_UNORDERED_OR_NOT_EQUAL SLJIT_SET(SLJIT_UNORDERED_OR_NOT_EQUAL) -#define SLJIT_ORDERED_LESS 24 -#define SLJIT_SET_ORDERED_LESS SLJIT_SET(SLJIT_ORDERED_LESS) -#define SLJIT_UNORDERED_OR_GREATER_EQUAL 25 -#define SLJIT_SET_UNORDERED_OR_GREATER_EQUAL SLJIT_SET(SLJIT_UNORDERED_OR_GREATER_EQUAL) -#define SLJIT_ORDERED_GREATER 26 -#define SLJIT_SET_ORDERED_GREATER SLJIT_SET(SLJIT_ORDERED_GREATER) -#define SLJIT_UNORDERED_OR_LESS_EQUAL 27 -#define SLJIT_SET_UNORDERED_OR_LESS_EQUAL SLJIT_SET(SLJIT_UNORDERED_OR_LESS_EQUAL) - -#define SLJIT_UNORDERED_OR_EQUAL 28 -#define SLJIT_SET_UNORDERED_OR_EQUAL SLJIT_SET(SLJIT_UNORDERED_OR_EQUAL) -#define SLJIT_ORDERED_NOT_EQUAL 29 -#define SLJIT_SET_ORDERED_NOT_EQUAL SLJIT_SET(SLJIT_ORDERED_NOT_EQUAL) -#define SLJIT_UNORDERED_OR_LESS 30 -#define SLJIT_SET_UNORDERED_OR_LESS SLJIT_SET(SLJIT_UNORDERED_OR_LESS) -#define SLJIT_ORDERED_GREATER_EQUAL 31 -#define SLJIT_SET_ORDERED_GREATER_EQUAL SLJIT_SET(SLJIT_ORDERED_GREATER_EQUAL) -#define SLJIT_UNORDERED_OR_GREATER 32 -#define SLJIT_SET_UNORDERED_OR_GREATER SLJIT_SET(SLJIT_UNORDERED_OR_GREATER) -#define SLJIT_ORDERED_LESS_EQUAL 33 -#define SLJIT_SET_ORDERED_LESS_EQUAL SLJIT_SET(SLJIT_ORDERED_LESS_EQUAL) - -/* Unconditional jump types. */ -#define SLJIT_JUMP 34 -/* Fast calling method. See sljit_emit_fast_enter / SLJIT_FAST_RETURN. */ -#define SLJIT_FAST_CALL 35 -/* Default C calling convention. */ -#define SLJIT_CALL 36 -/* Called function must be compiled by SLJIT. - See SLJIT_ENTER_REG_ARG option. */ -#define SLJIT_CALL_REG_ARG 37 - -/* The target can be changed during runtime (see: sljit_set_jump_addr). */ -#define SLJIT_REWRITABLE_JUMP 0x1000 -/* When this flag is passed, the execution of the current function ends and - the called function returns to the caller of the current function. The - stack usage is reduced before the call, but it is not necessarily reduced - to zero. In the latter case the compiler needs to allocate space for some - arguments and the return address must be stored on the stack as well. */ -#define SLJIT_CALL_RETURN 0x2000 - -/* Emit a jump instruction. The destination is not set, only the type of the jump. - type must be between SLJIT_EQUAL and SLJIT_FAST_CALL - type can be combined (or'ed) with SLJIT_REWRITABLE_JUMP - - Flags: does not modify flags. */ -SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type); - -/* Emit a C compiler (ABI) compatible function call. - type must be SLJIT_CALL or SLJIT_CALL_REG_ARG - type can be combined (or'ed) with SLJIT_REWRITABLE_JUMP and/or SLJIT_CALL_RETURN - arg_types can be specified by SLJIT_ARGSx (SLJIT_ARG_RETURN / SLJIT_ARG_VALUE) macros - - Flags: destroy all flags. */ -SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_call(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 arg_types); - -/* Basic arithmetic comparison. In most architectures it is implemented as - a compare operation followed by a sljit_emit_jump. However some - architectures (i.e: ARM64 or MIPS) may employ special optimizations - here. It is suggested to use this comparison form when appropriate. - type must be between SLJIT_EQUAL and SLJIT_SIG_LESS_EQUAL - type can be combined (or'ed) with SLJIT_REWRITABLE_JUMP - - Flags: may destroy flags. */ -SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w); - -/* Basic floating point comparison. In most architectures it is implemented as - a SLJIT_CMP_F32/64 operation (setting appropriate flags) followed by a - sljit_emit_jump. However some architectures (i.e: MIPS) may employ - special optimizations here. It is suggested to use this comparison form - when appropriate. - type must be between SLJIT_F_EQUAL and SLJIT_ORDERED_LESS_EQUAL - type can be combined (or'ed) with SLJIT_REWRITABLE_JUMP - Flags: destroy flags. - Note: when an operand is NaN the behaviour depends on the comparison type. */ -SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_fcmp(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w); - -/* Set the destination of the jump to this label. */ -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_label(struct sljit_jump *jump, struct sljit_label* label); -/* Set the destination address of the jump to this label. */ -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_target(struct sljit_jump *jump, sljit_uw target); - -/* Emit an indirect jump or fast call. - Direct form: set src to SLJIT_IMM() and srcw to the address - Indirect form: any other valid addressing mode - type must be between SLJIT_JUMP and SLJIT_FAST_CALL - - Flags: does not modify flags. */ -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 src, sljit_sw srcw); - -/* Emit a C compiler (ABI) compatible function call. - Direct form: set src to SLJIT_IMM() and srcw to the address - Indirect form: any other valid addressing mode - type must be SLJIT_CALL or SLJIT_CALL_REG_ARG - type can be combined (or'ed) with SLJIT_CALL_RETURN - arg_types can be specified by SLJIT_ARGSx (SLJIT_ARG_RETURN / SLJIT_ARG_VALUE) macros - - Flags: destroy all flags. */ -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 arg_types, sljit_s32 src, sljit_sw srcw); - -/* Perform an operation using the conditional flags as the second argument. - Type must always be between SLJIT_EQUAL and SLJIT_ORDERED_LESS_EQUAL. - The value represented by the type is 1, if the condition represented - by the type is fulfilled, and 0 otherwise. - - When op is SLJIT_MOV or SLJIT_MOV32: - Set dst to the value represented by the type (0 or 1). - Flags: - (does not modify flags) - When op is SLJIT_AND, SLJIT_AND32, SLJIT_OR, SLJIT_OR32, SLJIT_XOR, or SLJIT_XOR32 - Performs the binary operation using dst as the first, and the value - represented by type as the second argument. Result is written into dst. - Flags: Z (may destroy flags) */ -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 type); - -/* Emit a conditional mov instruction which moves source to destination, - if the condition is satisfied. Unlike other arithmetic operations this - instruction does not support memory access. - - type must be between SLJIT_EQUAL and SLJIT_ORDERED_LESS_EQUAL - type can be combined (or'ed) with SLJIT_32 - dst_reg must be a valid register - src must be a valid register or immediate (SLJIT_IMM) - - Flags: - (does not modify flags) */ -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 dst_reg, - sljit_s32 src, sljit_sw srcw); - -/* The following flags are used by sljit_emit_mem(), sljit_emit_mem_update(), - sljit_emit_fmem(), and sljit_emit_fmem_update(). */ - -/* Memory load operation. This is the default. */ -#define SLJIT_MEM_LOAD 0x000000 -/* Memory store operation. */ -#define SLJIT_MEM_STORE 0x000200 - -/* The following flags are used by sljit_emit_mem() and sljit_emit_fmem(). */ - -/* Load or stora data from an unaligned (byte aligned) address. */ -#define SLJIT_MEM_UNALIGNED 0x000400 -/* Load or stora data from a 16 bit aligned address. */ -#define SLJIT_MEM_UNALIGNED_16 0x000800 -/* Load or stora data from a 32 bit aligned address. */ -#define SLJIT_MEM_UNALIGNED_32 0x001000 - -/* The following flags are used by sljit_emit_mem_update(), - and sljit_emit_fmem_update(). */ - -/* Base register is updated before the memory access (default). */ -#define SLJIT_MEM_PRE 0x000000 -/* Base register is updated after the memory access. */ -#define SLJIT_MEM_POST 0x000400 - -/* When SLJIT_MEM_SUPP is passed, no instructions are emitted. - Instead the function returns with SLJIT_SUCCESS if the instruction - form is supported and SLJIT_ERR_UNSUPPORTED otherwise. This flag - allows runtime checking of available instruction forms. */ -#define SLJIT_MEM_SUPP 0x000800 - -/* The sljit_emit_mem emits instructions for various memory operations: - - When SLJIT_MEM_UNALIGNED / SLJIT_MEM_UNALIGNED_16 / - SLJIT_MEM_UNALIGNED_32 is set in type argument: - Emit instructions for unaligned memory loads or stores. When - SLJIT_UNALIGNED is not defined, the only way to access unaligned - memory data is using sljit_emit_mem. Otherwise all operations (e.g. - sljit_emit_op1/2, or sljit_emit_fop1/2) supports unaligned access. - In general, the performance of unaligned memory accesses are often - lower than aligned and should be avoided. - - When a pair of registers is passed in reg argument: - Emit instructions for moving data between a register pair and - memory. The register pair can be specified by the SLJIT_REG_PAIR - macro. The first register is loaded from or stored into the - location specified by the mem/memw arguments, and the end address - of this operation is the starting address of the data transfer - between the second register and memory. The type argument must - be SLJIT_MOV. The SLJIT_MEM_UNALIGNED* options are allowed for - this operation. - - type must be between SLJIT_MOV and SLJIT_MOV_P and can be - combined (or'ed) with SLJIT_MEM_* flags - reg is a register or register pair, which is the source or - destination of the operation - mem must be a memory operand - - Flags: - (does not modify flags) */ -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); - -/* Emit a single memory load or store with update instruction. - When the requested instruction form is not supported by the CPU, - it returns with SLJIT_ERR_UNSUPPORTED instead of emulating the - instruction. This allows specializing tight loops based on - the supported instruction forms (see SLJIT_MEM_SUPP flag). - Absolute address (SLJIT_MEM0) forms are never supported - and the base (first) register specified by the mem argument - must not be SLJIT_SP and must also be different from the - register specified by the reg argument. - - type must be between SLJIT_MOV and SLJIT_MOV_P and can be - combined (or'ed) with SLJIT_MEM_* flags - reg is the source or destination register of the operation - mem must be a memory operand - - Flags: - (does not modify flags) */ - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem_update(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 reg, - sljit_s32 mem, sljit_sw memw); - -/* Same as sljit_emit_mem except the followings: - - Loading or storing a pair of registers is not supported. - - type must be SLJIT_MOV_F64 or SLJIT_MOV_F32 and can be - combined (or'ed) with SLJIT_MEM_* flags. - freg is the source or destination floating point register - of the operation - mem must be a memory operand - - Flags: - (does not modify flags) */ - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fmem(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 freg, - sljit_s32 mem, sljit_sw memw); - -/* Same as sljit_emit_mem_update except the followings: - - type must be SLJIT_MOV_F64 or SLJIT_MOV_F32 and can be - combined (or'ed) with SLJIT_MEM_* flags - freg is the source or destination floating point register - of the operation - mem must be a memory operand - - Flags: - (does not modify flags) */ - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fmem_update(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 freg, - sljit_s32 mem, sljit_sw memw); - -/* Copies the base address of SLJIT_SP + offset to dst. The offset can - represent the starting address of a value in the local data (stack). - The offset is not limited by the local data limits, it can be any value. - For example if an array of bytes are stored on the stack from - offset 0x40, and R0 contains the offset of an array item plus 0x120, - this item can be changed by two SLJIT instructions: - - sljit_get_local_base(compiler, SLJIT_R1, 0, 0x40 - 0x120); - sljit_emit_op1(compiler, SLJIT_MOV_U8, SLJIT_MEM2(SLJIT_R1, SLJIT_R0), 0, SLJIT_IMM, 0x5); - - Flags: - (may destroy flags) */ -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_local_base(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw offset); - -/* Store a value that can be changed runtime (see: sljit_get_const_addr / sljit_set_const) - 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) - 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); - -/* 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; } -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; } - -/* Only the address and executable offset are required to perform dynamic - code modifications. See sljit_get_executable_offset function. */ -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset); -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset); - -/* --------------------------------------------------------------------- */ -/* CPU specific functions */ -/* --------------------------------------------------------------------- */ - -/* The following function is a helper function for sljit_emit_op_custom. - It returns with the real machine register index ( >=0 ) of any SLJIT_R, - SLJIT_S and SLJIT_SP registers. - - Note: it returns with -1 for virtual registers (only on x86-32). */ - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 reg); - -/* The following function is a helper function for sljit_emit_op_custom. - It returns with the real machine register ( >= 0 ) index of any SLJIT_FR, - and SLJIT_FS register. - - Note: the index is always an even number on ARM-32, MIPS. */ - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_float_register_index(sljit_s32 reg); - -/* Any instruction can be inserted into the instruction stream by - sljit_emit_op_custom. It has a similar purpose as inline assembly. - The size parameter must match to the instruction size of the target - architecture: - - x86: 0 < size <= 15. The instruction argument can be byte aligned. - Thumb2: if size == 2, the instruction argument must be 2 byte aligned. - if size == 4, the instruction argument must be 4 byte aligned. - Otherwise: size must be 4 and instruction argument must be 4 byte aligned. */ - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler, - void *instruction, sljit_u32 size); - -/* Flags were set by a 32 bit operation. */ -#define SLJIT_CURRENT_FLAGS_32 SLJIT_32 - -/* Flags were set by an ADD or ADDC operations. */ -#define SLJIT_CURRENT_FLAGS_ADD 0x01 -/* Flags were set by a SUB, SUBC, or NEG operation. */ -#define SLJIT_CURRENT_FLAGS_SUB 0x02 - -/* Flags were set by sljit_emit_op2u with SLJIT_SUB opcode. - Must be combined with SLJIT_CURRENT_FLAGS_SUB. */ -#define SLJIT_CURRENT_FLAGS_COMPARE 0x04 - -/* Define the currently available CPU status flags. It is usually used after - an sljit_emit_label or sljit_emit_op_custom operations to define which CPU - status flags are available. - - The current_flags must be a valid combination of SLJIT_SET_* and - SLJIT_CURRENT_FLAGS_* constants. */ - -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_current_flags(struct sljit_compiler *compiler, - sljit_s32 current_flags); - -/* --------------------------------------------------------------------- */ -/* Miscellaneous utility functions */ -/* --------------------------------------------------------------------- */ - -/* Get the human readable name of the platform. Can be useful on platforms - like ARM, where ARM and Thumb2 functions can be mixed, and it is useful - to know the type of the code generator. */ -SLJIT_API_FUNC_ATTRIBUTE const char* sljit_get_platform_name(void); - -/* Portable helper function to get an offset of a member. */ -#define SLJIT_OFFSETOF(base, member) ((sljit_sw)(&((base*)0x10)->member) - 0x10) - -#if (defined SLJIT_UTIL_STACK && SLJIT_UTIL_STACK) - -/* The sljit_stack structure and its manipulation functions provides - an implementation for a top-down stack. The stack top is stored - in the end field of the sljit_stack structure and the stack goes - down to the min_start field, so the memory region reserved for - this stack is between min_start (inclusive) and end (exclusive) - fields. However the application can only use the region between - start (inclusive) and end (exclusive) fields. The sljit_stack_resize - function can be used to extend this region up to min_start. - - This feature uses the "address space reserve" feature of modern - operating systems. Instead of allocating a large memory block - applications can allocate a small memory region and extend it - later without moving the content of the memory area. Therefore - after a successful resize by sljit_stack_resize all pointers into - this region are still valid. - - Note: - this structure may not be supported by all operating systems. - end and max_limit fields are aligned to PAGE_SIZE bytes (usually - 4 Kbyte or more). - stack should grow in larger steps, e.g. 4Kbyte, 16Kbyte or more. */ - -struct sljit_stack { - /* User data, anything can be stored here. - Initialized to the same value as the end field. */ - sljit_u8 *top; -/* These members are read only. */ - /* End address of the stack */ - sljit_u8 *end; - /* Current start address of the stack. */ - sljit_u8 *start; - /* Lowest start address of the stack. */ - sljit_u8 *min_start; -}; - -/* Allocates a new stack. Returns NULL if unsuccessful. - Note: see sljit_create_compiler for the explanation of allocator_data. */ -SLJIT_API_FUNC_ATTRIBUTE struct sljit_stack* SLJIT_FUNC sljit_allocate_stack(sljit_uw start_size, sljit_uw max_size, void *allocator_data); -SLJIT_API_FUNC_ATTRIBUTE void SLJIT_FUNC sljit_free_stack(struct sljit_stack *stack, void *allocator_data); - -/* Can be used to increase (extend) or decrease (shrink) the stack - memory area. Returns with new_start if successful and NULL otherwise. - It always fails if new_start is less than min_start or greater or equal - than end fields. The fields of the stack are not changed if the returned - value is NULL (the current memory content is never lost). */ -SLJIT_API_FUNC_ATTRIBUTE sljit_u8 *SLJIT_FUNC sljit_stack_resize(struct sljit_stack *stack, sljit_u8 *new_start); - -#endif /* (defined SLJIT_UTIL_STACK && SLJIT_UTIL_STACK) */ - -#if !(defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL) - -/* Get the entry address of a given function (signed, unsigned result). */ -#define SLJIT_FUNC_ADDR(func_name) ((sljit_sw)func_name) -#define SLJIT_FUNC_UADDR(func_name) ((sljit_uw)func_name) - -#else /* !(defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL) */ - -/* All JIT related code should be placed in the same context (library, binary, etc.). */ - -/* Get the entry address of a given function (signed, unsigned result). */ -#define SLJIT_FUNC_ADDR(func_name) (*(sljit_sw*)(void*)func_name) -#define SLJIT_FUNC_UADDR(func_name) (*(sljit_uw*)(void*)func_name) - -/* For powerpc64, the function pointers point to a context descriptor. */ -struct sljit_function_context { - sljit_uw addr; - sljit_uw r2; - sljit_uw r11; -}; - -/* Fill the context arguments using the addr and the function. - If func_ptr is NULL, it will not be set to the address of context - If addr is NULL, the function address also comes from the func pointer. */ -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_function_context(void** func_ptr, struct sljit_function_context* context, sljit_uw addr, void* func); - -#endif /* !(defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL) */ - -#if (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR) -/* Free unused executable memory. The allocator keeps some free memory - around to reduce the number of OS executable memory allocations. - This improves performance since these calls are costly. However - it is sometimes desired to free all unused memory regions, e.g. - before the application terminates. */ -SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void); -#endif - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* SLJIT_LIR_H_ */ diff --git a/modules/regex/pcre2/src/sljit/sljitNativeARM_32.c b/modules/regex/pcre2/src/sljit/sljitNativeARM_32.c deleted file mode 100644 index 54b8ade..0000000 --- a/modules/regex/pcre2/src/sljit/sljitNativeARM_32.c +++ /dev/null @@ -1,3700 +0,0 @@ -/* - * 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. - */ - -#ifdef __SOFTFP__ -#define ARM_ABI_INFO " ABI:softfp" -#else -#define ARM_ABI_INFO " ABI:hardfp" -#endif - -SLJIT_API_FUNC_ATTRIBUTE const char* sljit_get_platform_name(void) -{ -#if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) - return "ARMv7" SLJIT_CPUINFO ARM_ABI_INFO; -#elif (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) - return "ARMv5" SLJIT_CPUINFO ARM_ABI_INFO; -#else -#error "Internal error: Unknown ARM architecture" -#endif -} - -/* Last register + 1. */ -#define TMP_REG1 (SLJIT_NUMBER_OF_REGISTERS + 2) -#define TMP_REG2 (SLJIT_NUMBER_OF_REGISTERS + 3) -#define TMP_PC (SLJIT_NUMBER_OF_REGISTERS + 4) - -#define TMP_FREG1 (SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1) -#define TMP_FREG2 (SLJIT_NUMBER_OF_FLOAT_REGISTERS + 2) - -/* In ARM instruction words. - Cache lines are usually 32 byte aligned. */ -#define CONST_POOL_ALIGNMENT 8 -#define CONST_POOL_EMPTY 0xffffffff - -#define ALIGN_INSTRUCTION(ptr) \ - (sljit_uw*)(((sljit_uw)(ptr) + (CONST_POOL_ALIGNMENT * sizeof(sljit_uw)) - 1) & ~((CONST_POOL_ALIGNMENT * sizeof(sljit_uw)) - 1)) -#define MAX_DIFFERENCE(max_diff) \ - (((max_diff) / (sljit_s32)sizeof(sljit_uw)) - (CONST_POOL_ALIGNMENT - 1)) - -/* See sljit_emit_enter and sljit_emit_op0 if you want to change them. */ -static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 5] = { - 0, 0, 1, 2, 3, 11, 10, 9, 8, 7, 6, 5, 4, 13, 12, 14, 15 -}; - -static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 3] = { - 0, 0, 1, 2, 3, 4, 5, 15, 14, 13, 12, 11, 10, 9, 8, 6, 7 -}; - -#define RM(rm) ((sljit_uw)reg_map[rm]) -#define RM8(rm) ((sljit_uw)reg_map[rm] << 8) -#define RD(rd) ((sljit_uw)reg_map[rd] << 12) -#define RN(rn) ((sljit_uw)reg_map[rn] << 16) - -#define VM(rm) ((sljit_uw)freg_map[rm]) -#define VD(rd) ((sljit_uw)freg_map[rd] << 12) -#define VN(rn) ((sljit_uw)freg_map[rn] << 16) - -/* --------------------------------------------------------------------- */ -/* Instrucion forms */ -/* --------------------------------------------------------------------- */ - -/* The instruction includes the AL condition. - INST_NAME - CONDITIONAL remove this flag. */ -#define COND_MASK 0xf0000000 -#define CONDITIONAL 0xe0000000 -#define PUSH_POOL 0xff000000 - -#define ADC 0xe0a00000 -#define ADD 0xe0800000 -#define AND 0xe0000000 -#define B 0xea000000 -#define BIC 0xe1c00000 -#define BL 0xeb000000 -#define BLX 0xe12fff30 -#define BX 0xe12fff10 -#define CLZ 0xe16f0f10 -#define CMN 0xe1600000 -#define CMP 0xe1400000 -#define BKPT 0xe1200070 -#define EOR 0xe0200000 -#define LDR 0xe5100000 -#define LDR_POST 0xe4100000 -#define MOV 0xe1a00000 -#define MUL 0xe0000090 -#define MVN 0xe1e00000 -#define NOP 0xe1a00000 -#define ORR 0xe1800000 -#define PUSH 0xe92d0000 -#define POP 0xe8bd0000 -#define RBIT 0xe6ff0f30 -#define RSB 0xe0600000 -#define RSC 0xe0e00000 -#define SBC 0xe0c00000 -#define SMULL 0xe0c00090 -#define STR 0xe5000000 -#define SUB 0xe0400000 -#define TST 0xe1000000 -#define UMULL 0xe0800090 -#define VABS_F32 0xeeb00ac0 -#define VADD_F32 0xee300a00 -#define VCMP_F32 0xeeb40a40 -#define VCVT_F32_S32 0xeeb80ac0 -#define VCVT_F64_F32 0xeeb70ac0 -#define VCVT_S32_F32 0xeebd0ac0 -#define VDIV_F32 0xee800a00 -#define VLDR_F32 0xed100a00 -#define VMOV_F32 0xeeb00a40 -#define VMOV 0xee000a10 -#define VMOV2 0xec400a10 -#define VMRS 0xeef1fa10 -#define VMUL_F32 0xee200a00 -#define VNEG_F32 0xeeb10a40 -#define VPOP 0xecbd0b00 -#define VPUSH 0xed2d0b00 -#define VSTR_F32 0xed000a00 -#define VSUB_F32 0xee300a40 - -#if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) -/* Arm v7 specific instructions. */ -#define MOVW 0xe3000000 -#define MOVT 0xe3400000 -#define SXTB 0xe6af0070 -#define SXTH 0xe6bf0070 -#define UXTB 0xe6ef0070 -#define UXTH 0xe6ff0070 -#endif - -#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) - -static sljit_s32 push_cpool(struct sljit_compiler *compiler) -{ - /* Pushing the constant pool into the instruction stream. */ - sljit_uw* inst; - sljit_uw* cpool_ptr; - sljit_uw* cpool_end; - sljit_s32 i; - - /* The label could point the address after the constant pool. */ - if (compiler->last_label && compiler->last_label->size == compiler->size) - compiler->last_label->size += compiler->cpool_fill + (CONST_POOL_ALIGNMENT - 1) + 1; - - SLJIT_ASSERT(compiler->cpool_fill > 0 && compiler->cpool_fill <= CPOOL_SIZE); - inst = (sljit_uw*)ensure_buf(compiler, sizeof(sljit_uw)); - FAIL_IF(!inst); - compiler->size++; - *inst = 0xff000000 | compiler->cpool_fill; - - for (i = 0; i < CONST_POOL_ALIGNMENT - 1; i++) { - inst = (sljit_uw*)ensure_buf(compiler, sizeof(sljit_uw)); - FAIL_IF(!inst); - compiler->size++; - *inst = 0; - } - - cpool_ptr = compiler->cpool; - cpool_end = cpool_ptr + compiler->cpool_fill; - while (cpool_ptr < cpool_end) { - inst = (sljit_uw*)ensure_buf(compiler, sizeof(sljit_uw)); - FAIL_IF(!inst); - compiler->size++; - *inst = *cpool_ptr++; - } - compiler->cpool_diff = CONST_POOL_EMPTY; - compiler->cpool_fill = 0; - return SLJIT_SUCCESS; -} - -static sljit_s32 push_inst(struct sljit_compiler *compiler, sljit_uw inst) -{ - sljit_uw* ptr; - - if (SLJIT_UNLIKELY(compiler->cpool_diff != CONST_POOL_EMPTY && compiler->size - compiler->cpool_diff >= MAX_DIFFERENCE(4092))) - FAIL_IF(push_cpool(compiler)); - - ptr = (sljit_uw*)ensure_buf(compiler, sizeof(sljit_uw)); - FAIL_IF(!ptr); - compiler->size++; - *ptr = inst; - return SLJIT_SUCCESS; -} - -static sljit_s32 push_inst_with_literal(struct sljit_compiler *compiler, sljit_uw inst, sljit_uw literal) -{ - sljit_uw* ptr; - sljit_uw cpool_index = CPOOL_SIZE; - sljit_uw* cpool_ptr; - sljit_uw* cpool_end; - sljit_u8* cpool_unique_ptr; - - if (SLJIT_UNLIKELY(compiler->cpool_diff != CONST_POOL_EMPTY && compiler->size - compiler->cpool_diff >= MAX_DIFFERENCE(4092))) - FAIL_IF(push_cpool(compiler)); - else if (compiler->cpool_fill > 0) { - cpool_ptr = compiler->cpool; - cpool_end = cpool_ptr + compiler->cpool_fill; - cpool_unique_ptr = compiler->cpool_unique; - do { - if ((*cpool_ptr == literal) && !(*cpool_unique_ptr)) { - cpool_index = (sljit_uw)(cpool_ptr - compiler->cpool); - break; - } - cpool_ptr++; - cpool_unique_ptr++; - } while (cpool_ptr < cpool_end); - } - - if (cpool_index == CPOOL_SIZE) { - /* Must allocate a new entry in the literal pool. */ - if (compiler->cpool_fill < CPOOL_SIZE) { - cpool_index = compiler->cpool_fill; - compiler->cpool_fill++; - } - else { - FAIL_IF(push_cpool(compiler)); - cpool_index = 0; - compiler->cpool_fill = 1; - } - } - - SLJIT_ASSERT((inst & 0xfff) == 0); - ptr = (sljit_uw*)ensure_buf(compiler, sizeof(sljit_uw)); - FAIL_IF(!ptr); - compiler->size++; - *ptr = inst | cpool_index; - - compiler->cpool[cpool_index] = literal; - compiler->cpool_unique[cpool_index] = 0; - if (compiler->cpool_diff == CONST_POOL_EMPTY) - compiler->cpool_diff = compiler->size; - return SLJIT_SUCCESS; -} - -static sljit_s32 push_inst_with_unique_literal(struct sljit_compiler *compiler, sljit_uw inst, sljit_uw literal) -{ - sljit_uw* ptr; - if (SLJIT_UNLIKELY((compiler->cpool_diff != CONST_POOL_EMPTY && compiler->size - compiler->cpool_diff >= MAX_DIFFERENCE(4092)) || compiler->cpool_fill >= CPOOL_SIZE)) - FAIL_IF(push_cpool(compiler)); - - SLJIT_ASSERT(compiler->cpool_fill < CPOOL_SIZE && (inst & 0xfff) == 0); - ptr = (sljit_uw*)ensure_buf(compiler, sizeof(sljit_uw)); - FAIL_IF(!ptr); - compiler->size++; - *ptr = inst | compiler->cpool_fill; - - compiler->cpool[compiler->cpool_fill] = literal; - compiler->cpool_unique[compiler->cpool_fill] = 1; - compiler->cpool_fill++; - if (compiler->cpool_diff == CONST_POOL_EMPTY) - compiler->cpool_diff = compiler->size; - return SLJIT_SUCCESS; -} - -static SLJIT_INLINE sljit_s32 prepare_blx(struct sljit_compiler *compiler) -{ - /* Place for at least two instruction (doesn't matter whether the first has a literal). */ - if (SLJIT_UNLIKELY(compiler->cpool_diff != CONST_POOL_EMPTY && compiler->size - compiler->cpool_diff >= MAX_DIFFERENCE(4088))) - return push_cpool(compiler); - return SLJIT_SUCCESS; -} - -static SLJIT_INLINE sljit_s32 emit_blx(struct sljit_compiler *compiler) -{ - /* Must follow tightly the previous instruction (to be able to convert it to bl instruction). */ - SLJIT_ASSERT(compiler->cpool_diff == CONST_POOL_EMPTY || compiler->size - compiler->cpool_diff < MAX_DIFFERENCE(4092)); - SLJIT_ASSERT(reg_map[TMP_REG1] != 14); - - return push_inst(compiler, BLX | RM(TMP_REG1)); -} - -static sljit_uw patch_pc_relative_loads(sljit_uw *last_pc_patch, sljit_uw *code_ptr, sljit_uw* const_pool, sljit_uw cpool_size) -{ - sljit_uw diff; - sljit_uw ind; - sljit_uw counter = 0; - sljit_uw* clear_const_pool = const_pool; - sljit_uw* clear_const_pool_end = const_pool + cpool_size; - - SLJIT_ASSERT(const_pool - code_ptr <= CONST_POOL_ALIGNMENT); - /* Set unused flag for all literals in the constant pool. - I.e.: unused literals can belong to branches, which can be encoded as B or BL. - We can "compress" the constant pool by discarding these literals. */ - while (clear_const_pool < clear_const_pool_end) - *clear_const_pool++ = (sljit_uw)(-1); - - while (last_pc_patch < code_ptr) { - /* Data transfer instruction with Rn == r15. */ - if ((*last_pc_patch & 0x0c0f0000) == 0x040f0000) { - diff = (sljit_uw)(const_pool - last_pc_patch); - ind = (*last_pc_patch) & 0xfff; - - /* Must be a load instruction with immediate offset. */ - SLJIT_ASSERT(ind < cpool_size && !(*last_pc_patch & (1 << 25)) && (*last_pc_patch & (1 << 20))); - if ((sljit_s32)const_pool[ind] < 0) { - const_pool[ind] = counter; - ind = counter; - counter++; - } - else - ind = const_pool[ind]; - - SLJIT_ASSERT(diff >= 1); - if (diff >= 2 || ind > 0) { - diff = (diff + (sljit_uw)ind - 2) << 2; - SLJIT_ASSERT(diff <= 0xfff); - *last_pc_patch = (*last_pc_patch & ~(sljit_uw)0xfff) | diff; - } - else - *last_pc_patch = (*last_pc_patch & ~(sljit_uw)(0xfff | (1 << 23))) | 0x004; - } - last_pc_patch++; - } - return counter; -} - -/* In some rare ocasions we may need future patches. The probability is close to 0 in practice. */ -struct future_patch { - struct future_patch* next; - sljit_s32 index; - sljit_s32 value; -}; - -static sljit_s32 resolve_const_pool_index(struct sljit_compiler *compiler, struct future_patch **first_patch, sljit_uw cpool_current_index, sljit_uw *cpool_start_address, sljit_uw *buf_ptr) -{ - sljit_u32 value; - struct future_patch *curr_patch, *prev_patch; - - SLJIT_UNUSED_ARG(compiler); - - /* Using the values generated by patch_pc_relative_loads. */ - if (!*first_patch) - value = cpool_start_address[cpool_current_index]; - else { - curr_patch = *first_patch; - prev_patch = NULL; - while (1) { - if (!curr_patch) { - value = cpool_start_address[cpool_current_index]; - break; - } - if ((sljit_uw)curr_patch->index == cpool_current_index) { - value = (sljit_uw)curr_patch->value; - if (prev_patch) - prev_patch->next = curr_patch->next; - else - *first_patch = curr_patch->next; - SLJIT_FREE(curr_patch, compiler->allocator_data); - break; - } - prev_patch = curr_patch; - curr_patch = curr_patch->next; - } - } - - if ((sljit_sw)value >= 0) { - if (value > cpool_current_index) { - curr_patch = (struct future_patch*)SLJIT_MALLOC(sizeof(struct future_patch), compiler->allocator_data); - if (!curr_patch) { - while (*first_patch) { - curr_patch = *first_patch; - *first_patch = (*first_patch)->next; - SLJIT_FREE(curr_patch, compiler->allocator_data); - } - return SLJIT_ERR_ALLOC_FAILED; - } - curr_patch->next = *first_patch; - curr_patch->index = (sljit_sw)value; - curr_patch->value = (sljit_sw)cpool_start_address[value]; - *first_patch = curr_patch; - } - cpool_start_address[value] = *buf_ptr; - } - return SLJIT_SUCCESS; -} - -#else - -static sljit_s32 push_inst(struct sljit_compiler *compiler, sljit_uw inst) -{ - sljit_uw* ptr; - - ptr = (sljit_uw*)ensure_buf(compiler, sizeof(sljit_uw)); - FAIL_IF(!ptr); - compiler->size++; - *ptr = inst; - return SLJIT_SUCCESS; -} - -static SLJIT_INLINE sljit_s32 emit_imm(struct sljit_compiler *compiler, sljit_s32 reg, sljit_sw imm) -{ - FAIL_IF(push_inst(compiler, MOVW | RD(reg) | ((imm << 4) & 0xf0000) | ((sljit_u32)imm & 0xfff))); - return push_inst(compiler, MOVT | RD(reg) | ((imm >> 12) & 0xf0000) | (((sljit_u32)imm >> 16) & 0xfff)); -} - -#endif - -static SLJIT_INLINE sljit_s32 detect_jump_type(struct sljit_jump *jump, sljit_uw *code_ptr, sljit_uw *code, sljit_sw executable_offset) -{ - sljit_sw diff; - - if (jump->flags & SLJIT_REWRITABLE_JUMP) - return 0; - -#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) - if (jump->flags & IS_BL) - code_ptr--; - - 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); - diff = ((sljit_sw)(code + jump->u.label->size) - (sljit_sw)(code_ptr + 2)); - } - - /* Branch to Thumb code has not been optimized yet. */ - if (diff & 0x3) - return 0; - - if (jump->flags & IS_BL) { - if (diff <= 0x01ffffff && diff >= -0x02000000) { - *code_ptr = (BL - CONDITIONAL) | (*(code_ptr + 1) & COND_MASK); - jump->flags |= PATCH_B; - return 1; - } - } - else { - if (diff <= 0x01ffffff && diff >= -0x02000000) { - *code_ptr = (B - CONDITIONAL) | (*code_ptr & COND_MASK); - jump->flags |= PATCH_B; - } - } -#else - 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); - jump->flags |= PATCH_B; - return 1; - } -#endif - 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) -{ -#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) - sljit_uw *ptr = (sljit_uw *)jump_ptr; - sljit_uw *inst = (sljit_uw *)ptr[0]; - sljit_uw mov_pc = ptr[1]; - sljit_s32 bl = (mov_pc & 0x0000f000) != RD(TMP_PC); - sljit_sw diff = (sljit_sw)(((sljit_sw)new_addr - (sljit_sw)(inst + 2) - executable_offset) >> 2); - - SLJIT_UNUSED_ARG(executable_offset); - - if (diff <= 0x7fffff && diff >= -0x800000) { - /* Turn to branch. */ - if (!bl) { - if (flush_cache) { - SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 0); - } - inst[0] = (mov_pc & COND_MASK) | (B - CONDITIONAL) | (diff & 0xffffff); - if (flush_cache) { - SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 1); - inst = (sljit_uw *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset); - SLJIT_CACHE_FLUSH(inst, inst + 1); - } - } else { - if (flush_cache) { - SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 0); - } - inst[0] = (mov_pc & COND_MASK) | (BL - CONDITIONAL) | (diff & 0xffffff); - inst[1] = NOP; - if (flush_cache) { - SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 1); - inst = (sljit_uw *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset); - SLJIT_CACHE_FLUSH(inst, inst + 2); - } - } - } else { - /* Get the position of the constant. */ - if (mov_pc & (1 << 23)) - ptr = inst + ((mov_pc & 0xfff) >> 2) + 2; - else - ptr = inst + 1; - - if (*inst != mov_pc) { - if (flush_cache) { - SLJIT_UPDATE_WX_FLAGS(inst, inst + (!bl ? 1 : 2), 0); - } - inst[0] = mov_pc; - if (!bl) { - if (flush_cache) { - SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 1); - inst = (sljit_uw *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset); - SLJIT_CACHE_FLUSH(inst, inst + 1); - } - } else { - inst[1] = BLX | RM(TMP_REG1); - if (flush_cache) { - SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 1); - inst = (sljit_uw *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset); - SLJIT_CACHE_FLUSH(inst, inst + 2); - } - } - } - - if (flush_cache) { - SLJIT_UPDATE_WX_FLAGS(ptr, ptr + 1, 0); - } - - *ptr = new_addr; - - if (flush_cache) { - SLJIT_UPDATE_WX_FLAGS(ptr, ptr + 1, 1); - } - } -#else - sljit_uw *inst = (sljit_uw*)jump_ptr; - - SLJIT_UNUSED_ARG(executable_offset); - - SLJIT_ASSERT((inst[0] & 0xfff00000) == MOVW && (inst[1] & 0xfff00000) == MOVT); - - if (flush_cache) { - SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 0); - } - - inst[0] = MOVW | (inst[0] & 0xf000) | ((new_addr << 4) & 0xf0000) | (new_addr & 0xfff); - inst[1] = MOVT | (inst[1] & 0xf000) | ((new_addr >> 12) & 0xf0000) | ((new_addr >> 16) & 0xfff); - - if (flush_cache) { - SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 1); - inst = (sljit_uw *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset); - SLJIT_CACHE_FLUSH(inst, inst + 2); - } -#endif -} - -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) -{ -#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) - sljit_uw *ptr = (sljit_uw*)addr; - sljit_uw *inst = (sljit_uw*)ptr[0]; - sljit_uw ldr_literal = ptr[1]; - sljit_uw src2; - - SLJIT_UNUSED_ARG(executable_offset); - - src2 = get_imm(new_constant); - if (src2) { - if (flush_cache) { - SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 0); - } - - *inst = 0xe3a00000 | (ldr_literal & 0xf000) | src2; - - if (flush_cache) { - SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 1); - inst = (sljit_uw *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset); - SLJIT_CACHE_FLUSH(inst, inst + 1); - } - return; - } - - src2 = get_imm(~new_constant); - if (src2) { - if (flush_cache) { - SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 0); - } - - *inst = 0xe3e00000 | (ldr_literal & 0xf000) | src2; - - if (flush_cache) { - SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 1); - inst = (sljit_uw *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset); - SLJIT_CACHE_FLUSH(inst, inst + 1); - } - return; - } - - if (ldr_literal & (1 << 23)) - ptr = inst + ((ldr_literal & 0xfff) >> 2) + 2; - else - ptr = inst + 1; - - if (*inst != ldr_literal) { - if (flush_cache) { - SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 0); - } - - *inst = ldr_literal; - - if (flush_cache) { - SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 1); - inst = (sljit_uw *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset); - SLJIT_CACHE_FLUSH(inst, inst + 1); - } - } - - if (flush_cache) { - SLJIT_UPDATE_WX_FLAGS(ptr, ptr + 1, 0); - } - - *ptr = new_constant; - - if (flush_cache) { - SLJIT_UPDATE_WX_FLAGS(ptr, ptr + 1, 1); - } -#else - sljit_uw *inst = (sljit_uw*)addr; - - SLJIT_UNUSED_ARG(executable_offset); - - SLJIT_ASSERT((inst[0] & 0xfff00000) == MOVW && (inst[1] & 0xfff00000) == MOVT); - - if (flush_cache) { - SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 0); - } - - inst[0] = MOVW | (inst[0] & 0xf000) | ((new_constant << 4) & 0xf0000) | (new_constant & 0xfff); - inst[1] = MOVT | (inst[1] & 0xf000) | ((new_constant >> 12) & 0xf0000) | ((new_constant >> 16) & 0xfff); - - if (flush_cache) { - SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 1); - inst = (sljit_uw *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset); - SLJIT_CACHE_FLUSH(inst, inst + 2); - } -#endif -} - -SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler) -{ - struct sljit_memory_fragment *buf; - sljit_uw *code; - sljit_uw *code_ptr; - sljit_uw *buf_ptr; - sljit_uw *buf_end; - sljit_uw size; - sljit_uw word_count; - sljit_uw next_addr; - sljit_sw executable_offset; - sljit_uw addr; -#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) - sljit_uw cpool_size; - sljit_uw cpool_skip_alignment; - sljit_uw cpool_current_index; - sljit_uw *cpool_start_address; - sljit_uw *last_pc_patch; - struct future_patch *first_patch; -#endif - - 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_V5 && SLJIT_CONFIG_ARM_V5) - size = compiler->size + (compiler->patches << 1); - if (compiler->cpool_fill > 0) - size += compiler->cpool_fill + CONST_POOL_ALIGNMENT - 1; -#else - size = compiler->size; -#endif - code = (sljit_uw*)SLJIT_MALLOC_EXEC(size * sizeof(sljit_uw), compiler->exec_allocator_data); - PTR_FAIL_WITH_EXEC_IF(code); - buf = compiler->buf; - -#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) - cpool_size = 0; - cpool_skip_alignment = 0; - cpool_current_index = 0; - cpool_start_address = NULL; - first_patch = NULL; - last_pc_patch = code; -#endif - - 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; - } - - do { - buf_ptr = (sljit_uw*)buf->memory; - buf_end = buf_ptr + (buf->used_size >> 2); - do { - word_count++; -#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) - if (cpool_size > 0) { - if (cpool_skip_alignment > 0) { - buf_ptr++; - cpool_skip_alignment--; - } - 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); - compiler->error = SLJIT_ERR_ALLOC_FAILED; - return NULL; - } - buf_ptr++; - 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) { -#endif - *code_ptr = *buf_ptr++; - if (next_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_V5 && SLJIT_CONFIG_ARM_V5) - if (detect_jump_type(jump, code_ptr, code, executable_offset)) - code_ptr--; - jump->addr = (sljit_uw)code_ptr; -#else - jump->addr = (sljit_uw)(code_ptr - 2); - if (detect_jump_type(jump, code_ptr, code, executable_offset)) - code_ptr -= 2; -#endif - 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); - label = label->next; - } - if (const_ && const_->addr == word_count) { -#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) - const_->addr = (sljit_uw)code_ptr; -#else - const_->addr = (sljit_uw)(code_ptr - 1); -#endif - const_ = const_->next; - } - 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); - } - code_ptr++; -#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) - } - else { - /* Fortunately, no need to shift. */ - cpool_size = *buf_ptr++ & ~PUSH_POOL; - SLJIT_ASSERT(cpool_size > 0); - cpool_start_address = ALIGN_INSTRUCTION(code_ptr + 1); - cpool_current_index = patch_pc_relative_loads(last_pc_patch, code_ptr, cpool_start_address, cpool_size); - if (cpool_current_index > 0) { - /* Unconditional branch. */ - *code_ptr = B | (((sljit_uw)(cpool_start_address - code_ptr) + cpool_current_index - 2) & ~PUSH_POOL); - code_ptr = (sljit_uw*)(cpool_start_address + cpool_current_index); - } - cpool_skip_alignment = CONST_POOL_ALIGNMENT - 1; - cpool_current_index = 0; - last_pc_patch = code_ptr; - } -#endif - } while (buf_ptr < buf_end); - buf = buf->next; - } while (buf); - - SLJIT_ASSERT(!label); - SLJIT_ASSERT(!jump); - SLJIT_ASSERT(!const_); - SLJIT_ASSERT(!put_label); - -#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) - SLJIT_ASSERT(cpool_size == 0); - if (compiler->cpool_fill > 0) { - cpool_start_address = ALIGN_INSTRUCTION(code_ptr); - cpool_current_index = patch_pc_relative_loads(last_pc_patch, code_ptr, cpool_start_address, compiler->cpool_fill); - if (cpool_current_index > 0) - code_ptr = (sljit_uw*)(cpool_start_address + cpool_current_index); - - buf_ptr = compiler->cpool; - buf_end = buf_ptr + compiler->cpool_fill; - 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); - compiler->error = SLJIT_ERR_ALLOC_FAILED; - return NULL; - } - buf_ptr++; - cpool_current_index++; - } - SLJIT_ASSERT(!first_patch); - } -#endif - - jump = compiler->jumps; - while (jump) { - buf_ptr = (sljit_uw *)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 (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) - jump->addr = (sljit_uw)code_ptr; - code_ptr[0] = (sljit_uw)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; -#else - inline_set_jump_addr((sljit_uw)buf_ptr, executable_offset, (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target, 0); -#endif - } - else { -#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) - 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; -#else - inline_set_jump_addr((sljit_uw)buf_ptr, executable_offset, (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target, 0); -#endif - } - jump = jump->next; - } - -#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) - const_ = compiler->consts; - while (const_) { - buf_ptr = (sljit_uw*)const_->addr; - const_->addr = (sljit_uw)code_ptr; - - code_ptr[0] = (sljit_uw)buf_ptr; - code_ptr[1] = *buf_ptr; - if (*buf_ptr & (1 << 23)) - buf_ptr += ((*buf_ptr & 0xfff) >> 2) + 2; - 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); - code_ptr += 2; - - const_ = const_->next; - } -#endif - - put_label = compiler->put_labels; - while (put_label) { - addr = put_label->label->addr; - buf_ptr = (sljit_uw*)put_label->addr; - -#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) - SLJIT_ASSERT((buf_ptr[0] & 0xffff0000) == 0xe59f0000); - buf_ptr[((buf_ptr[0] & 0xfff) >> 2) + 2] = addr; -#else - 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 - put_label = put_label->next; - } - - SLJIT_ASSERT(code_ptr - code <= (sljit_s32)size); - - compiler->error = SLJIT_ERR_COMPILED; - compiler->executable_offset = executable_offset; - compiler->executable_size = (sljit_uw)(code_ptr - code) * sizeof(sljit_uw); - - code = (sljit_uw *)SLJIT_ADD_EXEC_OFFSET(code, executable_offset); - code_ptr = (sljit_uw *)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset); - - SLJIT_CACHE_FLUSH(code, code_ptr); - SLJIT_UPDATE_WX_FLAGS(code, code_ptr, 1); - return code; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type) -{ - switch (feature_type) { - case SLJIT_HAS_FPU: -#ifdef SLJIT_IS_FPU_AVAILABLE - return SLJIT_IS_FPU_AVAILABLE; -#else - /* Available by default. */ - return 1; -#endif - - case SLJIT_HAS_CLZ: - case SLJIT_HAS_ROT: - case SLJIT_HAS_CMOV: -#if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) - case SLJIT_HAS_CTZ: - case SLJIT_HAS_PREFETCH: -#endif - return 1; - -#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) - case SLJIT_HAS_CTZ: - return 2; -#endif - - default: - return 0; - } -} - -/* --------------------------------------------------------------------- */ -/* Entry, exit */ -/* --------------------------------------------------------------------- */ - -/* Creates an index in data_transfer_insts array. */ -#define WORD_SIZE 0x00 -#define BYTE_SIZE 0x01 -#define HALF_SIZE 0x02 -#define PRELOAD 0x03 -#define SIGNED 0x04 -#define LOAD_DATA 0x08 - -/* Flag bits for emit_op. */ -#define ALLOW_IMM 0x10 -#define ALLOW_INV_IMM 0x20 -#define ALLOW_ANY_IMM (ALLOW_IMM | ALLOW_INV_IMM) -#define ALLOW_NEG_IMM 0x40 - -/* s/l - store/load (1 bit) - u/s - signed/unsigned (1 bit) - w/b/h/N - word/byte/half/NOT allowed (2 bit) - Storing signed and unsigned values are the same operations. */ - -static const sljit_uw data_transfer_insts[16] = { -/* s u w */ 0xe5000000 /* str */, -/* s u b */ 0xe5400000 /* strb */, -/* s u h */ 0xe10000b0 /* strh */, -/* s u N */ 0x00000000 /* not allowed */, -/* s s w */ 0xe5000000 /* str */, -/* s s b */ 0xe5400000 /* strb */, -/* s s h */ 0xe10000b0 /* strh */, -/* s s N */ 0x00000000 /* not allowed */, - -/* l u w */ 0xe5100000 /* ldr */, -/* l u b */ 0xe5500000 /* ldrb */, -/* l u h */ 0xe11000b0 /* ldrh */, -/* l u p */ 0xf5500000 /* preload */, -/* l s w */ 0xe5100000 /* ldr */, -/* l s b */ 0xe11000d0 /* ldrsb */, -/* l s h */ 0xe11000f0 /* ldrsh */, -/* l s N */ 0x00000000 /* not allowed */, -}; - -#define EMIT_DATA_TRANSFER(type, add, target_reg, base_reg, arg) \ - (data_transfer_insts[(type) & 0xf] | ((add) << 23) | RD(target_reg) | RN(base_reg) | (sljit_uw)(arg)) - -/* Normal ldr/str instruction. - Type2: ldrsb, ldrh, ldrsh */ -#define IS_TYPE1_TRANSFER(type) \ - (data_transfer_insts[(type) & 0xf] & 0x04000000) -#define TYPE2_TRANSFER_IMM(imm) \ - (((imm) & 0xf) | (((imm) & 0xf0) << 4) | (1 << 22)) - -#define EMIT_FPU_OPERATION(opcode, mode, dst, src1, src2) \ - ((sljit_uw)(opcode) | (sljit_uw)(mode) | VD(dst) | VM(src1) | VN(src2)) - -/* Flags for emit_op: */ - /* Arguments are swapped. */ -#define ARGS_SWAPPED 0x01 - /* Inverted immediate. */ -#define INV_IMM 0x02 - /* Source and destination is register. */ -#define MOVE_REG_CONV 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). */ -#define SET_FLAGS (1 << 20) -/* dst: reg - src1: reg - src2: reg or imm (if allowed) - SRC2_IMM must be (1 << 25) as it is also the value of I bit (can be used for optimization). */ -#define SRC2_IMM (1 << 25) - -static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 inp_flags, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w); - -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, - sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size) -{ - sljit_uw imm, offset; - sljit_s32 i, tmp, size, word_arg_count; - sljit_s32 saved_arg_count = SLJIT_KEPT_SAVEDS_COUNT(options); -#ifdef __SOFTFP__ - sljit_u32 float_arg_count; -#else - sljit_u32 old_offset, f32_offset; - sljit_u32 remap[3]; - sljit_u32 *remap_ptr = remap; -#endif - - CHECK_ERROR(); - CHECK(check_sljit_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size)); - set_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size); - - imm = 0; - - tmp = SLJIT_S0 - saveds; - for (i = SLJIT_S0 - saved_arg_count; i > tmp; i--) - imm |= (sljit_uw)1 << reg_map[i]; - - for (i = scratches; i >= SLJIT_FIRST_SAVED_REG; i--) - imm |= (sljit_uw)1 << reg_map[i]; - - SLJIT_ASSERT(reg_map[TMP_REG2] == 14); - - /* Push saved and temporary registers - multiple registers: stmdb sp!, {..., lr} - single register: str reg, [sp, #-4]! */ - if (imm != 0) - FAIL_IF(push_inst(compiler, PUSH | (1 << 14) | imm)); - else - FAIL_IF(push_inst(compiler, 0xe52d0004 | RD(TMP_REG2))); - - /* Stack must be aligned to 8 bytes: */ - size = GET_SAVED_REGISTERS_SIZE(scratches, saveds - saved_arg_count, 1); - - if (fsaveds > 0 || fscratches >= SLJIT_FIRST_SAVED_FLOAT_REG) { - if ((size & SSIZE_OF(sw)) != 0) { - FAIL_IF(push_inst(compiler, SUB | RD(SLJIT_SP) | RN(SLJIT_SP) | SRC2_IMM | sizeof(sljit_sw))); - size += SSIZE_OF(sw); - } - - if (fsaveds + fscratches >= SLJIT_NUMBER_OF_FLOAT_REGISTERS) { - FAIL_IF(push_inst(compiler, VPUSH | VD(SLJIT_FS0) | ((sljit_uw)SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS << 1))); - } else { - if (fsaveds > 0) - FAIL_IF(push_inst(compiler, VPUSH | VD(SLJIT_FS0) | ((sljit_uw)fsaveds << 1))); - if (fscratches >= SLJIT_FIRST_SAVED_FLOAT_REG) - FAIL_IF(push_inst(compiler, VPUSH | VD(fscratches) | ((sljit_uw)(fscratches - (SLJIT_FIRST_SAVED_FLOAT_REG - 1)) << 1))); - } - } - - local_size = ((size + local_size + 0x7) & ~0x7) - size; - compiler->local_size = local_size; - - if (options & SLJIT_ENTER_REG_ARG) - arg_types = 0; - - arg_types >>= SLJIT_ARG_SHIFT; - word_arg_count = 0; - saved_arg_count = 0; -#ifdef __SOFTFP__ - SLJIT_COMPILE_ASSERT(SLJIT_FR0 == 1, float_register_index_start); - - offset = 0; - float_arg_count = 0; - - while (arg_types) { - switch (arg_types & SLJIT_ARG_MASK) { - case SLJIT_ARG_TYPE_F64: - if (offset & 0x7) - offset += sizeof(sljit_sw); - - if (offset < 4 * sizeof(sljit_sw)) - FAIL_IF(push_inst(compiler, VMOV2 | (offset << 10) | ((offset + sizeof(sljit_sw)) << 14) | float_arg_count)); - else - FAIL_IF(push_inst(compiler, VLDR_F32 | 0x800100 | RN(SLJIT_SP) - | (float_arg_count << 12) | ((offset + (sljit_uw)size - 4 * sizeof(sljit_sw)) >> 2))); - float_arg_count++; - offset += sizeof(sljit_f64) - sizeof(sljit_sw); - break; - case SLJIT_ARG_TYPE_F32: - if (offset < 4 * sizeof(sljit_sw)) - FAIL_IF(push_inst(compiler, VMOV | (float_arg_count << 16) | (offset << 10))); - else - FAIL_IF(push_inst(compiler, VLDR_F32 | 0x800000 | RN(SLJIT_SP) - | (float_arg_count << 12) | ((offset + (sljit_uw)size - 4 * sizeof(sljit_sw)) >> 2))); - float_arg_count++; - break; - default: - word_arg_count++; - - if (!(arg_types & SLJIT_ARG_TYPE_SCRATCH_REG)) { - tmp = SLJIT_S0 - saved_arg_count; - saved_arg_count++; - } else if (word_arg_count - 1 != (sljit_s32)(offset >> 2)) - tmp = word_arg_count; - else - break; - - if (offset < 4 * sizeof(sljit_sw)) - FAIL_IF(push_inst(compiler, MOV | RD(tmp) | (offset >> 2))); - else - FAIL_IF(push_inst(compiler, LDR | 0x800000 | RN(SLJIT_SP) | RD(tmp) | (offset + (sljit_uw)size - 4 * sizeof(sljit_sw)))); - break; - } - - offset += sizeof(sljit_sw); - arg_types >>= SLJIT_ARG_SHIFT; - } - - compiler->args_size = offset; -#else - offset = SLJIT_FR0; - old_offset = SLJIT_FR0; - f32_offset = 0; - - while (arg_types) { - switch (arg_types & SLJIT_ARG_MASK) { - case SLJIT_ARG_TYPE_F64: - if (offset != old_offset) - *remap_ptr++ = EMIT_FPU_OPERATION(VMOV_F32, SLJIT_32, offset, old_offset, 0); - old_offset++; - offset++; - break; - case SLJIT_ARG_TYPE_F32: - if (f32_offset != 0) { - *remap_ptr++ = EMIT_FPU_OPERATION(VMOV_F32, 0x20, offset, f32_offset, 0); - f32_offset = 0; - } else { - if (offset != old_offset) - *remap_ptr++ = EMIT_FPU_OPERATION(VMOV_F32, 0, offset, old_offset, 0); - f32_offset = old_offset; - old_offset++; - } - offset++; - break; - default: - if (!(arg_types & SLJIT_ARG_TYPE_SCRATCH_REG)) { - FAIL_IF(push_inst(compiler, MOV | RD(SLJIT_S0 - saved_arg_count) | RM(SLJIT_R0 + word_arg_count))); - saved_arg_count++; - } - - word_arg_count++; - break; - } - arg_types >>= SLJIT_ARG_SHIFT; - } - - SLJIT_ASSERT((sljit_uw)(remap_ptr - remap) <= sizeof(remap)); - - while (remap_ptr > remap) - FAIL_IF(push_inst(compiler, *(--remap_ptr))); -#endif - - if (local_size > 0) - FAIL_IF(emit_op(compiler, SLJIT_SUB, ALLOW_IMM, SLJIT_SP, 0, SLJIT_SP, 0, SLJIT_IMM, local_size)); - - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(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) -{ - sljit_s32 size; - - CHECK_ERROR(); - CHECK(check_sljit_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size)); - set_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size); - - size = GET_SAVED_REGISTERS_SIZE(scratches, saveds - SLJIT_KEPT_SAVEDS_COUNT(options), 1); - - if ((size & SSIZE_OF(sw)) != 0 && (fsaveds > 0 || fscratches >= SLJIT_FIRST_SAVED_FLOAT_REG)) - size += SSIZE_OF(sw); - - compiler->local_size = ((size + local_size + 0x7) & ~0x7) - size; - return SLJIT_SUCCESS; -} - -static sljit_s32 emit_add_sp(struct sljit_compiler *compiler, sljit_uw imm) -{ - sljit_uw imm2 = get_imm(imm); - - if (imm2 == 0) { - imm2 = (imm & ~(sljit_uw)0x3ff) >> 10; - imm = (imm & 0x3ff) >> 2; - - FAIL_IF(push_inst(compiler, ADD | SRC2_IMM | RD(SLJIT_SP) | RN(SLJIT_SP) | 0xb00 | imm2)); - return push_inst(compiler, ADD | SRC2_IMM | RD(SLJIT_SP) | RN(SLJIT_SP) | 0xf00 | (imm & 0xff)); - } - - return push_inst(compiler, ADD | RD(SLJIT_SP) | RN(SLJIT_SP) | imm2); -} - -static sljit_s32 emit_stack_frame_release(struct sljit_compiler *compiler, sljit_s32 frame_size) -{ - sljit_s32 local_size, fscratches, fsaveds, i, tmp; - sljit_s32 restored_reg = 0; - sljit_s32 lr_dst = TMP_PC; - sljit_uw reg_list = 0; - - SLJIT_ASSERT(reg_map[TMP_REG2] == 14 && frame_size <= 128); - - local_size = compiler->local_size; - fscratches = compiler->fscratches; - fsaveds = compiler->fsaveds; - - if (fsaveds > 0 || fscratches >= SLJIT_FIRST_SAVED_FLOAT_REG) { - if (local_size > 0) - FAIL_IF(emit_add_sp(compiler, (sljit_uw)local_size)); - - if (fsaveds + fscratches >= SLJIT_NUMBER_OF_FLOAT_REGISTERS) { - FAIL_IF(push_inst(compiler, VPOP | VD(SLJIT_FS0) | ((sljit_uw)SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS << 1))); - } else { - if (fscratches >= SLJIT_FIRST_SAVED_FLOAT_REG) - FAIL_IF(push_inst(compiler, VPOP | VD(fscratches) | ((sljit_uw)(fscratches - (SLJIT_FIRST_SAVED_FLOAT_REG - 1)) << 1))); - if (fsaveds > 0) - FAIL_IF(push_inst(compiler, VPOP | VD(SLJIT_FS0) | ((sljit_uw)fsaveds << 1))); - } - - local_size = GET_SAVED_REGISTERS_SIZE(compiler->scratches, compiler->saveds, 1) & 0x7; - } - - if (frame_size < 0) { - lr_dst = TMP_REG2; - frame_size = 0; - } else if (frame_size > 0) { - SLJIT_ASSERT(frame_size == 1 || (frame_size & 0x7) == 0); - lr_dst = 0; - frame_size &= ~0x7; - } - - if (lr_dst != 0) - reg_list |= (sljit_uw)1 << reg_map[lr_dst]; - - tmp = SLJIT_S0 - compiler->saveds; - i = SLJIT_S0 - SLJIT_KEPT_SAVEDS_COUNT(compiler->options); - if (tmp < i) { - restored_reg = i; - do { - reg_list |= (sljit_uw)1 << reg_map[i]; - } while (--i > tmp); - } - - i = compiler->scratches; - if (i >= SLJIT_FIRST_SAVED_REG) { - restored_reg = i; - do { - reg_list |= (sljit_uw)1 << reg_map[i]; - } while (--i >= SLJIT_FIRST_SAVED_REG); - } - - if (lr_dst == TMP_REG2 && reg_list == 0) { - restored_reg = TMP_REG2; - lr_dst = 0; - } - - if (lr_dst == 0 && (reg_list & (reg_list - 1)) == 0) { - /* The local_size does not include the saved registers. */ - tmp = 0; - if (reg_list != 0) { - tmp = 2; - if (local_size <= 0xfff) { - if (local_size == 0) { - SLJIT_ASSERT(restored_reg != TMP_REG2); - if (frame_size == 0) - return push_inst(compiler, LDR_POST | RN(SLJIT_SP) | RD(restored_reg) | 0x800008); - if (frame_size > 2 * SSIZE_OF(sw)) - return push_inst(compiler, LDR_POST | RN(SLJIT_SP) | RD(restored_reg) | (sljit_uw)(frame_size - (2 * SSIZE_OF(sw)))); - } - - FAIL_IF(push_inst(compiler, LDR | 0x800000 | RN(SLJIT_SP) | RD(restored_reg) | (sljit_uw)local_size)); - tmp = 1; - } else if (frame_size == 0) { - frame_size = (restored_reg == TMP_REG2) ? SSIZE_OF(sw) : 2 * SSIZE_OF(sw); - tmp = 3; - } - - /* Place for the saved register. */ - if (restored_reg != TMP_REG2) - local_size += SSIZE_OF(sw); - } - - /* Place for the lr register. */ - local_size += SSIZE_OF(sw); - - if (frame_size > local_size) - FAIL_IF(push_inst(compiler, SUB | RD(SLJIT_SP) | RN(SLJIT_SP) | (1 << 25) | (sljit_uw)(frame_size - local_size))); - else if (frame_size < local_size) - FAIL_IF(emit_add_sp(compiler, (sljit_uw)(local_size - frame_size))); - - if (tmp <= 1) - return SLJIT_SUCCESS; - - if (tmp == 2) { - frame_size -= SSIZE_OF(sw); - if (restored_reg != TMP_REG2) - frame_size -= SSIZE_OF(sw); - - return push_inst(compiler, LDR | 0x800000 | RN(SLJIT_SP) | RD(restored_reg) | (sljit_uw)frame_size); - } - - tmp = (restored_reg == TMP_REG2) ? 0x800004 : 0x800008; - return push_inst(compiler, LDR_POST | RN(SLJIT_SP) | RD(restored_reg) | (sljit_uw)tmp); - } - - if (local_size > 0) - FAIL_IF(emit_add_sp(compiler, (sljit_uw)local_size)); - - /* Pop saved and temporary registers - multiple registers: ldmia sp!, {...} - single register: ldr reg, [sp], #4 */ - if ((reg_list & (reg_list - 1)) == 0) { - SLJIT_ASSERT(lr_dst != 0); - SLJIT_ASSERT(reg_list == (sljit_uw)1 << reg_map[lr_dst]); - - return push_inst(compiler, LDR_POST | RN(SLJIT_SP) | RD(lr_dst) | 0x800004); - } - - FAIL_IF(push_inst(compiler, POP | reg_list)); - - if (frame_size > 0) - return push_inst(compiler, SUB | RD(SLJIT_SP) | RN(SLJIT_SP) | (1 << 25) | ((sljit_uw)frame_size - sizeof(sljit_sw))); - - if (lr_dst != 0) - return SLJIT_SUCCESS; - - return push_inst(compiler, ADD | RD(SLJIT_SP) | RN(SLJIT_SP) | (1 << 25) | sizeof(sljit_sw)); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_void(struct sljit_compiler *compiler) -{ - CHECK_ERROR(); - CHECK(check_sljit_emit_return_void(compiler)); - - return emit_stack_frame_release(compiler, 0); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_to(struct sljit_compiler *compiler, - sljit_s32 src, sljit_sw srcw) -{ - CHECK_ERROR(); - CHECK(check_sljit_emit_return_to(compiler, src, srcw)); - - if (src & SLJIT_MEM) { - FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, TMP_REG1, src, srcw, TMP_REG1)); - src = TMP_REG1; - srcw = 0; - } else if (src >= SLJIT_FIRST_SAVED_REG && src <= (SLJIT_S0 - SLJIT_KEPT_SAVEDS_COUNT(compiler->options))) { - FAIL_IF(push_inst(compiler, MOV | RD(TMP_REG1) | RM(src))); - src = TMP_REG1; - srcw = 0; - } - - FAIL_IF(emit_stack_frame_release(compiler, 1)); - - SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_ijump(compiler, SLJIT_JUMP, src, srcw); -} - -/* --------------------------------------------------------------------- */ -/* Operators */ -/* --------------------------------------------------------------------- */ - -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_uw shift_type; - - switch (GET_OPCODE(op)) { - case SLJIT_MOV: - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & ARGS_SWAPPED)); - if (dst != src2) { - if (src2 & SRC2_IMM) { - return push_inst(compiler, ((flags & INV_IMM) ? MVN : MOV) | RD(dst) | src2); - } - return push_inst(compiler, MOV | RD(dst) | RM(src2)); - } - return SLJIT_SUCCESS; - - case SLJIT_MOV_U8: - case SLJIT_MOV_S8: - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & ARGS_SWAPPED)); - if (flags & MOVE_REG_CONV) { -#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) - if (op == SLJIT_MOV_U8) - return push_inst(compiler, AND | RD(dst) | RN(src2) | SRC2_IMM | 0xff); - FAIL_IF(push_inst(compiler, MOV | RD(dst) | (24 << 7) | RM(src2))); - return push_inst(compiler, MOV | RD(dst) | (24 << 7) | (op == SLJIT_MOV_U8 ? 0x20 : 0x40) | RM(dst)); -#else - return push_inst(compiler, (op == SLJIT_MOV_U8 ? UXTB : SXTB) | RD(dst) | RM(src2)); -#endif - } - else if (dst != src2) { - SLJIT_ASSERT(src2 & SRC2_IMM); - return push_inst(compiler, ((flags & INV_IMM) ? MVN : MOV) | RD(dst) | src2); - } - return SLJIT_SUCCESS; - - case SLJIT_MOV_U16: - case SLJIT_MOV_S16: - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & ARGS_SWAPPED)); - if (flags & MOVE_REG_CONV) { -#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) - FAIL_IF(push_inst(compiler, MOV | RD(dst) | (16 << 7) | RM(src2))); - return push_inst(compiler, MOV | RD(dst) | (16 << 7) | (op == SLJIT_MOV_U16 ? 0x20 : 0x40) | RM(dst)); -#else - return push_inst(compiler, (op == SLJIT_MOV_U16 ? UXTH : SXTH) | RD(dst) | RM(src2)); -#endif - } - else if (dst != src2) { - SLJIT_ASSERT(src2 & SRC2_IMM); - return push_inst(compiler, ((flags & INV_IMM) ? MVN : MOV) | RD(dst) | src2); - } - return SLJIT_SUCCESS; - - case SLJIT_NOT: - if (src2 & SRC2_IMM) - return push_inst(compiler, ((flags & INV_IMM) ? MOV : MVN) | (flags & SET_FLAGS) | RD(dst) | src2); - - return push_inst(compiler, MVN | (flags & SET_FLAGS) | RD(dst) | RM(src2)); - - case SLJIT_CLZ: - SLJIT_ASSERT(!(flags & INV_IMM) && !(src2 & SRC2_IMM)); - FAIL_IF(push_inst(compiler, CLZ | RD(dst) | RM(src2))); - return SLJIT_SUCCESS; - - case SLJIT_CTZ: - SLJIT_ASSERT(!(flags & INV_IMM) && !(src2 & SRC2_IMM)); - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & ARGS_SWAPPED)); -#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) - 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, 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_V5 */ - FAIL_IF(push_inst(compiler, RBIT | RD(dst) | RM(src2))); - return push_inst(compiler, CLZ | RD(dst) | RM(dst)); -#endif /* SLJIT_CONFIG_ARM_V5 */ - - case SLJIT_ADD: - SLJIT_ASSERT(!(flags & INV_IMM)); - - if ((flags & (UNUSED_RETURN | ARGS_SWAPPED)) == UNUSED_RETURN) - return push_inst(compiler, CMN | SET_FLAGS | RN(src1) | ((src2 & SRC2_IMM) ? src2 : RM(src2))); - return push_inst(compiler, ADD | (flags & SET_FLAGS) | RD(dst) | RN(src1) | ((src2 & SRC2_IMM) ? src2 : RM(src2))); - - case SLJIT_ADDC: - SLJIT_ASSERT(!(flags & INV_IMM)); - return push_inst(compiler, ADC | (flags & SET_FLAGS) | RD(dst) | RN(src1) | ((src2 & SRC2_IMM) ? src2 : RM(src2))); - - case SLJIT_SUB: - SLJIT_ASSERT(!(flags & INV_IMM)); - - if ((flags & (UNUSED_RETURN | ARGS_SWAPPED)) == UNUSED_RETURN) - return push_inst(compiler, CMP | SET_FLAGS | RN(src1) | ((src2 & SRC2_IMM) ? src2 : RM(src2))); - - return push_inst(compiler, (!(flags & ARGS_SWAPPED) ? SUB : RSB) | (flags & SET_FLAGS) - | RD(dst) | RN(src1) | ((src2 & SRC2_IMM) ? src2 : RM(src2))); - - case SLJIT_SUBC: - SLJIT_ASSERT(!(flags & INV_IMM)); - return push_inst(compiler, (!(flags & ARGS_SWAPPED) ? SBC : RSC) | (flags & SET_FLAGS) - | RD(dst) | RN(src1) | ((src2 & SRC2_IMM) ? src2 : RM(src2))); - - case SLJIT_MUL: - SLJIT_ASSERT(!(flags & INV_IMM)); - SLJIT_ASSERT(!(src2 & SRC2_IMM)); - compiler->status_flags_state = 0; - - if (!HAS_FLAGS(op)) - 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))); - - /* cmp TMP_REG1, dst asr #31. */ - return push_inst(compiler, CMP | SET_FLAGS | RN(TMP_REG1) | RM(dst) | 0xfc0); - - case SLJIT_AND: - if ((flags & (UNUSED_RETURN | INV_IMM)) == UNUSED_RETURN) - return push_inst(compiler, TST | SET_FLAGS | RN(src1) | ((src2 & SRC2_IMM) ? src2 : RM(src2))); - return push_inst(compiler, (!(flags & INV_IMM) ? AND : BIC) | (flags & SET_FLAGS) - | RD(dst) | RN(src1) | ((src2 & SRC2_IMM) ? src2 : RM(src2))); - - case SLJIT_OR: - SLJIT_ASSERT(!(flags & INV_IMM)); - return push_inst(compiler, ORR | (flags & SET_FLAGS) | RD(dst) | RN(src1) | ((src2 & SRC2_IMM) ? src2 : RM(src2))); - - case SLJIT_XOR: - SLJIT_ASSERT(!(flags & INV_IMM)); - return push_inst(compiler, EOR | (flags & SET_FLAGS) | RD(dst) | RN(src1) | ((src2 & SRC2_IMM) ? src2 : RM(src2))); - - case SLJIT_SHL: - case SLJIT_MSHL: - shift_type = 0; - is_masked = GET_OPCODE(op) == SLJIT_MSHL; - break; - - case SLJIT_LSHR: - case SLJIT_MLSHR: - shift_type = 1; - is_masked = GET_OPCODE(op) == SLJIT_MLSHR; - break; - - case SLJIT_ASHR: - case SLJIT_MASHR: - shift_type = 2; - is_masked = GET_OPCODE(op) == SLJIT_MASHR; - break; - - case SLJIT_ROTL: - if (compiler->shift_imm == 0x20) { - FAIL_IF(push_inst(compiler, RSB | SRC2_IMM | RD(TMP_REG2) | RN(src2) | 0)); - src2 = TMP_REG2; - } else - compiler->shift_imm = (sljit_uw)(-(sljit_sw)compiler->shift_imm) & 0x1f; - /* fallthrough */ - - case SLJIT_ROTR: - shift_type = 3; - is_masked = 0; - break; - - default: - SLJIT_UNREACHABLE(); - return SLJIT_SUCCESS; - } - - SLJIT_ASSERT(!(flags & ARGS_SWAPPED) && !(flags & INV_IMM) && !(src2 & SRC2_IMM)); - - if (compiler->shift_imm != 0x20) { - SLJIT_ASSERT(src1 == TMP_REG1); - - if (compiler->shift_imm != 0) - return push_inst(compiler, MOV | (flags & SET_FLAGS) | - RD(dst) | (compiler->shift_imm << 7) | (shift_type << 5) | RM(src2)); - return push_inst(compiler, MOV | (flags & SET_FLAGS) | RD(dst) | RM(src2)); - } - - SLJIT_ASSERT(src1 != TMP_REG2); - - if (is_masked) { - FAIL_IF(push_inst(compiler, AND | RD(TMP_REG2) | RN(src2) | SRC2_IMM | 0x1f)); - src2 = TMP_REG2; - } - - return push_inst(compiler, MOV | (flags & SET_FLAGS) | RD(dst) - | RM8(src2) | (sljit_uw)(shift_type << 5) | 0x10 | RM(src1)); -} - -#undef EMIT_SHIFT_INS_AND_RETURN - -/* Tests whether the immediate can be stored in the 12 bit imm field. - Returns with 0 if not possible. */ -static sljit_uw get_imm(sljit_uw imm) -{ - sljit_u32 rol; - - if (imm <= 0xff) - return SRC2_IMM | imm; - - if (!(imm & 0xff000000)) { - imm <<= 8; - rol = 8; - } - else { - imm = (imm << 24) | (imm >> 8); - rol = 0; - } - - if (!(imm & 0xff000000)) { - imm <<= 8; - rol += 4; - } - - if (!(imm & 0xf0000000)) { - imm <<= 4; - rol += 2; - } - - if (!(imm & 0xc0000000)) { - imm <<= 2; - rol += 1; - } - - if (!(imm & 0x00ffffff)) - return SRC2_IMM | (imm >> 24) | (rol << 8); - else - return 0; -} - -#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) -static sljit_s32 generate_int(struct sljit_compiler *compiler, sljit_s32 reg, sljit_uw imm, sljit_s32 positive) -{ - sljit_uw mask; - sljit_uw imm1; - sljit_uw imm2; - sljit_uw rol; - - /* Step1: Search a zero byte (8 continous zero bit). */ - mask = 0xff000000; - rol = 8; - while(1) { - if (!(imm & mask)) { - /* Rol imm by rol. */ - imm = (imm << rol) | (imm >> (32 - rol)); - /* Calculate arm rol. */ - rol = 4 + (rol >> 1); - break; - } - rol += 2; - mask >>= 2; - if (mask & 0x3) { - /* rol by 8. */ - imm = (imm << 8) | (imm >> 24); - mask = 0xff00; - rol = 24; - while (1) { - if (!(imm & mask)) { - /* Rol imm by rol. */ - imm = (imm << rol) | (imm >> (32 - rol)); - /* Calculate arm rol. */ - rol = (rol >> 1) - 8; - break; - } - rol += 2; - mask >>= 2; - if (mask & 0x3) - return 0; - } - break; - } - } - - /* The low 8 bit must be zero. */ - SLJIT_ASSERT(!(imm & 0xff)); - - if (!(imm & 0xff000000)) { - imm1 = SRC2_IMM | ((imm >> 16) & 0xff) | (((rol + 4) & 0xf) << 8); - imm2 = SRC2_IMM | ((imm >> 8) & 0xff) | (((rol + 8) & 0xf) << 8); - } - else if (imm & 0xc0000000) { - imm1 = SRC2_IMM | ((imm >> 24) & 0xff) | ((rol & 0xf) << 8); - imm <<= 8; - rol += 4; - - if (!(imm & 0xff000000)) { - imm <<= 8; - rol += 4; - } - - if (!(imm & 0xf0000000)) { - imm <<= 4; - rol += 2; - } - - if (!(imm & 0xc0000000)) { - imm <<= 2; - rol += 1; - } - - if (!(imm & 0x00ffffff)) - imm2 = SRC2_IMM | (imm >> 24) | ((rol & 0xf) << 8); - else - return 0; - } - else { - if (!(imm & 0xf0000000)) { - imm <<= 4; - rol += 2; - } - - if (!(imm & 0xc0000000)) { - imm <<= 2; - rol += 1; - } - - imm1 = SRC2_IMM | ((imm >> 24) & 0xff) | ((rol & 0xf) << 8); - imm <<= 8; - rol += 4; - - if (!(imm & 0xf0000000)) { - imm <<= 4; - rol += 2; - } - - if (!(imm & 0xc0000000)) { - imm <<= 2; - rol += 1; - } - - if (!(imm & 0x00ffffff)) - imm2 = SRC2_IMM | (imm >> 24) | ((rol & 0xf) << 8); - else - return 0; - } - - FAIL_IF(push_inst(compiler, (positive ? MOV : MVN) | RD(reg) | imm1)); - FAIL_IF(push_inst(compiler, (positive ? ORR : BIC) | RD(reg) | RN(reg) | imm2)); - return 1; -} -#endif - -static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 reg, sljit_uw imm) -{ - sljit_uw tmp; - -#if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) - if (!(imm & ~(sljit_uw)0xffff)) - return push_inst(compiler, MOVW | RD(reg) | ((imm << 4) & 0xf0000) | (imm & 0xfff)); -#endif - - /* Create imm by 1 inst. */ - tmp = get_imm(imm); - if (tmp) - return push_inst(compiler, MOV | RD(reg) | tmp); - - tmp = get_imm(~imm); - if (tmp) - return push_inst(compiler, MVN | RD(reg) | tmp); - -#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) - /* Create imm by 2 inst. */ - FAIL_IF(generate_int(compiler, reg, imm, 1)); - FAIL_IF(generate_int(compiler, reg, ~imm, 0)); - - /* Load integer. */ - return push_inst_with_literal(compiler, EMIT_DATA_TRANSFER(WORD_SIZE | LOAD_DATA, 1, reg, TMP_PC, 0), imm); -#else - FAIL_IF(push_inst(compiler, MOVW | RD(reg) | ((imm << 4) & 0xf0000) | (imm & 0xfff))); - if (imm <= 0xffff) - return SLJIT_SUCCESS; - return push_inst(compiler, MOVT | RD(reg) | ((imm >> 12) & 0xf0000) | ((imm >> 16) & 0xfff)); -#endif -} - -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) -{ - sljit_uw imm, offset_reg, tmp; - sljit_sw mask = IS_TYPE1_TRANSFER(flags) ? 0xfff : 0xff; - sljit_sw sign = IS_TYPE1_TRANSFER(flags) ? 0x1000 : 0x100; - - SLJIT_ASSERT(arg & SLJIT_MEM); - SLJIT_ASSERT((arg & REG_MASK) != tmp_reg || (arg == SLJIT_MEM1(tmp_reg) && argw >= -mask && argw <= mask)); - - if (SLJIT_UNLIKELY(!(arg & REG_MASK))) { - tmp = (sljit_uw)(argw & (sign | mask)); - tmp = (sljit_uw)((argw + (tmp <= (sljit_uw)sign ? 0 : sign)) & ~mask); - - FAIL_IF(load_immediate(compiler, tmp_reg, tmp)); - - argw -= (sljit_sw)tmp; - tmp = 1; - - if (argw < 0) { - argw = -argw; - tmp = 0; - } - - return push_inst(compiler, EMIT_DATA_TRANSFER(flags, tmp, reg, tmp_reg, - (mask == 0xff) ? TYPE2_TRANSFER_IMM(argw) : argw)); - } - - if (arg & OFFS_REG_MASK) { - offset_reg = OFFS_REG(arg); - arg &= REG_MASK; - argw &= 0x3; - - if (argw != 0 && (mask == 0xff)) { - FAIL_IF(push_inst(compiler, ADD | RD(tmp_reg) | RN(arg) | RM(offset_reg) | ((sljit_uw)argw << 7))); - return push_inst(compiler, EMIT_DATA_TRANSFER(flags, 1, reg, tmp_reg, TYPE2_TRANSFER_IMM(0))); - } - - /* Bit 25: RM is offset. */ - return push_inst(compiler, EMIT_DATA_TRANSFER(flags, 1, reg, arg, - RM(offset_reg) | (mask == 0xff ? 0 : (1 << 25)) | ((sljit_uw)argw << 7))); - } - - arg &= REG_MASK; - - if (argw > mask) { - tmp = (sljit_uw)(argw & (sign | mask)); - tmp = (sljit_uw)((argw + (tmp <= (sljit_uw)sign ? 0 : sign)) & ~mask); - imm = get_imm(tmp); - - if (imm) { - FAIL_IF(push_inst(compiler, ADD | RD(tmp_reg) | RN(arg) | imm)); - argw -= (sljit_sw)tmp; - arg = tmp_reg; - - SLJIT_ASSERT(argw >= -mask && argw <= mask); - } - } else if (argw < -mask) { - tmp = (sljit_uw)(-argw & (sign | mask)); - tmp = (sljit_uw)((-argw + (tmp <= (sljit_uw)sign ? 0 : sign)) & ~mask); - imm = get_imm(tmp); - - if (imm) { - FAIL_IF(push_inst(compiler, SUB | RD(tmp_reg) | RN(arg) | imm)); - argw += (sljit_sw)tmp; - arg = tmp_reg; - - SLJIT_ASSERT(argw >= -mask && argw <= mask); - } - } - - if (argw <= mask && argw >= -mask) { - if (argw >= 0) { - if (mask == 0xff) - argw = TYPE2_TRANSFER_IMM(argw); - return push_inst(compiler, EMIT_DATA_TRANSFER(flags, 1, reg, arg, argw)); - } - - argw = -argw; - - if (mask == 0xff) - argw = TYPE2_TRANSFER_IMM(argw); - - return push_inst(compiler, EMIT_DATA_TRANSFER(flags, 0, reg, arg, argw)); - } - - FAIL_IF(load_immediate(compiler, tmp_reg, (sljit_uw)argw)); - return push_inst(compiler, EMIT_DATA_TRANSFER(flags, 1, reg, arg, - RM(tmp_reg) | (mask == 0xff ? 0 : (1 << 25)))); -} - -static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 inp_flags, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - /* src1 is reg or TMP_REG1 - src2 is reg, TMP_REG2, or imm - result goes to TMP_REG2, so put result can use TMP_REG1. */ - - /* We prefers register and simple consts. */ - sljit_s32 dst_reg; - sljit_s32 src1_reg; - sljit_s32 src2_reg = 0; - sljit_s32 flags = HAS_FLAGS(op) ? SET_FLAGS : 0; - sljit_s32 neg_op = 0; - - if (dst == TMP_REG2) - flags |= UNUSED_RETURN; - - SLJIT_ASSERT(!(inp_flags & ALLOW_INV_IMM) || (inp_flags & ALLOW_IMM)); - - if (inp_flags & ALLOW_NEG_IMM) { - switch (GET_OPCODE(op)) { - case SLJIT_ADD: - compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD; - neg_op = SLJIT_SUB; - break; - case SLJIT_ADDC: - compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD; - neg_op = SLJIT_SUBC; - break; - case SLJIT_SUB: - compiler->status_flags_state = SLJIT_CURRENT_FLAGS_SUB; - neg_op = SLJIT_ADD; - break; - case SLJIT_SUBC: - compiler->status_flags_state = SLJIT_CURRENT_FLAGS_SUB; - neg_op = SLJIT_ADDC; - break; - } - } - - do { - if (!(inp_flags & ALLOW_IMM)) - break; - - if (src2 & SLJIT_IMM) { - src2_reg = (sljit_s32)get_imm((sljit_uw)src2w); - if (src2_reg) - break; - if (inp_flags & ALLOW_INV_IMM) { - src2_reg = (sljit_s32)get_imm(~(sljit_uw)src2w); - if (src2_reg) { - flags |= INV_IMM; - break; - } - } - if (neg_op != 0) { - src2_reg = (sljit_s32)get_imm((sljit_uw)-src2w); - if (src2_reg) { - op = neg_op | GET_ALL_FLAGS(op); - break; - } - } - } - - if (src1 & SLJIT_IMM) { - src2_reg = (sljit_s32)get_imm((sljit_uw)src1w); - if (src2_reg) { - flags |= ARGS_SWAPPED; - src1 = src2; - src1w = src2w; - break; - } - if (inp_flags & ALLOW_INV_IMM) { - src2_reg = (sljit_s32)get_imm(~(sljit_uw)src1w); - if (src2_reg) { - flags |= ARGS_SWAPPED | INV_IMM; - src1 = src2; - src1w = src2w; - break; - } - } - if (neg_op >= SLJIT_SUB) { - /* Note: additive operation (commutative). */ - src2_reg = (sljit_s32)get_imm((sljit_uw)-src1w); - if (src2_reg) { - src1 = src2; - src1w = src2w; - op = neg_op | GET_ALL_FLAGS(op); - break; - } - } - } - } 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 { - FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)src1w)); - src1_reg = TMP_REG1; - } - - /* Destination. */ - dst_reg = FAST_IS_REG(dst) ? dst : TMP_REG2; - - if (op <= SLJIT_MOV_P) { - if (dst & SLJIT_MEM) { - if (inp_flags & BYTE_SIZE) - inp_flags &= ~SIGNED; - - if (FAST_IS_REG(src2)) - return emit_op_mem(compiler, inp_flags, src2, dst, dstw, TMP_REG2); - } - - if (FAST_IS_REG(src2) && dst_reg != TMP_REG2) - flags |= MOVE_REG_CONV; - } - - /* Source 2. */ - if (src2_reg == 0) { - src2_reg = (op <= SLJIT_MOV_P) ? dst_reg : TMP_REG2; - - 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 - FAIL_IF(load_immediate(compiler, src2_reg, (sljit_uw)src2w)); - } - - FAIL_IF(emit_single_op(compiler, op, flags, (sljit_uw)dst_reg, (sljit_uw)src1_reg, (sljit_uw)src2_reg)); - - if (!(dst & SLJIT_MEM)) - return SLJIT_SUCCESS; - - return emit_op_mem(compiler, inp_flags, dst_reg, dst, dstw, TMP_REG1); -} - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined(__GNUC__) -extern unsigned int __aeabi_uidivmod(unsigned int numerator, unsigned int denominator); -extern int __aeabi_idivmod(int numerator, int denominator); -#else -#error "Software divmod functions are needed" -#endif - -#ifdef __cplusplus -} -#endif - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compiler, sljit_s32 op) -{ - sljit_uw saved_reg_list[3]; - sljit_sw saved_reg_count; - - CHECK_ERROR(); - CHECK(check_sljit_emit_op0(compiler, op)); - - op = GET_OPCODE(op); - switch (op) { - case SLJIT_BREAKPOINT: - FAIL_IF(push_inst(compiler, BKPT)); - break; - case SLJIT_NOP: - FAIL_IF(push_inst(compiler, NOP)); - break; - case SLJIT_LMUL_UW: - case SLJIT_LMUL_SW: - return push_inst(compiler, (op == SLJIT_LMUL_UW ? UMULL : SMULL) - | RN(SLJIT_R1) | RD(SLJIT_R0) | RM8(SLJIT_R0) | RM(SLJIT_R1)); - case SLJIT_DIVMOD_UW: - case SLJIT_DIVMOD_SW: - case SLJIT_DIV_UW: - case SLJIT_DIV_SW: - SLJIT_COMPILE_ASSERT((SLJIT_DIVMOD_UW & 0x2) == 0 && SLJIT_DIV_UW - 0x2 == SLJIT_DIVMOD_UW, bad_div_opcode_assignments); - SLJIT_ASSERT(reg_map[2] == 1 && reg_map[3] == 2 && reg_map[4] == 3); - - saved_reg_count = 0; - if (compiler->scratches >= 4) - saved_reg_list[saved_reg_count++] = 3; - if (compiler->scratches >= 3) - saved_reg_list[saved_reg_count++] = 2; - if (op >= SLJIT_DIV_UW) - saved_reg_list[saved_reg_count++] = 1; - - if (saved_reg_count > 0) { - FAIL_IF(push_inst(compiler, STR | 0x2d0000 | (saved_reg_count >= 3 ? 16 : 8) - | (saved_reg_list[0] << 12) /* str rX, [sp, #-8/-16]! */)); - if (saved_reg_count >= 2) { - SLJIT_ASSERT(saved_reg_list[1] < 8); - FAIL_IF(push_inst(compiler, STR | 0x8d0004 | (saved_reg_list[1] << 12) /* str rX, [sp, #4] */)); - } - if (saved_reg_count >= 3) { - SLJIT_ASSERT(saved_reg_list[2] < 8); - FAIL_IF(push_inst(compiler, STR | 0x8d0008 | (saved_reg_list[2] << 12) /* str rX, [sp, #8] */)); - } - } - -#if defined(__GNUC__) - FAIL_IF(sljit_emit_ijump(compiler, SLJIT_FAST_CALL, SLJIT_IMM, - ((op | 0x2) == SLJIT_DIV_UW ? SLJIT_FUNC_ADDR(__aeabi_uidivmod) : SLJIT_FUNC_ADDR(__aeabi_idivmod)))); -#else -#error "Software divmod functions are needed" -#endif - - if (saved_reg_count > 0) { - if (saved_reg_count >= 3) { - SLJIT_ASSERT(saved_reg_list[2] < 8); - FAIL_IF(push_inst(compiler, LDR | 0x8d0008 | (saved_reg_list[2] << 12) /* ldr rX, [sp, #8] */)); - } - if (saved_reg_count >= 2) { - SLJIT_ASSERT(saved_reg_list[1] < 8); - FAIL_IF(push_inst(compiler, LDR | 0x8d0004 | (saved_reg_list[1] << 12) /* ldr rX, [sp, #4] */)); - } - return push_inst(compiler, (LDR ^ (1 << 24)) | 0x8d0000 | (sljit_uw)(saved_reg_count >= 3 ? 16 : 8) - | (saved_reg_list[0] << 12) /* ldr rX, [sp], #8/16 */); - } - return SLJIT_SUCCESS; - case SLJIT_ENDBR: - case SLJIT_SKIP_FRAMES_BEFORE_RETURN: - return SLJIT_SUCCESS; - } - - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src, sljit_sw srcw) -{ - CHECK_ERROR(); - CHECK(check_sljit_emit_op1(compiler, op, dst, dstw, src, srcw)); - ADJUST_LOCAL_OFFSET(dst, dstw); - ADJUST_LOCAL_OFFSET(src, srcw); - - switch (GET_OPCODE(op)) { - case SLJIT_MOV: - case SLJIT_MOV_U32: - case SLJIT_MOV_S32: - case SLJIT_MOV32: - case SLJIT_MOV_P: - return emit_op(compiler, SLJIT_MOV, ALLOW_ANY_IMM, dst, dstw, TMP_REG1, 0, src, srcw); - - case SLJIT_MOV_U8: - return emit_op(compiler, SLJIT_MOV_U8, ALLOW_ANY_IMM | BYTE_SIZE, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_u8)srcw : srcw); - - case SLJIT_MOV_S8: - return emit_op(compiler, SLJIT_MOV_S8, ALLOW_ANY_IMM | SIGNED | BYTE_SIZE, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_s8)srcw : srcw); - - case SLJIT_MOV_U16: - return emit_op(compiler, SLJIT_MOV_U16, ALLOW_ANY_IMM | HALF_SIZE, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_u16)srcw : srcw); - - case SLJIT_MOV_S16: - return emit_op(compiler, SLJIT_MOV_S16, ALLOW_ANY_IMM | SIGNED | HALF_SIZE, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_s16)srcw : srcw); - - case SLJIT_NOT: - return emit_op(compiler, op, ALLOW_ANY_IMM, dst, dstw, TMP_REG1, 0, src, srcw); - - case SLJIT_CLZ: - case SLJIT_CTZ: - return emit_op(compiler, op, 0, dst, dstw, TMP_REG1, 0, src, srcw); - } - - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - CHECK_ERROR(); - CHECK(check_sljit_emit_op2(compiler, op, 0, dst, dstw, src1, src1w, src2, src2w)); - ADJUST_LOCAL_OFFSET(dst, dstw); - ADJUST_LOCAL_OFFSET(src1, src1w); - ADJUST_LOCAL_OFFSET(src2, src2w); - - switch (GET_OPCODE(op)) { - case SLJIT_ADD: - case SLJIT_ADDC: - case SLJIT_SUB: - case SLJIT_SUBC: - return emit_op(compiler, op, ALLOW_IMM | ALLOW_NEG_IMM, dst, dstw, src1, src1w, src2, src2w); - - case SLJIT_OR: - case SLJIT_XOR: - return emit_op(compiler, op, ALLOW_IMM, dst, dstw, src1, src1w, src2, src2w); - - case SLJIT_MUL: - return emit_op(compiler, op, 0, dst, dstw, src1, src1w, src2, src2w); - - case SLJIT_AND: - return emit_op(compiler, op, ALLOW_ANY_IMM, dst, dstw, src1, src1w, src2, src2w); - - case SLJIT_SHL: - case SLJIT_MSHL: - case SLJIT_LSHR: - case SLJIT_MLSHR: - case SLJIT_ASHR: - case SLJIT_MASHR: - case SLJIT_ROTL: - case SLJIT_ROTR: - if (src2 & SLJIT_IMM) { - compiler->shift_imm = src2w & 0x1f; - return emit_op(compiler, op, 0, dst, dstw, TMP_REG1, 0, src1, src1w); - } else { - compiler->shift_imm = 0x20; - return emit_op(compiler, op, 0, dst, dstw, src1, src1w, src2, src2w); - } - } - - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - 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, TMP_REG2, 0, src1, src1w, src2, src2w); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 src_dst, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - sljit_s32 is_left; - - CHECK_ERROR(); - CHECK(check_sljit_emit_shift_into(compiler, op, src_dst, src1, src1w, src2, src2w)); - - op = GET_OPCODE(op); - is_left = (op == SLJIT_SHL || op == SLJIT_MSHL); - - if (src_dst == src1) { - SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_op2(compiler, is_left ? SLJIT_ROTL : SLJIT_ROTR, src_dst, 0, src_dst, 0, src2, src2w); - } - - ADJUST_LOCAL_OFFSET(src1, src1w); - ADJUST_LOCAL_OFFSET(src2, src2w); - - /* Shift type of ROR is 3. */ - if (src2 & SLJIT_IMM) { - src2w &= 0x1f; - - if (src2w == 0) - return SLJIT_SUCCESS; - } else if (src2 & SLJIT_MEM) { - FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, TMP_REG2, src2, src2w, TMP_REG2)); - src2 = TMP_REG2; - } - - if (src1 & SLJIT_MEM) { - FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, TMP_REG1, src1, src1w, TMP_REG1)); - src1 = TMP_REG1; - } else if (src1 & SLJIT_IMM) { - FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)src1w)); - src1 = TMP_REG1; - } - - if (src2 & SLJIT_IMM) { - FAIL_IF(push_inst(compiler, MOV | RD(src_dst) | RM(src_dst) | ((sljit_uw)(is_left ? 0 : 1) << 5) | ((sljit_uw)src2w << 7))); - src2w = (src2w ^ 0x1f) + 1; - return push_inst(compiler, ORR | RD(src_dst) | RN(src_dst) | RM(src1) | ((sljit_uw)(is_left ? 1 : 0) << 5) | ((sljit_uw)src2w << 7)); - } - - if (op == SLJIT_MSHL || op == SLJIT_MLSHR) { - FAIL_IF(push_inst(compiler, AND | SRC2_IMM | RD(TMP_REG2) | RN(src2) | 0x1f)); - src2 = TMP_REG2; - } - - FAIL_IF(push_inst(compiler, MOV | RD(src_dst) | RM8(src2) | ((sljit_uw)(is_left ? 0 : 1) << 5) | 0x10 | RM(src_dst))); - FAIL_IF(push_inst(compiler, MOV | RD(TMP_REG1) | RM(src1) | ((sljit_uw)(is_left ? 1 : 0) << 5) | (1 << 7))); - FAIL_IF(push_inst(compiler, EOR | SRC2_IMM | RD(TMP_REG2) | RN(src2) | 0x1f)); - return push_inst(compiler, ORR | RD(src_dst) | RN(src_dst) | RM(TMP_REG1) | ((sljit_uw)(is_left ? 1 : 0) << 5) | 0x10 | RM8(TMP_REG2)); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 src, sljit_sw srcw) -{ - CHECK_ERROR(); - CHECK(check_sljit_emit_op_src(compiler, op, src, srcw)); - ADJUST_LOCAL_OFFSET(src, srcw); - - switch (op) { - case SLJIT_FAST_RETURN: - SLJIT_ASSERT(reg_map[TMP_REG2] == 14); - - if (FAST_IS_REG(src)) - FAIL_IF(push_inst(compiler, MOV | RD(TMP_REG2) | RM(src))); - else - FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, TMP_REG2, src, srcw, TMP_REG1)); - - return push_inst(compiler, BX | RM(TMP_REG2)); - case SLJIT_SKIP_FRAMES_BEFORE_FAST_RETURN: - return SLJIT_SUCCESS; - case SLJIT_PREFETCH_L1: - case SLJIT_PREFETCH_L2: - case SLJIT_PREFETCH_L3: - case SLJIT_PREFETCH_ONCE: -#if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) - SLJIT_ASSERT(src & SLJIT_MEM); - return emit_op_mem(compiler, PRELOAD | LOAD_DATA, TMP_PC, src, srcw, TMP_REG1); -#else /* !SLJIT_CONFIG_ARM_V7 */ - return SLJIT_SUCCESS; -#endif /* SLJIT_CONFIG_ARM_V7 */ - } - - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 reg) -{ - CHECK_REG_INDEX(check_sljit_get_register_index(reg)); - return reg_map[reg]; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_float_register_index(sljit_s32 reg) -{ - CHECK_REG_INDEX(check_sljit_get_float_register_index(reg)); - return (freg_map[reg] << 1); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler, - void *instruction, sljit_u32 size) -{ - SLJIT_UNUSED_ARG(size); - CHECK_ERROR(); - CHECK(check_sljit_emit_op_custom(compiler, instruction, size)); - - return push_inst(compiler, *(sljit_uw*)instruction); -} - -/* --------------------------------------------------------------------- */ -/* Floating point operators */ -/* --------------------------------------------------------------------- */ - -#define FPU_LOAD (1 << 20) -#define EMIT_FPU_DATA_TRANSFER(inst, add, base, freg, offs) \ - ((inst) | (sljit_uw)((add) << 23) | RN(base) | VD(freg) | (sljit_uw)(offs)) - -static sljit_s32 emit_fop_mem(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg, sljit_sw argw) -{ - sljit_uw imm; - sljit_uw inst = VSTR_F32 | (flags & (SLJIT_32 | FPU_LOAD)); - - SLJIT_ASSERT(arg & SLJIT_MEM); - 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_uw)argw & 0x3) << 7))); - arg = TMP_REG2; - argw = 0; - } - - /* Fast loads and stores. */ - if (arg) { - if (!(argw & ~0x3fc)) - return push_inst(compiler, EMIT_FPU_DATA_TRANSFER(inst, 1, arg & REG_MASK, reg, argw >> 2)); - if (!(-argw & ~0x3fc)) - return push_inst(compiler, EMIT_FPU_DATA_TRANSFER(inst, 0, arg & REG_MASK, reg, (-argw) >> 2)); - - 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)); - } - 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)); - } - } - - 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))); - } - else - FAIL_IF(load_immediate(compiler, TMP_REG2, (sljit_uw)argw)); - - return push_inst(compiler, EMIT_FPU_DATA_TRANSFER(inst, 1, TMP_REG2, reg, 0)); -} - -static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src, sljit_sw srcw) -{ - op ^= SLJIT_32; - - if (src & SLJIT_MEM) { - FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_32) | FPU_LOAD, TMP_FREG1, src, srcw)); - src = TMP_FREG1; - } - - FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VCVT_S32_F32, op & SLJIT_32, TMP_FREG1, src, 0))); - - if (FAST_IS_REG(dst)) - return push_inst(compiler, VMOV | (1 << 20) | RD(dst) | VN(TMP_FREG1)); - - /* Store the integer value from a VFP register. */ - return emit_fop_mem(compiler, 0, TMP_FREG1, dst, dstw); -} - -static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src, sljit_sw srcw) -{ - sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1; - - op ^= SLJIT_32; - - if (FAST_IS_REG(src)) - FAIL_IF(push_inst(compiler, VMOV | RD(src) | VN(TMP_FREG1))); - else if (src & SLJIT_MEM) { - /* Load the integer value into a VFP register. */ - FAIL_IF(emit_fop_mem(compiler, FPU_LOAD, TMP_FREG1, src, srcw)); - } - else { - FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)srcw)); - FAIL_IF(push_inst(compiler, VMOV | RD(TMP_REG1) | VN(TMP_FREG1))); - } - - FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VCVT_F32_S32, op & SLJIT_32, dst_r, TMP_FREG1, 0))); - - if (dst & SLJIT_MEM) - return emit_fop_mem(compiler, (op & SLJIT_32), TMP_FREG1, dst, dstw); - return SLJIT_SUCCESS; -} - -static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - op ^= SLJIT_32; - - if (src1 & SLJIT_MEM) { - FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_32) | FPU_LOAD, TMP_FREG1, src1, src1w)); - src1 = TMP_FREG1; - } - - if (src2 & SLJIT_MEM) { - FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_32) | FPU_LOAD, TMP_FREG2, src2, src2w)); - src2 = TMP_FREG2; - } - - FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VCMP_F32, op & SLJIT_32, src1, src2, 0))); - return push_inst(compiler, VMRS); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src, sljit_sw srcw) -{ - sljit_s32 dst_r; - - CHECK_ERROR(); - - SLJIT_COMPILE_ASSERT((SLJIT_32 == 0x100), float_transfer_bit_error); - SELECT_FOP1_OPERATION_WITH_CHECKS(compiler, op, dst, dstw, src, srcw); - - dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1; - - if (GET_OPCODE(op) != SLJIT_CONV_F64_FROM_F32) - op ^= SLJIT_32; - - if (src & SLJIT_MEM) { - FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_32) | FPU_LOAD, dst_r, src, srcw)); - src = dst_r; - } - - switch (GET_OPCODE(op)) { - case SLJIT_MOV_F64: - if (src != dst_r) { - if (dst_r != TMP_FREG1) - FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VMOV_F32, op & SLJIT_32, dst_r, src, 0))); - else - dst_r = src; - } - break; - case SLJIT_NEG_F64: - FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VNEG_F32, op & SLJIT_32, dst_r, src, 0))); - break; - case SLJIT_ABS_F64: - FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VABS_F32, op & SLJIT_32, dst_r, src, 0))); - break; - case SLJIT_CONV_F64_FROM_F32: - FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VCVT_F64_F32, op & SLJIT_32, dst_r, src, 0))); - op ^= SLJIT_32; - break; - } - - if (dst & SLJIT_MEM) - return emit_fop_mem(compiler, (op & SLJIT_32), dst_r, dst, dstw); - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - sljit_s32 dst_r; - - CHECK_ERROR(); - CHECK(check_sljit_emit_fop2(compiler, op, dst, dstw, src1, src1w, src2, src2w)); - ADJUST_LOCAL_OFFSET(dst, dstw); - ADJUST_LOCAL_OFFSET(src1, src1w); - ADJUST_LOCAL_OFFSET(src2, src2w); - - op ^= SLJIT_32; - - dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1; - - if (src2 & SLJIT_MEM) { - FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_32) | FPU_LOAD, TMP_FREG2, src2, src2w)); - src2 = TMP_FREG2; - } - - if (src1 & SLJIT_MEM) { - FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_32) | FPU_LOAD, TMP_FREG1, src1, src1w)); - src1 = TMP_FREG1; - } - - switch (GET_OPCODE(op)) { - case SLJIT_ADD_F64: - FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VADD_F32, op & SLJIT_32, dst_r, src2, src1))); - break; - - case SLJIT_SUB_F64: - FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VSUB_F32, op & SLJIT_32, dst_r, src2, src1))); - break; - - case SLJIT_MUL_F64: - FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VMUL_F32, op & SLJIT_32, dst_r, src2, src1))); - break; - - case SLJIT_DIV_F64: - FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VDIV_F32, op & SLJIT_32, dst_r, src2, src1))); - break; - } - - if (dst_r == TMP_FREG1) - FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_32), TMP_FREG1, dst, dstw)); - - return SLJIT_SUCCESS; -} - -#undef EMIT_FPU_DATA_TRANSFER - -/* --------------------------------------------------------------------- */ -/* Other instructions */ -/* --------------------------------------------------------------------- */ - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw) -{ - CHECK_ERROR(); - CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw)); - ADJUST_LOCAL_OFFSET(dst, dstw); - - SLJIT_ASSERT(reg_map[TMP_REG2] == 14); - - if (FAST_IS_REG(dst)) - return push_inst(compiler, MOV | RD(dst) | RM(TMP_REG2)); - - /* Memory. */ - return emit_op_mem(compiler, WORD_SIZE, TMP_REG2, dst, dstw, TMP_REG1); -} - -/* --------------------------------------------------------------------- */ -/* Conditional instructions */ -/* --------------------------------------------------------------------- */ - -static sljit_uw get_cc(struct sljit_compiler *compiler, sljit_s32 type) -{ - switch (type) { - case SLJIT_EQUAL: - case SLJIT_F_EQUAL: - case SLJIT_ORDERED_EQUAL: - case SLJIT_UNORDERED_OR_EQUAL: /* Not supported. */ - return 0x00000000; - - case SLJIT_NOT_EQUAL: - case SLJIT_F_NOT_EQUAL: - case SLJIT_UNORDERED_OR_NOT_EQUAL: - case SLJIT_ORDERED_NOT_EQUAL: /* Not supported. */ - return 0x10000000; - - case SLJIT_CARRY: - if (compiler->status_flags_state & SLJIT_CURRENT_FLAGS_ADD) - return 0x20000000; - /* fallthrough */ - - case SLJIT_LESS: - return 0x30000000; - - case SLJIT_NOT_CARRY: - if (compiler->status_flags_state & SLJIT_CURRENT_FLAGS_ADD) - return 0x30000000; - /* fallthrough */ - - case SLJIT_GREATER_EQUAL: - return 0x20000000; - - case SLJIT_GREATER: - case SLJIT_UNORDERED_OR_GREATER: - return 0x80000000; - - case SLJIT_LESS_EQUAL: - case SLJIT_F_LESS_EQUAL: - case SLJIT_ORDERED_LESS_EQUAL: - return 0x90000000; - - case SLJIT_SIG_LESS: - case SLJIT_UNORDERED_OR_LESS: - return 0xb0000000; - - case SLJIT_SIG_GREATER_EQUAL: - case SLJIT_F_GREATER_EQUAL: - case SLJIT_ORDERED_GREATER_EQUAL: - return 0xa0000000; - - case SLJIT_SIG_GREATER: - case SLJIT_F_GREATER: - case SLJIT_ORDERED_GREATER: - return 0xc0000000; - - case SLJIT_SIG_LESS_EQUAL: - case SLJIT_UNORDERED_OR_LESS_EQUAL: - return 0xd0000000; - - case SLJIT_OVERFLOW: - if (!(compiler->status_flags_state & (SLJIT_CURRENT_FLAGS_ADD | SLJIT_CURRENT_FLAGS_SUB))) - return 0x10000000; - /* fallthrough */ - - case SLJIT_UNORDERED: - return 0x60000000; - - case SLJIT_NOT_OVERFLOW: - if (!(compiler->status_flags_state & (SLJIT_CURRENT_FLAGS_ADD | SLJIT_CURRENT_FLAGS_SUB))) - return 0x00000000; - /* fallthrough */ - - case SLJIT_ORDERED: - return 0x70000000; - - case SLJIT_F_LESS: - case SLJIT_ORDERED_LESS: - return 0x40000000; - - case SLJIT_UNORDERED_OR_GREATER_EQUAL: - return 0x50000000; - - default: - SLJIT_ASSERT(type >= SLJIT_JUMP && type <= SLJIT_CALL_REG_ARG); - return 0xe0000000; - } -} - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compiler *compiler) -{ - struct sljit_label *label; - - CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_label(compiler)); - - if (compiler->last_label && compiler->last_label->size == compiler->size) - return compiler->last_label; - - label = (struct sljit_label*)ensure_abuf(compiler, sizeof(struct sljit_label)); - PTR_FAIL_IF(!label); - set_label(label, compiler); - return label; -} - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type) -{ - struct sljit_jump *jump; - - CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_jump(compiler, type)); - - jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump)); - PTR_FAIL_IF(!jump); - set_jump(jump, compiler, type & SLJIT_REWRITABLE_JUMP); - type &= 0xff; - - SLJIT_ASSERT(reg_map[TMP_REG1] != 14); - -#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) - if (type >= SLJIT_FAST_CALL) - PTR_FAIL_IF(prepare_blx(compiler)); - 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; - compiler->patches++; - } - - if (type >= SLJIT_FAST_CALL) { - jump->flags |= IS_BL; - PTR_FAIL_IF(emit_blx(compiler)); - } - - if (!(jump->flags & SLJIT_REWRITABLE_JUMP)) - jump->addr = compiler->size; -#else - 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; -#endif - return jump; -} - -#ifdef __SOFTFP__ - -static sljit_s32 softfloat_call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_types, sljit_s32 *src, sljit_u32 *extra_space) -{ - sljit_u32 is_tail_call = *extra_space & SLJIT_CALL_RETURN; - sljit_u32 offset = 0; - sljit_u32 word_arg_offset = 0; - sljit_u32 src_offset = 4 * sizeof(sljit_sw); - sljit_u32 float_arg_count = 0; - sljit_s32 types = 0; - sljit_u8 offsets[4]; - sljit_u8 *offset_ptr = offsets; - - if (src && FAST_IS_REG(*src)) - src_offset = (sljit_uw)reg_map[*src] * sizeof(sljit_sw); - - arg_types >>= SLJIT_ARG_SHIFT; - - while (arg_types) { - types = (types << SLJIT_ARG_SHIFT) | (arg_types & SLJIT_ARG_MASK); - - switch (arg_types & SLJIT_ARG_MASK) { - case SLJIT_ARG_TYPE_F64: - if (offset & 0x7) - offset += sizeof(sljit_sw); - *offset_ptr++ = (sljit_u8)offset; - offset += sizeof(sljit_f64); - float_arg_count++; - break; - case SLJIT_ARG_TYPE_F32: - *offset_ptr++ = (sljit_u8)offset; - offset += sizeof(sljit_f32); - float_arg_count++; - break; - default: - *offset_ptr++ = (sljit_u8)offset; - offset += sizeof(sljit_sw); - word_arg_offset += sizeof(sljit_sw); - break; - } - - arg_types >>= SLJIT_ARG_SHIFT; - } - - if (offset > 4 * sizeof(sljit_sw) && (!is_tail_call || offset > compiler->args_size)) { - /* Keep lr register on the stack. */ - if (is_tail_call) - offset += sizeof(sljit_sw); - - offset = ((offset - 4 * sizeof(sljit_sw)) + 0x7) & ~(sljit_uw)0x7; - - *extra_space = offset; - - if (is_tail_call) - FAIL_IF(emit_stack_frame_release(compiler, (sljit_s32)offset)); - else - FAIL_IF(push_inst(compiler, SUB | RD(SLJIT_SP) | RN(SLJIT_SP) | SRC2_IMM | offset)); - } else { - if (is_tail_call) - FAIL_IF(emit_stack_frame_release(compiler, -1)); - *extra_space = 0; - } - - /* Process arguments in reversed direction. */ - while (types) { - switch (types & SLJIT_ARG_MASK) { - case SLJIT_ARG_TYPE_F64: - float_arg_count--; - offset = *(--offset_ptr); - - SLJIT_ASSERT((offset & 0x7) == 0); - - if (offset < 4 * sizeof(sljit_sw)) { - if (src_offset == offset || src_offset == offset + sizeof(sljit_sw)) { - FAIL_IF(push_inst(compiler, MOV | RD(TMP_REG1) | (src_offset >> 2))); - *src = TMP_REG1; - } - FAIL_IF(push_inst(compiler, VMOV2 | 0x100000 | (offset << 10) | ((offset + sizeof(sljit_sw)) << 14) | float_arg_count)); - } else - FAIL_IF(push_inst(compiler, VSTR_F32 | 0x800100 | RN(SLJIT_SP) - | (float_arg_count << 12) | ((offset - 4 * sizeof(sljit_sw)) >> 2))); - break; - case SLJIT_ARG_TYPE_F32: - float_arg_count--; - offset = *(--offset_ptr); - - if (offset < 4 * sizeof(sljit_sw)) { - if (src_offset == offset) { - FAIL_IF(push_inst(compiler, MOV | RD(TMP_REG1) | (src_offset >> 2))); - *src = TMP_REG1; - } - FAIL_IF(push_inst(compiler, VMOV | 0x100000 | (float_arg_count << 16) | (offset << 10))); - } else - FAIL_IF(push_inst(compiler, VSTR_F32 | 0x800000 | RN(SLJIT_SP) - | (float_arg_count << 12) | ((offset - 4 * sizeof(sljit_sw)) >> 2))); - break; - default: - word_arg_offset -= sizeof(sljit_sw); - offset = *(--offset_ptr); - - SLJIT_ASSERT(offset >= word_arg_offset); - - if (offset != word_arg_offset) { - if (offset < 4 * sizeof(sljit_sw)) { - if (src_offset == offset) { - FAIL_IF(push_inst(compiler, MOV | RD(TMP_REG1) | (src_offset >> 2))); - *src = TMP_REG1; - } - else if (src_offset == word_arg_offset) { - *src = (sljit_s32)(SLJIT_R0 + (offset >> 2)); - src_offset = offset; - } - FAIL_IF(push_inst(compiler, MOV | (offset << 10) | (word_arg_offset >> 2))); - } else - FAIL_IF(push_inst(compiler, STR | 0x800000 | RN(SLJIT_SP) | (word_arg_offset << 10) | (offset - 4 * sizeof(sljit_sw)))); - } - break; - } - - types >>= SLJIT_ARG_SHIFT; - } - - return SLJIT_SUCCESS; -} - -static sljit_s32 softfloat_post_call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_types) -{ - if ((arg_types & SLJIT_ARG_MASK) == SLJIT_ARG_TYPE_F64) - FAIL_IF(push_inst(compiler, VMOV2 | (1 << 16) | (0 << 12) | 0)); - if ((arg_types & SLJIT_ARG_MASK) == SLJIT_ARG_TYPE_F32) - FAIL_IF(push_inst(compiler, VMOV | (0 << 16) | (0 << 12))); - - return SLJIT_SUCCESS; -} - -#else /* !__SOFTFP__ */ - -static sljit_s32 hardfloat_call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_types) -{ - sljit_u32 offset = SLJIT_FR0; - sljit_u32 new_offset = SLJIT_FR0; - sljit_u32 f32_offset = 0; - - /* Remove return value. */ - arg_types >>= SLJIT_ARG_SHIFT; - - while (arg_types) { - switch (arg_types & SLJIT_ARG_MASK) { - case SLJIT_ARG_TYPE_F64: - if (offset != new_offset) - FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VMOV_F32, - SLJIT_32, new_offset, offset, 0))); - - new_offset++; - offset++; - break; - case SLJIT_ARG_TYPE_F32: - if (f32_offset != 0) { - FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VMOV_F32, - 0x400000, f32_offset, offset, 0))); - f32_offset = 0; - } else { - if (offset != new_offset) - FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VMOV_F32, - 0, new_offset, offset, 0))); - f32_offset = new_offset; - new_offset++; - } - offset++; - break; - } - arg_types >>= SLJIT_ARG_SHIFT; - } - - return SLJIT_SUCCESS; -} - -#endif /* __SOFTFP__ */ - -#undef EMIT_FPU_OPERATION - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_call(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 arg_types) -{ -#ifdef __SOFTFP__ - struct sljit_jump *jump; - sljit_u32 extra_space = (sljit_u32)type; -#endif - - CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_call(compiler, type, arg_types)); - -#ifdef __SOFTFP__ - if ((type & 0xff) != SLJIT_CALL_REG_ARG) { - PTR_FAIL_IF(softfloat_call_with_args(compiler, arg_types, NULL, &extra_space)); - SLJIT_ASSERT((extra_space & 0x7) == 0); - - if ((type & SLJIT_CALL_RETURN) && extra_space == 0) - type = SLJIT_JUMP | (type & SLJIT_REWRITABLE_JUMP); - - SLJIT_SKIP_CHECKS(compiler); - jump = sljit_emit_jump(compiler, type); - PTR_FAIL_IF(jump == NULL); - - if (extra_space > 0) { - if (type & SLJIT_CALL_RETURN) - PTR_FAIL_IF(push_inst(compiler, EMIT_DATA_TRANSFER(WORD_SIZE | LOAD_DATA, 1, - TMP_REG2, SLJIT_SP, extra_space - sizeof(sljit_sw)))); - - PTR_FAIL_IF(push_inst(compiler, ADD | RD(SLJIT_SP) | RN(SLJIT_SP) | SRC2_IMM | extra_space)); - - if (type & SLJIT_CALL_RETURN) { - PTR_FAIL_IF(push_inst(compiler, BX | RM(TMP_REG2))); - return jump; - } - } - - SLJIT_ASSERT(!(type & SLJIT_CALL_RETURN)); - PTR_FAIL_IF(softfloat_post_call_with_args(compiler, arg_types)); - return jump; - } -#endif /* __SOFTFP__ */ - - if (type & SLJIT_CALL_RETURN) { - PTR_FAIL_IF(emit_stack_frame_release(compiler, -1)); - type = SLJIT_JUMP | (type & SLJIT_REWRITABLE_JUMP); - } - -#ifndef __SOFTFP__ - if ((type & 0xff) != SLJIT_CALL_REG_ARG) - PTR_FAIL_IF(hardfloat_call_with_args(compiler, arg_types)); -#endif /* !__SOFTFP__ */ - - SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_jump(compiler, type); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 src, sljit_sw srcw) -{ - struct sljit_jump *jump; - - CHECK_ERROR(); - CHECK(check_sljit_emit_ijump(compiler, type, src, srcw)); - ADJUST_LOCAL_OFFSET(src, srcw); - - SLJIT_ASSERT(reg_map[TMP_REG1] != 14); - - if (!(src & SLJIT_IMM)) { - if (FAST_IS_REG(src)) { - SLJIT_ASSERT(reg_map[src] != 14); - return push_inst(compiler, (type <= SLJIT_JUMP ? BX : BLX) | RM(src)); - } - - SLJIT_ASSERT(src & SLJIT_MEM); - FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, TMP_REG1, src, srcw, TMP_REG1)); - return push_inst(compiler, (type <= SLJIT_JUMP ? BX : BLX) | RM(TMP_REG1)); - } - - /* These jumps are converted to jump/call instructions when possible. */ - jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump)); - FAIL_IF(!jump); - set_jump(jump, compiler, JUMP_ADDR | ((type >= SLJIT_FAST_CALL) ? IS_BL : 0)); - jump->u.target = (sljit_uw)srcw; - -#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) - if (type >= SLJIT_FAST_CALL) - FAIL_IF(prepare_blx(compiler)); - 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) - FAIL_IF(emit_blx(compiler)); -#else - FAIL_IF(emit_imm(compiler, TMP_REG1, 0)); - FAIL_IF(push_inst(compiler, (type <= SLJIT_JUMP ? BX : BLX) | RM(TMP_REG1))); -#endif - jump->addr = compiler->size; - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 arg_types, - sljit_s32 src, sljit_sw srcw) -{ -#ifdef __SOFTFP__ - sljit_u32 extra_space = (sljit_u32)type; -#endif - - CHECK_ERROR(); - CHECK(check_sljit_emit_icall(compiler, type, arg_types, src, srcw)); - - if (src & SLJIT_MEM) { - FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, TMP_REG1, src, srcw, TMP_REG1)); - src = TMP_REG1; - } - - if ((type & SLJIT_CALL_RETURN) && (src >= SLJIT_FIRST_SAVED_REG && src <= (SLJIT_S0 - SLJIT_KEPT_SAVEDS_COUNT(compiler->options)))) { - FAIL_IF(push_inst(compiler, MOV | RD(TMP_REG1) | RM(src))); - src = TMP_REG1; - } - -#ifdef __SOFTFP__ - if ((type & 0xff) != SLJIT_CALL_REG_ARG) { - FAIL_IF(softfloat_call_with_args(compiler, arg_types, &src, &extra_space)); - SLJIT_ASSERT((extra_space & 0x7) == 0); - - if ((type & SLJIT_CALL_RETURN) && extra_space == 0) - type = SLJIT_JUMP; - - SLJIT_SKIP_CHECKS(compiler); - FAIL_IF(sljit_emit_ijump(compiler, type, src, srcw)); - - if (extra_space > 0) { - if (type & SLJIT_CALL_RETURN) - FAIL_IF(push_inst(compiler, EMIT_DATA_TRANSFER(WORD_SIZE | LOAD_DATA, 1, - TMP_REG2, SLJIT_SP, extra_space - sizeof(sljit_sw)))); - - FAIL_IF(push_inst(compiler, ADD | RD(SLJIT_SP) | RN(SLJIT_SP) | SRC2_IMM | extra_space)); - - if (type & SLJIT_CALL_RETURN) - return push_inst(compiler, BX | RM(TMP_REG2)); - } - - SLJIT_ASSERT(!(type & SLJIT_CALL_RETURN)); - return softfloat_post_call_with_args(compiler, arg_types); - } -#endif /* __SOFTFP__ */ - - if (type & SLJIT_CALL_RETURN) { - FAIL_IF(emit_stack_frame_release(compiler, -1)); - type = SLJIT_JUMP; - } - -#ifndef __SOFTFP__ - if ((type & 0xff) != SLJIT_CALL_REG_ARG) - FAIL_IF(hardfloat_call_with_args(compiler, arg_types)); -#endif /* !__SOFTFP__ */ - - SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_ijump(compiler, type, src, srcw); -} - -#ifdef __SOFTFP__ - -static SLJIT_INLINE sljit_s32 emit_fmov_before_return(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw) -{ - if (compiler->options & SLJIT_ENTER_REG_ARG) { - if (src == SLJIT_FR0) - return SLJIT_SUCCESS; - - SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_fop1(compiler, op, SLJIT_RETURN_FREG, 0, src, srcw); - } - - if (FAST_IS_REG(src)) { - if (op & SLJIT_32) - return push_inst(compiler, VMOV | (1 << 20) | RD(SLJIT_R0) | VN(src)); - return push_inst(compiler, VMOV2 | (1 << 20) | RD(SLJIT_R0) | RN(SLJIT_R1) | VM(src)); - } - - SLJIT_SKIP_CHECKS(compiler); - - if (op & SLJIT_32) - return sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_R0, 0, src, srcw); - return sljit_emit_mem(compiler, SLJIT_MOV, SLJIT_REG_PAIR(SLJIT_R0, SLJIT_R1), src, srcw); -} - -#endif /* __SOFTFP__ */ - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 type) -{ - sljit_s32 dst_reg, flags = GET_ALL_FLAGS(op); - sljit_uw cc, ins; - - CHECK_ERROR(); - CHECK(check_sljit_emit_op_flags(compiler, op, dst, dstw, type)); - ADJUST_LOCAL_OFFSET(dst, dstw); - - op = GET_OPCODE(op); - cc = get_cc(compiler, type); - dst_reg = FAST_IS_REG(dst) ? dst : TMP_REG1; - - if (op < SLJIT_ADD) { - FAIL_IF(push_inst(compiler, MOV | RD(dst_reg) | SRC2_IMM | 0)); - FAIL_IF(push_inst(compiler, ((MOV | RD(dst_reg) | SRC2_IMM | 1) & ~COND_MASK) | cc)); - if (dst & SLJIT_MEM) - return emit_op_mem(compiler, WORD_SIZE, TMP_REG1, dst, dstw, TMP_REG2); - return SLJIT_SUCCESS; - } - - ins = (op == SLJIT_AND ? AND : (op == SLJIT_OR ? ORR : EOR)); - - if (dst & SLJIT_MEM) - FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, TMP_REG1, dst, dstw, TMP_REG2)); - - FAIL_IF(push_inst(compiler, ((ins | RD(dst_reg) | RN(dst_reg) | SRC2_IMM | 1) & ~COND_MASK) | cc)); - - if (op == SLJIT_AND) - FAIL_IF(push_inst(compiler, ((ins | RD(dst_reg) | RN(dst_reg) | SRC2_IMM | 0) & ~COND_MASK) | (cc ^ 0x10000000))); - - if (dst & SLJIT_MEM) - FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG1, dst, dstw, TMP_REG2)); - - if (flags & SLJIT_SET_Z) - return push_inst(compiler, MOV | SET_FLAGS | RD(TMP_REG2) | RM(dst_reg)); - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 dst_reg, - sljit_s32 src, sljit_sw srcw) -{ - sljit_uw cc, tmp; - - CHECK_ERROR(); - CHECK(check_sljit_emit_cmov(compiler, type, dst_reg, src, srcw)); - - cc = get_cc(compiler, type & ~SLJIT_32); - - if (SLJIT_UNLIKELY(src & SLJIT_IMM)) { - tmp = get_imm((sljit_uw)srcw); - if (tmp) - return push_inst(compiler, ((MOV | RD(dst_reg) | tmp) & ~COND_MASK) | cc); - - tmp = get_imm(~(sljit_uw)srcw); - if (tmp) - return push_inst(compiler, ((MVN | RD(dst_reg) | tmp) & ~COND_MASK) | cc); - -#if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) - tmp = (sljit_uw)srcw; - FAIL_IF(push_inst(compiler, (MOVW & ~COND_MASK) | cc | RD(dst_reg) | ((tmp << 4) & 0xf0000) | (tmp & 0xfff))); - if (tmp <= 0xffff) - return SLJIT_SUCCESS; - return push_inst(compiler, (MOVT & ~COND_MASK) | cc | RD(dst_reg) | ((tmp >> 12) & 0xf0000) | ((tmp >> 16) & 0xfff)); -#else - FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)srcw)); - src = TMP_REG1; -#endif - } - - return push_inst(compiler, ((MOV | RD(dst_reg) | RM(src)) & ~COND_MASK) | cc); -} - -static sljit_s32 update_mem_addr(struct sljit_compiler *compiler, sljit_s32 *mem, sljit_sw *memw, sljit_s32 max_offset) -{ - sljit_s32 arg = *mem; - sljit_sw argw = *memw; - sljit_uw imm, tmp; -#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) - sljit_sw mask = max_offset >= 0xf00 ? 0xfff : 0xff; - sljit_sw sign = max_offset >= 0xf00 ? 0x1000 : 0x100; -#else /* !SLJIT_CONFIG_ARM_V5 */ - sljit_sw mask = 0xfff; - sljit_sw sign = 0x1000; - - SLJIT_ASSERT(max_offset >= 0xf00); -#endif /* SLJIT_CONFIG_ARM_V5 */ - - *mem = TMP_REG1; - - if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) { - *memw = 0; - return push_inst(compiler, ADD | RD(TMP_REG1) | RN(arg & REG_MASK) | RM(OFFS_REG(arg)) | ((sljit_uw)(argw & 0x3) << 7)); - } - - arg &= REG_MASK; - - if (arg) { - if (argw <= max_offset && argw >= -mask) { - *mem = arg; - return SLJIT_SUCCESS; - } - - if (argw >= 0) { - tmp = (sljit_uw)(argw & (sign | mask)); - tmp = (sljit_uw)((argw + ((tmp <= (sljit_uw)max_offset || tmp == (sljit_uw)sign) ? 0 : sign)) & ~mask); - imm = get_imm(tmp); - - if (imm) { - *memw = argw - (sljit_sw)tmp; - SLJIT_ASSERT(*memw >= -mask && *memw <= max_offset); - - return push_inst(compiler, ADD | RD(TMP_REG1) | RN(arg) | imm); - } - } else { - tmp = (sljit_uw)(-argw & (sign | mask)); - tmp = (sljit_uw)((-argw + ((tmp <= (sljit_uw)((sign << 1) - max_offset - 1)) ? 0 : sign)) & ~mask); - imm = get_imm(tmp); - - if (imm) { - *memw = argw + (sljit_sw)tmp; - SLJIT_ASSERT(*memw >= -mask && *memw <= max_offset); - - return push_inst(compiler, SUB | RD(TMP_REG1) | RN(arg) | imm); - } - } - } - - tmp = (sljit_uw)(argw & (sign | mask)); - tmp = (sljit_uw)((argw + ((tmp <= (sljit_uw)max_offset || tmp == (sljit_uw)sign) ? 0 : sign)) & ~mask); - *memw = argw - (sljit_sw)tmp; - - FAIL_IF(load_immediate(compiler, TMP_REG1, tmp)); - - if (arg == 0) - return SLJIT_SUCCESS; - - return push_inst(compiler, ADD | RD(TMP_REG1) | RN(TMP_REG1) | RM(arg)); -} - -#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) - -static sljit_s32 sljit_emit_mem_unaligned(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 reg, - sljit_s32 mem, sljit_sw memw) -{ - sljit_s32 flags, steps, tmp_reg; - sljit_uw add, shift; - - switch (type & 0xff) { - case SLJIT_MOV_U8: - case SLJIT_MOV_S8: - flags = BYTE_SIZE; - if (!(type & SLJIT_MEM_STORE)) - flags |= LOAD_DATA; - if ((type & 0xff) == SLJIT_MOV_S8) - flags |= SIGNED; - - return emit_op_mem(compiler, flags, reg, mem, memw, TMP_REG1); - - case SLJIT_MOV_U16: - FAIL_IF(update_mem_addr(compiler, &mem, &memw, 0xfff - 1)); - flags = BYTE_SIZE; - steps = 1; - break; - - case SLJIT_MOV_S16: - FAIL_IF(update_mem_addr(compiler, &mem, &memw, 0xff - 1)); - flags = BYTE_SIZE | SIGNED; - steps = 1; - break; - - default: - if (type & SLJIT_MEM_UNALIGNED_32) { - flags = WORD_SIZE; - if (!(type & SLJIT_MEM_STORE)) - flags |= LOAD_DATA; - - return emit_op_mem(compiler, flags, reg, mem, memw, TMP_REG1); - } - - if (!(type & SLJIT_MEM_UNALIGNED_16)) { - FAIL_IF(update_mem_addr(compiler, &mem, &memw, 0xfff - 3)); - flags = BYTE_SIZE; - steps = 3; - break; - } - - FAIL_IF(update_mem_addr(compiler, &mem, &memw, 0xff - 2)); - - add = 1; - if (memw < 0) { - add = 0; - memw = -memw; - } - - tmp_reg = reg; - - if (type & SLJIT_MEM_STORE) { - FAIL_IF(push_inst(compiler, EMIT_DATA_TRANSFER(HALF_SIZE, add, reg, mem, TYPE2_TRANSFER_IMM(memw)))); - FAIL_IF(push_inst(compiler, MOV | RD(TMP_REG2) | RM(reg) | (16 << 7) | (2 << 4))); - } else { - if (reg == mem) { - SLJIT_ASSERT(reg != TMP_REG1); - tmp_reg = TMP_REG1; - } - - FAIL_IF(push_inst(compiler, EMIT_DATA_TRANSFER(HALF_SIZE | LOAD_DATA, add, tmp_reg, mem, TYPE2_TRANSFER_IMM(memw)))); - } - - if (!add) { - memw -= 2; - if (memw <= 0) { - memw = -memw; - add = 1; - } - } else - memw += 2; - - if (type & SLJIT_MEM_STORE) - return push_inst(compiler, EMIT_DATA_TRANSFER(HALF_SIZE, add, TMP_REG2, mem, TYPE2_TRANSFER_IMM(memw))); - - FAIL_IF(push_inst(compiler, EMIT_DATA_TRANSFER(HALF_SIZE | LOAD_DATA, add, TMP_REG2, mem, TYPE2_TRANSFER_IMM(memw)))); - return push_inst(compiler, ORR | RD(reg) | RN(tmp_reg) | RM(TMP_REG2) | (16 << 7)); - } - - SLJIT_ASSERT(steps > 0); - - add = 1; - if (memw < 0) { - add = 0; - memw = -memw; - } - - if (type & SLJIT_MEM_STORE) { - FAIL_IF(push_inst(compiler, EMIT_DATA_TRANSFER(BYTE_SIZE, add, reg, mem, memw))); - FAIL_IF(push_inst(compiler, MOV | RD(TMP_REG2) | RM(reg) | (8 << 7) | (2 << 4))); - - while (1) { - if (!add) { - memw -= 1; - if (memw == 0) - add = 1; - } else - memw += 1; - - FAIL_IF(push_inst(compiler, EMIT_DATA_TRANSFER(BYTE_SIZE, add, TMP_REG2, mem, memw))); - - if (--steps == 0) - return SLJIT_SUCCESS; - - FAIL_IF(push_inst(compiler, MOV | RD(TMP_REG2) | RM(TMP_REG2) | (8 << 7) | (2 << 4))); - } - } - - tmp_reg = reg; - - if (reg == mem) { - SLJIT_ASSERT(reg != TMP_REG1); - tmp_reg = TMP_REG1; - } - - shift = 8; - FAIL_IF(push_inst(compiler, EMIT_DATA_TRANSFER(BYTE_SIZE | LOAD_DATA, add, tmp_reg, mem, memw))); - - do { - if (!add) { - memw -= 1; - if (memw == 0) - add = 1; - } else - memw += 1; - - if (steps > 1) { - FAIL_IF(push_inst(compiler, EMIT_DATA_TRANSFER(BYTE_SIZE | LOAD_DATA, add, TMP_REG2, mem, memw))); - FAIL_IF(push_inst(compiler, ORR | RD(tmp_reg) | RN(tmp_reg) | RM(TMP_REG2) | (shift << 7))); - shift += 8; - } - } while (--steps != 0); - - flags |= LOAD_DATA; - - if (flags & SIGNED) - FAIL_IF(push_inst(compiler, EMIT_DATA_TRANSFER(flags, add, TMP_REG2, mem, TYPE2_TRANSFER_IMM(memw)))); - else - FAIL_IF(push_inst(compiler, EMIT_DATA_TRANSFER(flags, add, TMP_REG2, mem, memw))); - - return push_inst(compiler, ORR | RD(reg) | RN(tmp_reg) | RM(TMP_REG2) | (shift << 7)); -} - -#endif /* SLJIT_CONFIG_ARM_V5 */ - -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) -{ - sljit_s32 flags; - - CHECK_ERROR(); - CHECK(check_sljit_emit_mem(compiler, type, reg, mem, memw)); - - if (!(reg & REG_PAIR_MASK)) { -#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) - ADJUST_LOCAL_OFFSET(mem, memw); -#endif /* SLJIT_CONFIG_ARM_V5 */ - - return sljit_emit_mem_unaligned(compiler, type, reg, mem, memw); - } - - ADJUST_LOCAL_OFFSET(mem, memw); - -#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) - if (type & (SLJIT_MEM_UNALIGNED | SLJIT_MEM_UNALIGNED_16)) { - FAIL_IF(update_mem_addr(compiler, &mem, &memw, (type & SLJIT_MEM_UNALIGNED_16) ? 0xfff - 6 : 0xfff - 7)); - - if (!(type & SLJIT_MEM_STORE) && REG_PAIR_FIRST(reg) == (mem & REG_MASK)) { - FAIL_IF(sljit_emit_mem_unaligned(compiler, type, REG_PAIR_SECOND(reg), SLJIT_MEM1(mem), memw + SSIZE_OF(sw))); - return sljit_emit_mem_unaligned(compiler, type, REG_PAIR_FIRST(reg), SLJIT_MEM1(mem), memw); - } - - FAIL_IF(sljit_emit_mem_unaligned(compiler, type, REG_PAIR_FIRST(reg), SLJIT_MEM1(mem), memw)); - return sljit_emit_mem_unaligned(compiler, type, REG_PAIR_SECOND(reg), SLJIT_MEM1(mem), memw + SSIZE_OF(sw)); - } -#endif /* SLJIT_CONFIG_ARM_V5 */ - - FAIL_IF(update_mem_addr(compiler, &mem, &memw, 0xfff - 4)); - - flags = WORD_SIZE; - - if (!(type & SLJIT_MEM_STORE)) { - if (REG_PAIR_FIRST(reg) == (mem & REG_MASK)) { - FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, REG_PAIR_SECOND(reg), SLJIT_MEM1(mem), memw + SSIZE_OF(sw), TMP_REG1)); - return emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, REG_PAIR_FIRST(reg), SLJIT_MEM1(mem), memw, TMP_REG1); - } - - flags = WORD_SIZE | LOAD_DATA; - } - - FAIL_IF(emit_op_mem(compiler, flags, REG_PAIR_FIRST(reg), SLJIT_MEM1(mem), memw, TMP_REG1)); - return emit_op_mem(compiler, flags, REG_PAIR_SECOND(reg), SLJIT_MEM1(mem), memw + SSIZE_OF(sw), TMP_REG1); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem_update(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 reg, - sljit_s32 mem, sljit_sw memw) -{ - sljit_s32 flags; - sljit_uw is_type1_transfer, inst; - - CHECK_ERROR(); - CHECK(check_sljit_emit_mem_update(compiler, type, reg, mem, memw)); - - is_type1_transfer = 1; - - switch (type & 0xff) { - case SLJIT_MOV: - case SLJIT_MOV_U32: - case SLJIT_MOV_S32: - case SLJIT_MOV32: - case SLJIT_MOV_P: - flags = WORD_SIZE; - break; - case SLJIT_MOV_U8: - flags = BYTE_SIZE; - break; - case SLJIT_MOV_S8: - if (!(type & SLJIT_MEM_STORE)) - is_type1_transfer = 0; - flags = BYTE_SIZE | SIGNED; - break; - case SLJIT_MOV_U16: - is_type1_transfer = 0; - flags = HALF_SIZE; - break; - case SLJIT_MOV_S16: - is_type1_transfer = 0; - flags = HALF_SIZE | SIGNED; - break; - default: - SLJIT_UNREACHABLE(); - flags = WORD_SIZE; - break; - } - - if (!(type & SLJIT_MEM_STORE)) - flags |= LOAD_DATA; - - SLJIT_ASSERT(is_type1_transfer == !!IS_TYPE1_TRANSFER(flags)); - - if (SLJIT_UNLIKELY(mem & OFFS_REG_MASK)) { - if (!is_type1_transfer && memw != 0) - return SLJIT_ERR_UNSUPPORTED; - } else { - if (is_type1_transfer) { - if (memw > 4095 || memw < -4095) - return SLJIT_ERR_UNSUPPORTED; - } else if (memw > 255 || memw < -255) - return SLJIT_ERR_UNSUPPORTED; - } - - if (type & SLJIT_MEM_SUPP) - return SLJIT_SUCCESS; - - if (SLJIT_UNLIKELY(mem & OFFS_REG_MASK)) { - memw &= 0x3; - - inst = EMIT_DATA_TRANSFER(flags, 1, reg, mem & REG_MASK, RM(OFFS_REG(mem)) | ((sljit_uw)memw << 7)); - - if (is_type1_transfer) - inst |= (1 << 25); - - if (type & SLJIT_MEM_POST) - inst ^= (1 << 24); - else - inst |= (1 << 21); - - return push_inst(compiler, inst); - } - - inst = EMIT_DATA_TRANSFER(flags, 0, reg, mem & REG_MASK, 0); - - if (type & SLJIT_MEM_POST) - inst ^= (1 << 24); - else - inst |= (1 << 21); - - if (is_type1_transfer) { - if (memw >= 0) - inst |= (1 << 23); - else - memw = -memw; - - return push_inst(compiler, inst | (sljit_uw)memw); - } - - if (memw >= 0) - inst |= (1 << 23); - else - memw = -memw; - - return push_inst(compiler, inst | TYPE2_TRANSFER_IMM((sljit_uw)memw)); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fmem(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 freg, - sljit_s32 mem, sljit_sw memw) -{ -#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) - sljit_s32 max_offset; - sljit_s32 dst; -#endif /* SLJIT_CONFIG_ARM_V5 */ - - CHECK_ERROR(); - CHECK(check_sljit_emit_fmem(compiler, type, freg, mem, memw)); - - if (type & SLJIT_MEM_UNALIGNED_32) - return emit_fop_mem(compiler, ((type ^ SLJIT_32) & SLJIT_32) | ((type & SLJIT_MEM_STORE) ? 0 : FPU_LOAD), freg, mem, memw); - -#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) - if (type & SLJIT_MEM_STORE) { - FAIL_IF(push_inst(compiler, VMOV | (1 << 20) | VN(freg) | RD(TMP_REG2))); - - if (type & SLJIT_32) - return sljit_emit_mem_unaligned(compiler, SLJIT_MOV | SLJIT_MEM_STORE | (type & SLJIT_MEM_UNALIGNED_16), TMP_REG2, mem, memw); - - max_offset = 0xfff - 7; - if (type & SLJIT_MEM_UNALIGNED_16) - max_offset++; - - FAIL_IF(update_mem_addr(compiler, &mem, &memw, max_offset)); - mem |= SLJIT_MEM; - - FAIL_IF(sljit_emit_mem_unaligned(compiler, SLJIT_MOV | SLJIT_MEM_STORE | (type & SLJIT_MEM_UNALIGNED_16), TMP_REG2, mem, memw)); - - FAIL_IF(push_inst(compiler, VMOV | (1 << 20) | VN(freg) | 0x80 | RD(TMP_REG2))); - return sljit_emit_mem_unaligned(compiler, SLJIT_MOV | SLJIT_MEM_STORE | (type & SLJIT_MEM_UNALIGNED_16), TMP_REG2, mem, memw + 4); - } - - max_offset = (type & SLJIT_32) ? 0xfff - 3 : 0xfff - 7; - if (type & SLJIT_MEM_UNALIGNED_16) - max_offset++; - - FAIL_IF(update_mem_addr(compiler, &mem, &memw, max_offset)); - - dst = TMP_REG1; - - /* Stack offset adjustment is not needed because dst - is not stored on the stack when mem is SLJIT_SP. */ - - if (mem == TMP_REG1) { - dst = SLJIT_R3; - - if (compiler->scratches >= 4) - FAIL_IF(push_inst(compiler, STR | (1 << 21) | RN(SLJIT_SP) | RD(SLJIT_R3) | 8)); - } - - mem |= SLJIT_MEM; - - FAIL_IF(sljit_emit_mem_unaligned(compiler, SLJIT_MOV | (type & SLJIT_MEM_UNALIGNED_16), dst, mem, memw)); - FAIL_IF(push_inst(compiler, VMOV | VN(freg) | RD(dst))); - - if (!(type & SLJIT_32)) { - FAIL_IF(sljit_emit_mem_unaligned(compiler, SLJIT_MOV | (type & SLJIT_MEM_UNALIGNED_16), dst, mem, memw + 4)); - FAIL_IF(push_inst(compiler, VMOV | VN(freg) | 0x80 | RD(dst))); - } - - if (dst == SLJIT_R3 && compiler->scratches >= 4) - FAIL_IF(push_inst(compiler, (LDR ^ (0x1 << 24)) | (0x1 << 23) | RN(SLJIT_SP) | RD(SLJIT_R3) | 8)); - return SLJIT_SUCCESS; -#else /* !SLJIT_CONFIG_ARM_V5 */ - if (type & SLJIT_MEM_STORE) { - FAIL_IF(push_inst(compiler, VMOV | (1 << 20) | VN(freg) | RD(TMP_REG2))); - - if (type & SLJIT_32) - return emit_op_mem(compiler, WORD_SIZE, TMP_REG2, mem, memw, TMP_REG1); - - FAIL_IF(update_mem_addr(compiler, &mem, &memw, 0xfff - 4)); - mem |= SLJIT_MEM; - - FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG2, mem, memw, TMP_REG1)); - FAIL_IF(push_inst(compiler, VMOV | (1 << 20) | VN(freg) | 0x80 | RD(TMP_REG2))); - return emit_op_mem(compiler, WORD_SIZE, TMP_REG2, mem, memw + 4, TMP_REG1); - } - - if (type & SLJIT_32) { - FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, TMP_REG2, mem, memw, TMP_REG1)); - return push_inst(compiler, VMOV | VN(freg) | RD(TMP_REG2)); - } - - FAIL_IF(update_mem_addr(compiler, &mem, &memw, 0xfff - 4)); - mem |= SLJIT_MEM; - - FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, TMP_REG2, mem, memw, TMP_REG1)); - FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, TMP_REG1, mem, memw + 4, TMP_REG1)); - return push_inst(compiler, VMOV2 | VM(freg) | RD(TMP_REG2) | RN(TMP_REG1)); -#endif /* SLJIT_CONFIG_ARM_V5 */ -} - -#undef FPU_LOAD - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value) -{ - struct sljit_const *const_; - sljit_s32 dst_r; - - CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_const(compiler, dst, dstw, init_value)); - ADJUST_LOCAL_OFFSET(dst, dstw); - - dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2; - -#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) - PTR_FAIL_IF(push_inst_with_unique_literal(compiler, - EMIT_DATA_TRANSFER(WORD_SIZE | LOAD_DATA, 1, dst_r, TMP_PC, 0), (sljit_uw)init_value)); - compiler->patches++; -#else - PTR_FAIL_IF(emit_imm(compiler, dst_r, init_value)); -#endif - - 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) -{ - struct sljit_put_label *put_label; - sljit_s32 dst_r; - - CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_put_label(compiler, dst, dstw)); - ADJUST_LOCAL_OFFSET(dst, dstw); - - dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2; - -#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) - PTR_FAIL_IF(push_inst_with_unique_literal(compiler, EMIT_DATA_TRANSFER(WORD_SIZE | LOAD_DATA, 1, dst_r, TMP_PC, 0), 0)); - compiler->patches++; -#else - PTR_FAIL_IF(emit_imm(compiler, dst_r, 0)); -#endif - - 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); - - if (dst & SLJIT_MEM) - PTR_FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG2, dst, dstw, TMP_REG1)); - return put_label; -} - -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); -} - -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); -} diff --git a/modules/regex/pcre2/src/sljit/sljitNativeARM_64.c b/modules/regex/pcre2/src/sljit/sljitNativeARM_64.c deleted file mode 100644 index 89f747e..0000000 --- a/modules/regex/pcre2/src/sljit/sljitNativeARM_64.c +++ /dev/null @@ -1,2417 +0,0 @@ -/* - * 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 const char* sljit_get_platform_name(void) -{ - return "ARM-64" SLJIT_CPUINFO; -} - -/* Length of an instruction word */ -typedef sljit_u32 sljit_ins; - -#define TMP_ZERO (0) - -#define TMP_REG1 (SLJIT_NUMBER_OF_REGISTERS + 2) -#define TMP_REG2 (SLJIT_NUMBER_OF_REGISTERS + 3) -#define TMP_LR (SLJIT_NUMBER_OF_REGISTERS + 4) -#define TMP_FP (SLJIT_NUMBER_OF_REGISTERS + 5) - -#define TMP_FREG1 (SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1) -#define TMP_FREG2 (SLJIT_NUMBER_OF_FLOAT_REGISTERS + 2) - -/* r18 - platform register, currently not used */ -static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 8] = { - 31, 0, 1, 2, 3, 4, 5, 6, 7, 11, 12, 13, 14, 15, 16, 17, 8, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 31, 9, 10, 30, 29 -}; - -static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 3] = { - 0, 0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 15, 14, 13, 12, 11, 10, 9, 8, 30, 31 -}; - -#define W_OP ((sljit_ins)1 << 31) -#define RD(rd) ((sljit_ins)reg_map[rd]) -#define RT(rt) ((sljit_ins)reg_map[rt]) -#define RN(rn) ((sljit_ins)reg_map[rn] << 5) -#define RT2(rt2) ((sljit_ins)reg_map[rt2] << 10) -#define RM(rm) ((sljit_ins)reg_map[rm] << 16) -#define VD(vd) ((sljit_ins)freg_map[vd]) -#define VT(vt) ((sljit_ins)freg_map[vt]) -#define VT2(vt) ((sljit_ins)freg_map[vt] << 10) -#define VN(vn) ((sljit_ins)freg_map[vn] << 5) -#define VM(vm) ((sljit_ins)freg_map[vm] << 16) - -/* --------------------------------------------------------------------- */ -/* Instrucion forms */ -/* --------------------------------------------------------------------- */ - -#define ADC 0x9a000000 -#define ADD 0x8b000000 -#define ADDE 0x8b200000 -#define ADDI 0x91000000 -#define AND 0x8a000000 -#define ANDI 0x92000000 -#define ASRV 0x9ac02800 -#define B 0x14000000 -#define B_CC 0x54000000 -#define BL 0x94000000 -#define BLR 0xd63f0000 -#define BR 0xd61f0000 -#define BRK 0xd4200000 -#define CBZ 0xb4000000 -#define CLZ 0xdac01000 -#define CSEL 0x9a800000 -#define CSINC 0x9a800400 -#define EOR 0xca000000 -#define EORI 0xd2000000 -#define EXTR 0x93c00000 -#define FABS 0x1e60c000 -#define FADD 0x1e602800 -#define FCMP 0x1e602000 -#define FCVT 0x1e224000 -#define FCVTZS 0x9e780000 -#define FDIV 0x1e601800 -#define FMOV 0x1e604000 -#define FMUL 0x1e600800 -#define FNEG 0x1e614000 -#define FSUB 0x1e603800 -#define LDRI 0xf9400000 -#define LDRI_F64 0xfd400000 -#define LDRI_POST 0xf8400400 -#define LDP 0xa9400000 -#define LDP_F64 0x6d400000 -#define LDP_POST 0xa8c00000 -#define LDR_PRE 0xf8400c00 -#define LSLV 0x9ac02000 -#define LSRV 0x9ac02400 -#define MADD 0x9b000000 -#define MOVK 0xf2800000 -#define MOVN 0x92800000 -#define MOVZ 0xd2800000 -#define NOP 0xd503201f -#define ORN 0xaa200000 -#define ORR 0xaa000000 -#define ORRI 0xb2000000 -#define RBIT 0xdac00000 -#define RET 0xd65f0000 -#define RORV 0x9ac02c00 -#define SBC 0xda000000 -#define SBFM 0x93000000 -#define SCVTF 0x9e620000 -#define SDIV 0x9ac00c00 -#define SMADDL 0x9b200000 -#define SMULH 0x9b403c00 -#define STP 0xa9000000 -#define STP_F64 0x6d000000 -#define STP_PRE 0xa9800000 -#define STRB 0x38206800 -#define STRBI 0x39000000 -#define STRI 0xf9000000 -#define STRI_F64 0xfd000000 -#define STR_FI 0x3d000000 -#define STR_FR 0x3c206800 -#define STUR_FI 0x3c000000 -#define STURBI 0x38000000 -#define SUB 0xcb000000 -#define SUBI 0xd1000000 -#define SUBS 0xeb000000 -#define UBFM 0xd3000000 -#define UDIV 0x9ac00800 -#define UMULH 0x9bc03c00 - -static sljit_s32 push_inst(struct sljit_compiler *compiler, sljit_ins ins) -{ - sljit_ins *ptr = (sljit_ins*)ensure_buf(compiler, sizeof(sljit_ins)); - FAIL_IF(!ptr); - *ptr = ins; - compiler->size++; - return SLJIT_SUCCESS; -} - -static SLJIT_INLINE sljit_s32 emit_imm64_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_uw imm) -{ - FAIL_IF(push_inst(compiler, MOVZ | RD(dst) | ((sljit_ins)(imm & 0xffff) << 5))); - FAIL_IF(push_inst(compiler, MOVK | RD(dst) | (((sljit_ins)(imm >> 16) & 0xffff) << 5) | (1 << 21))); - FAIL_IF(push_inst(compiler, MOVK | RD(dst) | (((sljit_ins)(imm >> 32) & 0xffff) << 5) | (2 << 21))); - 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) -{ - sljit_sw diff; - sljit_uw target_addr; - - if (jump->flags & SLJIT_REWRITABLE_JUMP) { - jump->flags |= PATCH_ABS64; - return 0; - } - - if (jump->flags & JUMP_ADDR) - target_addr = jump->u.target; - else { - SLJIT_ASSERT(jump->flags & JUMP_LABEL); - 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; - - 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); - jump->flags |= PATCH_COND; - return 5; - } - diff -= SSIZE_OF(ins); - } - - if (diff <= 0x7ffffff && diff >= -0x8000000) { - jump->flags |= PATCH_B; - return 4; - } - - if (target_addr < 0x100000000l) { - if (jump->flags & IS_COND) - code_ptr[-5] -= (2 << 5); - code_ptr[-2] = code_ptr[0]; - return 2; - } - - if (target_addr < 0x1000000000000l) { - if (jump->flags & IS_COND) - code_ptr[-5] -= (1 << 5); - jump->flags |= PATCH_ABS48; - code_ptr[-1] = code_ptr[0]; - return 1; - } - - jump->flags |= PATCH_ABS64; - return 0; -} - -static SLJIT_INLINE sljit_sw put_label_get_length(struct sljit_put_label *put_label, sljit_uw max_label) -{ - if (max_label < 0x100000000l) { - put_label->flags = 0; - return 2; - } - - if (max_label < 0x1000000000000l) { - put_label->flags = 1; - return 1; - } - - put_label->flags = 2; - return 0; -} - -SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler) -{ - struct sljit_memory_fragment *buf; - sljit_ins *code; - sljit_ins *code_ptr; - sljit_ins *buf_ptr; - sljit_ins *buf_end; - sljit_uw word_count; - sljit_uw next_addr; - 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); - 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; - - 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) { - 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); - label->size = (sljit_uw)(code_ptr - code); - label = label->next; - } - 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) { - const_->addr = (sljit_uw)code_ptr; - const_ = const_->next; - } - 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); - } - code_ptr++; - word_count++; - } while (buf_ptr < buf_end); - - buf = buf->next; - } while (buf); - - if (label && label->size == word_count) { - label->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); - 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); - 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); - - code = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(code, executable_offset); - code_ptr = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset); - - SLJIT_CACHE_FLUSH(code, code_ptr); - SLJIT_UPDATE_WX_FLAGS(code, code_ptr, 1); - return code; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type) -{ - switch (feature_type) { - case SLJIT_HAS_FPU: -#ifdef SLJIT_IS_FPU_AVAILABLE - return SLJIT_IS_FPU_AVAILABLE; -#else - /* Available by default. */ - return 1; -#endif - - case SLJIT_HAS_CLZ: - case SLJIT_HAS_CTZ: - case SLJIT_HAS_ROT: - case SLJIT_HAS_CMOV: - case SLJIT_HAS_PREFETCH: - return 1; - - default: - return 0; - } -} - -/* --------------------------------------------------------------------- */ -/* Core code generator functions. */ -/* --------------------------------------------------------------------- */ - -#define COUNT_TRAILING_ZERO(value, result) \ - result = 0; \ - if (!(value & 0xffffffff)) { \ - result += 32; \ - value >>= 32; \ - } \ - if (!(value & 0xffff)) { \ - result += 16; \ - value >>= 16; \ - } \ - if (!(value & 0xff)) { \ - result += 8; \ - value >>= 8; \ - } \ - if (!(value & 0xf)) { \ - result += 4; \ - value >>= 4; \ - } \ - if (!(value & 0x3)) { \ - result += 2; \ - value >>= 2; \ - } \ - if (!(value & 0x1)) { \ - result += 1; \ - value >>= 1; \ - } - -#define LOGICAL_IMM_CHECK (sljit_ins)0x100 - -static sljit_ins logical_imm(sljit_sw imm, sljit_u32 len) -{ - sljit_s32 negated; - sljit_u32 ones, right; - sljit_uw mask, uimm; - sljit_ins ins; - - if (len & LOGICAL_IMM_CHECK) { - len &= ~LOGICAL_IMM_CHECK; - if (len == 32 && (imm == 0 || imm == -1)) - return 0; - if (len == 16 && ((sljit_s32)imm == 0 || (sljit_s32)imm == -1)) - return 0; - } - - SLJIT_ASSERT((len == 32 && imm != 0 && imm != -1) - || (len == 16 && (sljit_s32)imm != 0 && (sljit_s32)imm != -1)); - - uimm = (sljit_uw)imm; - while (1) { - if (len <= 0) { - SLJIT_UNREACHABLE(); - return 0; - } - - mask = ((sljit_uw)1 << len) - 1; - if ((uimm & mask) != ((uimm >> len) & mask)) - break; - len >>= 1; - } - - len <<= 1; - - negated = 0; - if (uimm & 0x1) { - negated = 1; - uimm = ~uimm; - } - - if (len < 64) - uimm &= ((sljit_uw)1 << len) - 1; - - /* Unsigned right shift. */ - COUNT_TRAILING_ZERO(uimm, right); - - /* Signed shift. We also know that the highest bit is set. */ - imm = (sljit_sw)~uimm; - SLJIT_ASSERT(imm < 0); - - COUNT_TRAILING_ZERO(imm, ones); - - if (~imm) - return 0; - - if (len == 64) - ins = 1 << 22; - else - ins = (0x3f - ((len << 1) - 1)) << 10; - - if (negated) - return ins | ((len - ones - 1) << 10) | ((len - ones - right) << 16); - - return ins | ((ones - 1) << 10) | ((len - right) << 16); -} - -#undef COUNT_TRAILING_ZERO - -static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw simm) -{ - sljit_uw imm = (sljit_uw)simm; - sljit_u32 i, zeros, ones, first; - sljit_ins bitmask; - - /* Handling simple immediates first. */ - if (imm <= 0xffff) - return push_inst(compiler, MOVZ | RD(dst) | ((sljit_ins)imm << 5)); - - if (simm < 0 && simm >= -0x10000) - return push_inst(compiler, MOVN | RD(dst) | (((sljit_ins)~imm & 0xffff) << 5)); - - if (imm <= 0xffffffffl) { - if ((imm & 0xffff) == 0) - return push_inst(compiler, MOVZ | RD(dst) | ((sljit_ins)(imm >> 16) << 5) | (1 << 21)); - if ((imm & 0xffff0000l) == 0xffff0000) - return push_inst(compiler, (MOVN ^ W_OP) | RD(dst) | (((sljit_ins)~imm & 0xffff) << 5)); - if ((imm & 0xffff) == 0xffff) - return push_inst(compiler, (MOVN ^ W_OP) | RD(dst) | (((sljit_ins)~imm & 0xffff0000u) >> (16 - 5)) | (1 << 21)); - - bitmask = logical_imm(simm, 16); - if (bitmask != 0) - return push_inst(compiler, (ORRI ^ W_OP) | RD(dst) | RN(TMP_ZERO) | bitmask); - - FAIL_IF(push_inst(compiler, MOVZ | RD(dst) | (((sljit_ins)imm & 0xffff) << 5))); - return push_inst(compiler, MOVK | RD(dst) | (((sljit_ins)imm & 0xffff0000u) >> (16 - 5)) | (1 << 21)); - } - - bitmask = logical_imm(simm, 32); - if (bitmask != 0) - return push_inst(compiler, ORRI | RD(dst) | RN(TMP_ZERO) | bitmask); - - if (simm < 0 && simm >= -0x100000000l) { - if ((imm & 0xffff) == 0xffff) - return push_inst(compiler, MOVN | RD(dst) | (((sljit_ins)~imm & 0xffff0000u) >> (16 - 5)) | (1 << 21)); - - FAIL_IF(push_inst(compiler, MOVN | RD(dst) | (((sljit_ins)~imm & 0xffff) << 5))); - return push_inst(compiler, MOVK | RD(dst) | (((sljit_ins)imm & 0xffff0000u) >> (16 - 5)) | (1 << 21)); - } - - /* A large amount of number can be constructed from ORR and MOVx, but computing them is costly. */ - - zeros = 0; - ones = 0; - for (i = 4; i > 0; i--) { - if ((simm & 0xffff) == 0) - zeros++; - if ((simm & 0xffff) == 0xffff) - ones++; - simm >>= 16; - } - - simm = (sljit_sw)imm; - first = 1; - if (ones > zeros) { - simm = ~simm; - for (i = 0; i < 4; i++) { - if (!(simm & 0xffff)) { - simm >>= 16; - continue; - } - if (first) { - first = 0; - FAIL_IF(push_inst(compiler, MOVN | RD(dst) | (((sljit_ins)simm & 0xffff) << 5) | (i << 21))); - } - else - FAIL_IF(push_inst(compiler, MOVK | RD(dst) | (((sljit_ins)~simm & 0xffff) << 5) | (i << 21))); - simm >>= 16; - } - return SLJIT_SUCCESS; - } - - for (i = 0; i < 4; i++) { - if (!(simm & 0xffff)) { - simm >>= 16; - continue; - } - if (first) { - first = 0; - FAIL_IF(push_inst(compiler, MOVZ | RD(dst) | (((sljit_ins)simm & 0xffff) << 5) | (i << 21))); - } - else - FAIL_IF(push_inst(compiler, MOVK | RD(dst) | (((sljit_ins)simm & 0xffff) << 5) | (i << 21))); - simm >>= 16; - } - return SLJIT_SUCCESS; -} - -#define ARG1_IMM 0x0010000 -#define ARG2_IMM 0x0020000 -#define INT_OP 0x0040000 -#define SET_FLAGS 0x0080000 -#define UNUSED_RETURN 0x0100000 - -#define CHECK_FLAGS(flag_bits) \ - if (flags & SET_FLAGS) { \ - inv_bits |= flag_bits; \ - if (flags & UNUSED_RETURN) \ - dst = TMP_ZERO; \ - } - -static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 dst, sljit_sw arg1, sljit_sw arg2) -{ - /* dst must be register, TMP_REG1 - arg1 must be register, TMP_REG1, imm - arg2 must be register, TMP_REG2, imm */ - sljit_ins inv_bits = (flags & INT_OP) ? W_OP : 0; - sljit_ins inst_bits; - sljit_s32 op = (flags & 0xffff); - sljit_s32 reg; - sljit_sw imm, nimm; - - if (SLJIT_UNLIKELY((flags & (ARG1_IMM | ARG2_IMM)) == (ARG1_IMM | ARG2_IMM))) { - /* Both are immediates. */ - flags &= ~ARG1_IMM; - if (arg1 == 0 && op != SLJIT_ADD && op != SLJIT_SUB) - arg1 = TMP_ZERO; - else { - FAIL_IF(load_immediate(compiler, TMP_REG1, arg1)); - arg1 = TMP_REG1; - } - } - - if (flags & (ARG1_IMM | ARG2_IMM)) { - reg = (sljit_s32)((flags & ARG2_IMM) ? arg1 : arg2); - imm = (flags & ARG2_IMM) ? arg2 : arg1; - - switch (op) { - case SLJIT_MUL: - case SLJIT_CLZ: - case SLJIT_CTZ: - case SLJIT_ADDC: - case SLJIT_SUBC: - /* No form with immediate operand (except imm 0, which - is represented by a ZERO register). */ - break; - case SLJIT_MOV: - SLJIT_ASSERT(!(flags & SET_FLAGS) && (flags & ARG2_IMM) && arg1 == TMP_REG1); - return load_immediate(compiler, dst, imm); - case SLJIT_NOT: - SLJIT_ASSERT(flags & ARG2_IMM); - FAIL_IF(load_immediate(compiler, dst, (flags & INT_OP) ? (~imm & 0xffffffff) : ~imm)); - goto set_flags; - case SLJIT_SUB: - compiler->status_flags_state = SLJIT_CURRENT_FLAGS_SUB; - if (flags & ARG1_IMM) - break; - imm = -imm; - /* Fall through. */ - case SLJIT_ADD: - if (op != SLJIT_SUB) - compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD; - - if (imm == 0) { - CHECK_FLAGS(1 << 29); - return push_inst(compiler, ((op == SLJIT_ADD ? ADDI : SUBI) ^ inv_bits) | RD(dst) | RN(reg)); - } - if (imm > 0 && imm <= 0xfff) { - CHECK_FLAGS(1 << 29); - return push_inst(compiler, (ADDI ^ inv_bits) | RD(dst) | RN(reg) | ((sljit_ins)imm << 10)); - } - nimm = -imm; - if (nimm > 0 && nimm <= 0xfff) { - CHECK_FLAGS(1 << 29); - return push_inst(compiler, (SUBI ^ inv_bits) | RD(dst) | RN(reg) | ((sljit_ins)nimm << 10)); - } - if (imm > 0 && imm <= 0xffffff && !(imm & 0xfff)) { - CHECK_FLAGS(1 << 29); - return push_inst(compiler, (ADDI ^ inv_bits) | RD(dst) | RN(reg) | (((sljit_ins)imm >> 12) << 10) | (1 << 22)); - } - if (nimm > 0 && nimm <= 0xffffff && !(nimm & 0xfff)) { - CHECK_FLAGS(1 << 29); - return push_inst(compiler, (SUBI ^ inv_bits) | RD(dst) | RN(reg) | (((sljit_ins)nimm >> 12) << 10) | (1 << 22)); - } - if (imm > 0 && imm <= 0xffffff && !(flags & SET_FLAGS)) { - FAIL_IF(push_inst(compiler, (ADDI ^ inv_bits) | RD(dst) | RN(reg) | (((sljit_ins)imm >> 12) << 10) | (1 << 22))); - return push_inst(compiler, (ADDI ^ inv_bits) | RD(dst) | RN(dst) | (((sljit_ins)imm & 0xfff) << 10)); - } - if (nimm > 0 && nimm <= 0xffffff && !(flags & SET_FLAGS)) { - FAIL_IF(push_inst(compiler, (SUBI ^ inv_bits) | RD(dst) | RN(reg) | (((sljit_ins)nimm >> 12) << 10) | (1 << 22))); - return push_inst(compiler, (SUBI ^ inv_bits) | RD(dst) | RN(dst) | (((sljit_ins)nimm & 0xfff) << 10)); - } - break; - case SLJIT_AND: - inst_bits = logical_imm(imm, LOGICAL_IMM_CHECK | ((flags & INT_OP) ? 16 : 32)); - if (!inst_bits) - break; - CHECK_FLAGS(3 << 29); - return push_inst(compiler, (ANDI ^ inv_bits) | RD(dst) | RN(reg) | inst_bits); - case SLJIT_OR: - case SLJIT_XOR: - inst_bits = logical_imm(imm, LOGICAL_IMM_CHECK | ((flags & INT_OP) ? 16 : 32)); - if (!inst_bits) - break; - if (op == SLJIT_OR) - inst_bits |= ORRI; - else - inst_bits |= EORI; - FAIL_IF(push_inst(compiler, (inst_bits ^ inv_bits) | RD(dst) | RN(reg))); - goto set_flags; - case SLJIT_SHL: - case SLJIT_MSHL: - if (flags & ARG1_IMM) - break; - - if (flags & INT_OP) { - imm &= 0x1f; - inst_bits = (((sljit_ins)-imm & 0x1f) << 16) | ((31 - (sljit_ins)imm) << 10); - } else { - imm &= 0x3f; - inst_bits = ((sljit_ins)1 << 22) | (((sljit_ins)-imm & 0x3f) << 16) | ((63 - (sljit_ins)imm) << 10); - } - - FAIL_IF(push_inst(compiler, (UBFM ^ inv_bits) | RD(dst) | RN(arg1) | inst_bits)); - goto set_flags; - case SLJIT_LSHR: - case SLJIT_MLSHR: - case SLJIT_ASHR: - case SLJIT_MASHR: - if (flags & ARG1_IMM) - break; - - if (op >= SLJIT_ASHR) - inv_bits |= 1 << 30; - - if (flags & INT_OP) { - imm &= 0x1f; - inst_bits = ((sljit_ins)imm << 16) | (31 << 10); - } else { - imm &= 0x3f; - inst_bits = ((sljit_ins)1 << 22) | ((sljit_ins)imm << 16) | (63 << 10); - } - - FAIL_IF(push_inst(compiler, (UBFM ^ inv_bits) | RD(dst) | RN(arg1) | inst_bits)); - goto set_flags; - case SLJIT_ROTL: - case SLJIT_ROTR: - if (flags & ARG1_IMM) - break; - - if (op == SLJIT_ROTL) - imm = -imm; - - imm &= (flags & INT_OP) ? 0x1f : 0x3f; - return push_inst(compiler, (EXTR ^ (inv_bits | (inv_bits >> 9))) | RD(dst) | RN(arg1) | RM(arg1) | ((sljit_ins)imm << 10)); - default: - SLJIT_UNREACHABLE(); - break; - } - - if (flags & ARG2_IMM) { - if (arg2 == 0) - arg2 = TMP_ZERO; - else { - FAIL_IF(load_immediate(compiler, TMP_REG2, arg2)); - arg2 = TMP_REG2; - } - } - else { - if (arg1 == 0) - arg1 = TMP_ZERO; - else { - FAIL_IF(load_immediate(compiler, TMP_REG1, arg1)); - arg1 = TMP_REG1; - } - } - } - - /* Both arguments are registers. */ - switch (op) { - case SLJIT_MOV: - case SLJIT_MOV_P: - SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG1); - if (dst == arg2) - return SLJIT_SUCCESS; - return push_inst(compiler, ORR | RD(dst) | RN(TMP_ZERO) | RM(arg2)); - case SLJIT_MOV_U8: - SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG1); - return push_inst(compiler, (UBFM ^ W_OP) | RD(dst) | RN(arg2) | (7 << 10)); - case SLJIT_MOV_S8: - SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG1); - if (!(flags & INT_OP)) - inv_bits |= 1 << 22; - return push_inst(compiler, (SBFM ^ inv_bits) | RD(dst) | RN(arg2) | (7 << 10)); - case SLJIT_MOV_U16: - SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG1); - return push_inst(compiler, (UBFM ^ W_OP) | RD(dst) | RN(arg2) | (15 << 10)); - case SLJIT_MOV_S16: - SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG1); - if (!(flags & INT_OP)) - inv_bits |= 1 << 22; - return push_inst(compiler, (SBFM ^ inv_bits) | RD(dst) | RN(arg2) | (15 << 10)); - case SLJIT_MOV32: - SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG1); - if (dst == arg2) - return SLJIT_SUCCESS; - /* fallthrough */ - case SLJIT_MOV_U32: - SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG1); - return push_inst(compiler, (ORR ^ W_OP) | RD(dst) | RN(TMP_ZERO) | RM(arg2)); - case SLJIT_MOV_S32: - SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG1); - return push_inst(compiler, SBFM | (1 << 22) | RD(dst) | RN(arg2) | (31 << 10)); - case SLJIT_NOT: - SLJIT_ASSERT(arg1 == TMP_REG1); - FAIL_IF(push_inst(compiler, (ORN ^ inv_bits) | RD(dst) | RN(TMP_ZERO) | RM(arg2))); - break; /* Set flags. */ - case SLJIT_CLZ: - SLJIT_ASSERT(arg1 == TMP_REG1); - return push_inst(compiler, (CLZ ^ inv_bits) | RD(dst) | RN(arg2)); - case SLJIT_CTZ: - SLJIT_ASSERT(arg1 == TMP_REG1); - FAIL_IF(push_inst(compiler, (RBIT ^ inv_bits) | RD(dst) | RN(arg2))); - return push_inst(compiler, (CLZ ^ inv_bits) | RD(dst) | RN(dst)); - case SLJIT_ADD: - compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD; - CHECK_FLAGS(1 << 29); - return push_inst(compiler, (ADD ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2)); - case SLJIT_ADDC: - compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD; - CHECK_FLAGS(1 << 29); - return push_inst(compiler, (ADC ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2)); - case SLJIT_SUB: - compiler->status_flags_state = SLJIT_CURRENT_FLAGS_SUB; - CHECK_FLAGS(1 << 29); - return push_inst(compiler, (SUB ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2)); - case SLJIT_SUBC: - compiler->status_flags_state = SLJIT_CURRENT_FLAGS_SUB; - CHECK_FLAGS(1 << 29); - return push_inst(compiler, (SBC ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2)); - case SLJIT_MUL: - compiler->status_flags_state = 0; - if (!(flags & SET_FLAGS)) - return push_inst(compiler, (MADD ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2) | RT2(TMP_ZERO)); - if (flags & INT_OP) { - FAIL_IF(push_inst(compiler, SMADDL | RD(dst) | RN(arg1) | RM(arg2) | (31 << 10))); - FAIL_IF(push_inst(compiler, ADD | RD(TMP_LR) | RN(TMP_ZERO) | RM(dst) | (2 << 22) | (31 << 10))); - return push_inst(compiler, SUBS | RD(TMP_ZERO) | RN(TMP_LR) | RM(dst) | (2 << 22) | (63 << 10)); - } - FAIL_IF(push_inst(compiler, SMULH | RD(TMP_LR) | RN(arg1) | RM(arg2))); - FAIL_IF(push_inst(compiler, MADD | RD(dst) | RN(arg1) | RM(arg2) | RT2(TMP_ZERO))); - return push_inst(compiler, SUBS | RD(TMP_ZERO) | RN(TMP_LR) | RM(dst) | (2 << 22) | (63 << 10)); - case SLJIT_AND: - CHECK_FLAGS(3 << 29); - return push_inst(compiler, (AND ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2)); - case SLJIT_OR: - FAIL_IF(push_inst(compiler, (ORR ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2))); - break; /* Set flags. */ - case SLJIT_XOR: - FAIL_IF(push_inst(compiler, (EOR ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2))); - break; /* Set flags. */ - case SLJIT_SHL: - case SLJIT_MSHL: - FAIL_IF(push_inst(compiler, (LSLV ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2))); - break; /* Set flags. */ - case SLJIT_LSHR: - case SLJIT_MLSHR: - FAIL_IF(push_inst(compiler, (LSRV ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2))); - break; /* Set flags. */ - case SLJIT_ASHR: - case SLJIT_MASHR: - FAIL_IF(push_inst(compiler, (ASRV ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2))); - break; /* Set flags. */ - case SLJIT_ROTL: - FAIL_IF(push_inst(compiler, (SUB ^ inv_bits) | RD(TMP_REG2) | RN(TMP_ZERO) | RM(arg2))); - arg2 = TMP_REG2; - /* fallthrough */ - case SLJIT_ROTR: - return push_inst(compiler, (RORV ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2)); - default: - SLJIT_UNREACHABLE(); - return SLJIT_SUCCESS; - } - -set_flags: - if (flags & SET_FLAGS) - return push_inst(compiler, (SUBS ^ inv_bits) | RD(TMP_ZERO) | RN(dst) | RM(TMP_ZERO)); - return SLJIT_SUCCESS; -} - -#define STORE 0x10 -#define SIGNED 0x20 - -#define BYTE_SIZE 0x0 -#define HALF_SIZE 0x1 -#define INT_SIZE 0x2 -#define WORD_SIZE 0x3 - -#define MEM_SIZE_SHIFT(flags) ((sljit_ins)(flags) & 0x3) - -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) -{ - sljit_u32 shift = MEM_SIZE_SHIFT(flags); - sljit_u32 type = (shift << 30); - - if (!(flags & STORE)) - type |= (flags & SIGNED) ? 0x00800000 : 0x00400000; - - SLJIT_ASSERT(arg & SLJIT_MEM); - - if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) { - argw &= 0x3; - - if (argw == 0 || argw == shift) - return push_inst(compiler, STRB | type | RT(reg) - | RN(arg & REG_MASK) | RM(OFFS_REG(arg)) | (argw ? (1 << 12) : 0)); - - FAIL_IF(push_inst(compiler, ADD | RD(tmp_reg) | RN(arg & REG_MASK) | RM(OFFS_REG(arg)) | ((sljit_ins)argw << 10))); - return push_inst(compiler, STRBI | type | RT(reg) | RN(tmp_reg)); - } - - arg &= REG_MASK; - - if (!arg) { - FAIL_IF(load_immediate(compiler, tmp_reg, argw & ~(0xfff << shift))); - - argw = (argw >> shift) & 0xfff; - - return push_inst(compiler, STRBI | type | RT(reg) | RN(tmp_reg) | ((sljit_ins)argw << 10)); - } - - if ((argw & ((1 << shift) - 1)) == 0) { - if (argw >= 0) { - if ((argw >> shift) <= 0xfff) - return push_inst(compiler, STRBI | type | RT(reg) | RN(arg) | ((sljit_ins)argw << (10 - shift))); - - if (argw <= 0xffffff) { - FAIL_IF(push_inst(compiler, ADDI | (1 << 22) | RD(tmp_reg) | RN(arg) | (((sljit_ins)argw >> 12) << 10))); - - argw = ((argw & 0xfff) >> shift); - return push_inst(compiler, STRBI | type | RT(reg) | RN(tmp_reg) | ((sljit_ins)argw << 10)); - } - } else if (argw < -256 && argw >= -0xfff000) { - FAIL_IF(push_inst(compiler, SUBI | (1 << 22) | RD(tmp_reg) | RN(arg) | (((sljit_ins)(-argw + 0xfff) >> 12) << 10))); - argw = ((0x1000 + argw) & 0xfff) >> shift; - return push_inst(compiler, STRBI | type | RT(reg) | RN(tmp_reg) | ((sljit_ins)argw << 10)); - } - } - - 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) { - 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 >= -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)); - - return push_inst(compiler, STRB | type | RT(reg) | RN(arg) | RM(tmp_reg)); -} - -/* --------------------------------------------------------------------- */ -/* Entry, exit */ -/* --------------------------------------------------------------------- */ - -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, - sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size) -{ - sljit_s32 prev, fprev, saved_regs_size, i, tmp; - sljit_s32 saved_arg_count = SLJIT_KEPT_SAVEDS_COUNT(options); - sljit_ins offs; - - CHECK_ERROR(); - CHECK(check_sljit_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size)); - set_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size); - - saved_regs_size = GET_SAVED_REGISTERS_SIZE(scratches, saveds - saved_arg_count, 2); - saved_regs_size += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, SSIZE_OF(f64)); - - local_size = (local_size + saved_regs_size + 0xf) & ~0xf; - compiler->local_size = local_size; - - if (local_size <= 512) { - FAIL_IF(push_inst(compiler, STP_PRE | RT(TMP_FP) | RT2(TMP_LR) - | RN(SLJIT_SP) | (sljit_ins)((-(local_size >> 3) & 0x7f) << 15))); - offs = (sljit_ins)(local_size - 2 * SSIZE_OF(sw)) << (15 - 3); - local_size = 0; - } else { - saved_regs_size = ((saved_regs_size - 2 * SSIZE_OF(sw)) + 0xf) & ~0xf; - - FAIL_IF(push_inst(compiler, SUBI | RD(SLJIT_SP) | RN(SLJIT_SP) | ((sljit_ins)saved_regs_size << 10))); - offs = (sljit_ins)(saved_regs_size - 2 * SSIZE_OF(sw)) << (15 - 3); - local_size -= saved_regs_size; - SLJIT_ASSERT(local_size > 0); - } - - prev = -1; - - tmp = SLJIT_S0 - saveds; - for (i = SLJIT_S0 - saved_arg_count; i > tmp; i--) { - if (prev == -1) { - prev = i; - continue; - } - FAIL_IF(push_inst(compiler, STP | RT(prev) | RT2(i) | RN(SLJIT_SP) | offs)); - offs -= (sljit_ins)2 << 15; - prev = -1; - } - - for (i = scratches; i >= SLJIT_FIRST_SAVED_REG; i--) { - if (prev == -1) { - prev = i; - continue; - } - FAIL_IF(push_inst(compiler, STP | RT(prev) | RT2(i) | RN(SLJIT_SP) | offs)); - offs -= (sljit_ins)2 << 15; - prev = -1; - } - - fprev = -1; - - tmp = SLJIT_FS0 - fsaveds; - for (i = SLJIT_FS0; i > tmp; i--) { - if (fprev == -1) { - fprev = i; - continue; - } - FAIL_IF(push_inst(compiler, STP_F64 | VT(fprev) | VT2(i) | RN(SLJIT_SP) | offs)); - offs -= (sljit_ins)2 << 15; - fprev = -1; - } - - for (i = fscratches; i >= SLJIT_FIRST_SAVED_FLOAT_REG; i--) { - if (fprev == -1) { - fprev = i; - continue; - } - FAIL_IF(push_inst(compiler, STP_F64 | VT(fprev) | VT2(i) | RN(SLJIT_SP) | offs)); - offs -= (sljit_ins)2 << 15; - fprev = -1; - } - - if (fprev != -1) - FAIL_IF(push_inst(compiler, STRI_F64 | VT(fprev) | RN(SLJIT_SP) | (offs >> 5) | (1 << 10))); - - if (prev != -1) - FAIL_IF(push_inst(compiler, STRI | RT(prev) | RN(SLJIT_SP) | (offs >> 5) | ((fprev == -1) ? (1 << 10) : 0))); - - -#ifdef _WIN32 - if (local_size > 4096) - FAIL_IF(push_inst(compiler, SUBI | RD(SLJIT_SP) | RN(SLJIT_SP) | (1 << 10) | (1 << 22))); -#endif /* _WIN32 */ - - if (!(options & SLJIT_ENTER_REG_ARG)) { - arg_types >>= SLJIT_ARG_SHIFT; - saved_arg_count = 0; - tmp = SLJIT_R0; - - while (arg_types) { - if ((arg_types & SLJIT_ARG_MASK) < SLJIT_ARG_TYPE_F64) { - if (!(arg_types & SLJIT_ARG_TYPE_SCRATCH_REG)) { - FAIL_IF(push_inst(compiler, ORR | RD(SLJIT_S0 - saved_arg_count) | RN(TMP_ZERO) | RM(tmp))); - saved_arg_count++; - } - tmp++; - } - arg_types >>= SLJIT_ARG_SHIFT; - } - } - -#ifdef _WIN32 - if (local_size > 4096) { - if (local_size < 4 * 4096) { - /* No need for a loop. */ - - if (local_size >= 2 * 4096) { - if (local_size >= 3 * 4096) { - FAIL_IF(push_inst(compiler, LDRI | RT(TMP_ZERO) | RN(SLJIT_SP))); - FAIL_IF(push_inst(compiler, SUBI | RD(SLJIT_SP) | RN(SLJIT_SP) | (1 << 10) | (1 << 22))); - } - - FAIL_IF(push_inst(compiler, LDRI | RT(TMP_ZERO) | RN(SLJIT_SP))); - FAIL_IF(push_inst(compiler, SUBI | RD(SLJIT_SP) | RN(SLJIT_SP) | (1 << 10) | (1 << 22))); - } - } - else { - FAIL_IF(push_inst(compiler, MOVZ | RD(TMP_REG1) | ((((sljit_ins)local_size >> 12) - 1) << 5))); - FAIL_IF(push_inst(compiler, LDRI | RT(TMP_ZERO) | RN(SLJIT_SP))); - FAIL_IF(push_inst(compiler, SUBI | RD(SLJIT_SP) | RN(SLJIT_SP) | (1 << 10) | (1 << 22))); - FAIL_IF(push_inst(compiler, SUBI | (1 << 29) | RD(TMP_REG1) | RN(TMP_REG1) | (1 << 10))); - FAIL_IF(push_inst(compiler, B_CC | ((((sljit_ins) -3) & 0x7ffff) << 5) | 0x1 /* not-equal */)); - } - - local_size &= 0xfff; - - if (local_size > 0) - FAIL_IF(push_inst(compiler, LDRI | RT(TMP_ZERO) | RN(SLJIT_SP))); - else - FAIL_IF(push_inst(compiler, STP | RT(TMP_FP) | RT2(TMP_LR) | RN(SLJIT_SP))); - } - - if (local_size > 0) { - if (local_size <= 512) - FAIL_IF(push_inst(compiler, STP_PRE | RT(TMP_FP) | RT2(TMP_LR) - | RN(SLJIT_SP) | (sljit_ins)((-(local_size >> 3) & 0x7f) << 15))); - else { - if (local_size >= 4096) - local_size = (1 << (22 - 10)); - - FAIL_IF(push_inst(compiler, SUBI | RD(SLJIT_SP) | RN(SLJIT_SP) | ((sljit_ins)local_size << 10))); - FAIL_IF(push_inst(compiler, STP | RT(TMP_FP) | RT2(TMP_LR) | RN(SLJIT_SP))); - } - } - -#else /* !_WIN32 */ - - /* The local_size does not include saved registers size. */ - if (local_size != 0) { - if (local_size > 0xfff) { - FAIL_IF(push_inst(compiler, SUBI | RD(SLJIT_SP) | RN(SLJIT_SP) | (((sljit_ins)local_size >> 12) << 10) | (1 << 22))); - local_size &= 0xfff; - } - - if (local_size > 512 || local_size == 0) { - if (local_size != 0) - FAIL_IF(push_inst(compiler, SUBI | RD(SLJIT_SP) | RN(SLJIT_SP) | ((sljit_ins)local_size << 10))); - - FAIL_IF(push_inst(compiler, STP | RT(TMP_FP) | RT2(TMP_LR) | RN(SLJIT_SP))); - } else - FAIL_IF(push_inst(compiler, STP_PRE | RT(TMP_FP) | RT2(TMP_LR) - | RN(SLJIT_SP) | (sljit_ins)((-(local_size >> 3) & 0x7f) << 15))); - } - -#endif /* _WIN32 */ - - return push_inst(compiler, ADDI | RD(TMP_FP) | RN(SLJIT_SP) | (0 << 10)); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(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) -{ - sljit_s32 saved_regs_size; - - CHECK_ERROR(); - CHECK(check_sljit_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size)); - set_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size); - - saved_regs_size = GET_SAVED_REGISTERS_SIZE(scratches, saveds - SLJIT_KEPT_SAVEDS_COUNT(options), 2); - saved_regs_size += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, SSIZE_OF(f64)); - - compiler->local_size = (local_size + saved_regs_size + 0xf) & ~0xf; - return SLJIT_SUCCESS; -} - -static sljit_s32 emit_stack_frame_release(struct sljit_compiler *compiler, sljit_s32 is_return_to) -{ - sljit_s32 local_size, prev, fprev, i, tmp; - sljit_ins offs; - - local_size = compiler->local_size; - - if (!is_return_to) { - if (local_size > 512 && local_size <= 512 + 496) { - FAIL_IF(push_inst(compiler, LDP_POST | RT(TMP_FP) | RT2(TMP_LR) - | RN(SLJIT_SP) | ((sljit_ins)(local_size - 512) << (15 - 3)))); - local_size = 512; - } else - FAIL_IF(push_inst(compiler, LDP | RT(TMP_FP) | RT2(TMP_LR) | RN(SLJIT_SP))); - } else { - if (local_size > 512 && local_size <= 512 + 248) { - FAIL_IF(push_inst(compiler, LDRI_POST | RT(TMP_FP) | RN(SLJIT_SP) | ((sljit_ins)(local_size - 512) << 12))); - local_size = 512; - } else - FAIL_IF(push_inst(compiler, LDRI | RT(TMP_FP) | RN(SLJIT_SP) | 0)); - } - - if (local_size > 512) { - local_size -= 512; - if (local_size > 0xfff) { - FAIL_IF(push_inst(compiler, ADDI | RD(SLJIT_SP) | RN(SLJIT_SP) - | (((sljit_ins)local_size >> 12) << 10) | (1 << 22))); - local_size &= 0xfff; - } - - FAIL_IF(push_inst(compiler, ADDI | RD(SLJIT_SP) | RN(SLJIT_SP) | ((sljit_ins)local_size << 10))); - local_size = 512; - } - - offs = (sljit_ins)(local_size - 2 * SSIZE_OF(sw)) << (15 - 3); - prev = -1; - - tmp = SLJIT_S0 - compiler->saveds; - for (i = SLJIT_S0 - SLJIT_KEPT_SAVEDS_COUNT(compiler->options); i > tmp; i--) { - if (prev == -1) { - prev = i; - continue; - } - FAIL_IF(push_inst(compiler, LDP | RT(prev) | RT2(i) | RN(SLJIT_SP) | offs)); - offs -= (sljit_ins)2 << 15; - prev = -1; - } - - for (i = compiler->scratches; i >= SLJIT_FIRST_SAVED_REG; i--) { - if (prev == -1) { - prev = i; - continue; - } - FAIL_IF(push_inst(compiler, LDP | RT(prev) | RT2(i) | RN(SLJIT_SP) | offs)); - offs -= (sljit_ins)2 << 15; - prev = -1; - } - - fprev = -1; - - tmp = SLJIT_FS0 - compiler->fsaveds; - for (i = SLJIT_FS0; i > tmp; i--) { - if (fprev == -1) { - fprev = i; - continue; - } - FAIL_IF(push_inst(compiler, LDP_F64 | VT(fprev) | VT2(i) | RN(SLJIT_SP) | offs)); - offs -= (sljit_ins)2 << 15; - fprev = -1; - } - - for (i = compiler->fscratches; i >= SLJIT_FIRST_SAVED_FLOAT_REG; i--) { - if (fprev == -1) { - fprev = i; - continue; - } - FAIL_IF(push_inst(compiler, LDP_F64 | VT(fprev) | VT2(i) | RN(SLJIT_SP) | offs)); - offs -= (sljit_ins)2 << 15; - fprev = -1; - } - - if (fprev != -1) - FAIL_IF(push_inst(compiler, LDRI_F64 | VT(fprev) | RN(SLJIT_SP) | (offs >> 5) | (1 << 10))); - - if (prev != -1) - FAIL_IF(push_inst(compiler, LDRI | RT(prev) | RN(SLJIT_SP) | (offs >> 5) | ((fprev == -1) ? (1 << 10) : 0))); - - /* This and the next call/jump instruction can be executed parallelly. */ - return push_inst(compiler, ADDI | RD(SLJIT_SP) | RN(SLJIT_SP) | (sljit_ins)(local_size << 10)); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_void(struct sljit_compiler *compiler) -{ - CHECK_ERROR(); - CHECK(check_sljit_emit_return_void(compiler)); - - FAIL_IF(emit_stack_frame_release(compiler, 0)); - - return push_inst(compiler, RET | RN(TMP_LR)); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_to(struct sljit_compiler *compiler, - sljit_s32 src, sljit_sw srcw) -{ - CHECK_ERROR(); - CHECK(check_sljit_emit_return_to(compiler, src, srcw)); - - 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; - srcw = 0; - } else if (src >= SLJIT_FIRST_SAVED_REG && src <= (SLJIT_S0 - SLJIT_KEPT_SAVEDS_COUNT(compiler->options))) { - FAIL_IF(push_inst(compiler, ORR | RD(TMP_REG1) | RN(TMP_ZERO) | RM(src))); - src = TMP_REG1; - srcw = 0; - } - - FAIL_IF(emit_stack_frame_release(compiler, 1)); - - SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_ijump(compiler, SLJIT_JUMP, src, srcw); -} - -/* --------------------------------------------------------------------- */ -/* Operators */ -/* --------------------------------------------------------------------- */ - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compiler, sljit_s32 op) -{ - sljit_ins inv_bits = (op & SLJIT_32) ? W_OP : 0; - - CHECK_ERROR(); - CHECK(check_sljit_emit_op0(compiler, op)); - - op = GET_OPCODE(op); - switch (op) { - case SLJIT_BREAKPOINT: - return push_inst(compiler, BRK); - case SLJIT_NOP: - return push_inst(compiler, NOP); - case SLJIT_LMUL_UW: - case SLJIT_LMUL_SW: - FAIL_IF(push_inst(compiler, ORR | RD(TMP_REG1) | RN(TMP_ZERO) | RM(SLJIT_R0))); - FAIL_IF(push_inst(compiler, MADD | RD(SLJIT_R0) | RN(SLJIT_R0) | RM(SLJIT_R1) | RT2(TMP_ZERO))); - return push_inst(compiler, (op == SLJIT_LMUL_UW ? UMULH : SMULH) | RD(SLJIT_R1) | RN(TMP_REG1) | RM(SLJIT_R1)); - case SLJIT_DIVMOD_UW: - case SLJIT_DIVMOD_SW: - FAIL_IF(push_inst(compiler, (ORR ^ inv_bits) | RD(TMP_REG1) | RN(TMP_ZERO) | RM(SLJIT_R0))); - FAIL_IF(push_inst(compiler, ((op == SLJIT_DIVMOD_UW ? UDIV : SDIV) ^ inv_bits) | RD(SLJIT_R0) | RN(SLJIT_R0) | RM(SLJIT_R1))); - FAIL_IF(push_inst(compiler, (MADD ^ inv_bits) | RD(SLJIT_R1) | RN(SLJIT_R0) | RM(SLJIT_R1) | RT2(TMP_ZERO))); - return push_inst(compiler, (SUB ^ inv_bits) | RD(SLJIT_R1) | RN(TMP_REG1) | RM(SLJIT_R1)); - case SLJIT_DIV_UW: - case SLJIT_DIV_SW: - return push_inst(compiler, ((op == SLJIT_DIV_UW ? UDIV : SDIV) ^ inv_bits) | RD(SLJIT_R0) | RN(SLJIT_R0) | RM(SLJIT_R1)); - case SLJIT_ENDBR: - case SLJIT_SKIP_FRAMES_BEFORE_RETURN: - return SLJIT_SUCCESS; - } - - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src, sljit_sw srcw) -{ - sljit_s32 dst_r, flags, mem_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; - - 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)) - return emit_op_imm(compiler, op | ((op_flags & SLJIT_32) ? INT_OP : 0), dst_r, TMP_REG1, src); - - switch (op) { - case SLJIT_MOV: - case SLJIT_MOV_P: - mem_flags = WORD_SIZE; - break; - case SLJIT_MOV_U8: - mem_flags = BYTE_SIZE; - if (src & SLJIT_IMM) - srcw = (sljit_u8)srcw; - break; - case SLJIT_MOV_S8: - mem_flags = BYTE_SIZE | SIGNED; - if (src & SLJIT_IMM) - srcw = (sljit_s8)srcw; - break; - case SLJIT_MOV_U16: - mem_flags = HALF_SIZE; - if (src & SLJIT_IMM) - srcw = (sljit_u16)srcw; - break; - case SLJIT_MOV_S16: - mem_flags = HALF_SIZE | SIGNED; - if (src & SLJIT_IMM) - srcw = (sljit_s16)srcw; - break; - case SLJIT_MOV_U32: - mem_flags = INT_SIZE; - if (src & SLJIT_IMM) - srcw = (sljit_u32)srcw; - break; - case SLJIT_MOV_S32: - case SLJIT_MOV32: - mem_flags = INT_SIZE | SIGNED; - if (src & SLJIT_IMM) - srcw = (sljit_s32)srcw; - break; - default: - SLJIT_UNREACHABLE(); - mem_flags = 0; - break; - } - - if (src & SLJIT_IMM) - FAIL_IF(emit_op_imm(compiler, SLJIT_MOV | ARG2_IMM, dst_r, TMP_REG1, srcw)); - else if (!(src & SLJIT_MEM)) - dst_r = src; - else - FAIL_IF(emit_op_mem(compiler, mem_flags, dst_r, src, srcw, TMP_REG1)); - - if (dst & SLJIT_MEM) - return emit_op_mem(compiler, mem_flags | STORE, dst_r, dst, dstw, TMP_REG2); - return SLJIT_SUCCESS; - } - - flags = HAS_FLAGS(op_flags) ? SET_FLAGS : 0; - mem_flags = WORD_SIZE; - - if (op_flags & SLJIT_32) { - flags |= INT_OP; - mem_flags = INT_SIZE; - } - - if (src & SLJIT_MEM) { - FAIL_IF(emit_op_mem(compiler, mem_flags, TMP_REG2, src, srcw, TMP_REG2)); - src = TMP_REG2; - } - - emit_op_imm(compiler, flags | op, dst_r, TMP_REG1, src); - - if (SLJIT_UNLIKELY(dst & SLJIT_MEM)) - return emit_op_mem(compiler, mem_flags | STORE, dst_r, dst, dstw, TMP_REG2); - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - sljit_s32 dst_r, flags, mem_flags; - - CHECK_ERROR(); - CHECK(check_sljit_emit_op2(compiler, op, 0, dst, dstw, src1, src1w, src2, src2w)); - ADJUST_LOCAL_OFFSET(dst, dstw); - ADJUST_LOCAL_OFFSET(src1, src1w); - ADJUST_LOCAL_OFFSET(src2, src2w); - - dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1; - flags = HAS_FLAGS(op) ? SET_FLAGS : 0; - mem_flags = WORD_SIZE; - - if (op & SLJIT_32) { - flags |= INT_OP; - mem_flags = INT_SIZE; - } - - if (dst == TMP_REG1) - flags |= UNUSED_RETURN; - - if (src1 & SLJIT_MEM) { - FAIL_IF(emit_op_mem(compiler, mem_flags, TMP_REG1, src1, src1w, TMP_REG1)); - src1 = TMP_REG1; - } - - if (src2 & SLJIT_MEM) { - FAIL_IF(emit_op_mem(compiler, mem_flags, TMP_REG2, src2, src2w, TMP_REG2)); - src2 = TMP_REG2; - } - - if (src1 & SLJIT_IMM) - flags |= ARG1_IMM; - else - src1w = src1; - - if (src2 & SLJIT_IMM) - flags |= ARG2_IMM; - else - src2w = src2; - - emit_op_imm(compiler, flags | GET_OPCODE(op), dst_r, src1w, src2w); - - if (dst & SLJIT_MEM) - return emit_op_mem(compiler, mem_flags | STORE, dst_r, dst, dstw, TMP_REG2); - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - 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, TMP_REG1, 0, src1, src1w, src2, src2w); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 src_dst, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - sljit_ins inv_bits, imm; - sljit_s32 is_left; - sljit_sw mask; - - CHECK_ERROR(); - CHECK(check_sljit_emit_shift_into(compiler, op, src_dst, src1, src1w, src2, src2w)); - - is_left = (GET_OPCODE(op) == SLJIT_SHL || GET_OPCODE(op) == SLJIT_MSHL); - - if (src_dst == src1) { - SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_op2(compiler, (is_left ? SLJIT_ROTL : SLJIT_ROTR) | (op & SLJIT_32), src_dst, 0, src_dst, 0, src2, src2w); - } - - ADJUST_LOCAL_OFFSET(src1, src1w); - ADJUST_LOCAL_OFFSET(src2, src2w); - - inv_bits = (op & SLJIT_32) ? W_OP : 0; - mask = inv_bits ? 0x1f : 0x3f; - - if (src2 & SLJIT_IMM) { - src2w &= mask; - - if (src2w == 0) - return SLJIT_SUCCESS; - } else if (src2 & SLJIT_MEM) { - FAIL_IF(emit_op_mem(compiler, inv_bits ? INT_SIZE : WORD_SIZE, TMP_REG2, src2, src2w, TMP_REG2)); - src2 = TMP_REG2; - } - - if (src1 & SLJIT_MEM) { - FAIL_IF(emit_op_mem(compiler, inv_bits ? INT_SIZE : WORD_SIZE, TMP_REG1, src1, src1w, TMP_REG1)); - src1 = TMP_REG1; - } else if (src1 & SLJIT_IMM) { - FAIL_IF(load_immediate(compiler, TMP_REG1, src1w)); - src1 = TMP_REG1; - } - - if (src2 & SLJIT_IMM) { - if (is_left) - src2w = (src2w ^ mask) + 1; - - return push_inst(compiler, (EXTR ^ (inv_bits | (inv_bits >> 9))) | RD(src_dst) - | RN(is_left ? src_dst : src1) | RM(is_left ? src1 : src_dst) | ((sljit_ins)src2w << 10)); - } - - FAIL_IF(push_inst(compiler, ((is_left ? LSLV : LSRV) ^ inv_bits) | RD(src_dst) | RN(src_dst) | RM(src2))); - - if (!(op & SLJIT_SHIFT_INTO_NON_ZERO)) { - /* Shift left/right by 1. */ - if (is_left) - imm = (sljit_ins)(inv_bits ? ((1 << 16) | (31 << 10)) : ((1 << 16) | (63 << 10) | (1 << 22))); - else - imm = (sljit_ins)(inv_bits ? ((31 << 16) | (30 << 10)) : ((63 << 16) | (62 << 10) | (1 << 22))); - - FAIL_IF(push_inst(compiler, (UBFM ^ inv_bits) | RD(TMP_REG1) | RN(src1) | imm)); - - /* Set imm to mask. */ - imm = (sljit_ins)(inv_bits ? (4 << 10) : ((5 << 10) | (1 << 22))); - FAIL_IF(push_inst(compiler, (EORI ^ inv_bits) | RD(TMP_REG2) | RN(src2) | imm)); - - src1 = TMP_REG1; - } else - FAIL_IF(push_inst(compiler, (SUB ^ inv_bits) | RD(TMP_REG2) | RN(TMP_ZERO) | RM(src2))); - - FAIL_IF(push_inst(compiler, ((is_left ? LSRV : LSLV) ^ inv_bits) | RD(TMP_REG1) | RN(src1) | RM(TMP_REG2))); - return push_inst(compiler, (ORR ^ inv_bits) | RD(src_dst) | RN(src_dst) | RM(TMP_REG1)); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 src, sljit_sw srcw) -{ - CHECK_ERROR(); - CHECK(check_sljit_emit_op_src(compiler, op, src, srcw)); - ADJUST_LOCAL_OFFSET(src, srcw); - - switch (op) { - case SLJIT_FAST_RETURN: - if (FAST_IS_REG(src)) - FAIL_IF(push_inst(compiler, ORR | RD(TMP_LR) | RN(TMP_ZERO) | RM(src))); - else - FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_LR, src, srcw, TMP_REG1)); - - return push_inst(compiler, RET | RN(TMP_LR)); - case SLJIT_SKIP_FRAMES_BEFORE_FAST_RETURN: - return SLJIT_SUCCESS; - case SLJIT_PREFETCH_L1: - case SLJIT_PREFETCH_L2: - case SLJIT_PREFETCH_L3: - case SLJIT_PREFETCH_ONCE: - SLJIT_ASSERT(reg_map[1] == 0 && reg_map[3] == 2 && reg_map[5] == 4); - - /* The reg_map[op] should provide the appropriate constant. */ - if (op == SLJIT_PREFETCH_L1) - op = 1; - else if (op == SLJIT_PREFETCH_L2) - op = 3; - else if (op == SLJIT_PREFETCH_L3) - op = 5; - else - op = 2; - - /* Signed word sized load is the prefetch instruction. */ - return emit_op_mem(compiler, WORD_SIZE | SIGNED, op, src, srcw, TMP_REG1); - } - - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 reg) -{ - CHECK_REG_INDEX(check_sljit_get_register_index(reg)); - return reg_map[reg]; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_float_register_index(sljit_s32 reg) -{ - CHECK_REG_INDEX(check_sljit_get_float_register_index(reg)); - return freg_map[reg]; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler, - void *instruction, sljit_u32 size) -{ - SLJIT_UNUSED_ARG(size); - CHECK_ERROR(); - CHECK(check_sljit_emit_op_custom(compiler, instruction, size)); - - return push_inst(compiler, *(sljit_ins*)instruction); -} - -/* --------------------------------------------------------------------- */ -/* Floating point operators */ -/* --------------------------------------------------------------------- */ - -static sljit_s32 emit_fop_mem(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg, sljit_sw argw) -{ - sljit_u32 shift = MEM_SIZE_SHIFT(flags); - sljit_ins type = (shift << 30); - - SLJIT_ASSERT(arg & SLJIT_MEM); - - if (!(flags & STORE)) - type |= 0x00400000; - - if (arg & OFFS_REG_MASK) { - argw &= 3; - if (argw == 0 || argw == shift) - 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)); - } - - arg &= REG_MASK; - - if (!arg) { - FAIL_IF(load_immediate(compiler, TMP_REG1, argw & ~(0xfff << shift))); - - argw = (argw >> shift) & 0xfff; - - return push_inst(compiler, STR_FI | type | VT(reg) | RN(TMP_REG1) | ((sljit_ins)argw << 10)); - } - - if (argw >= 0 && (argw & ((1 << shift) - 1)) == 0) { - if ((argw >> shift) <= 0xfff) - 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))); - - argw = ((argw & 0xfff) >> shift); - return push_inst(compiler, STR_FI | type | VT(reg) | RN(TMP_REG1) | ((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)); -} - -static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src, sljit_sw srcw) -{ - sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1; - sljit_ins inv_bits = (op & SLJIT_32) ? (1 << 22) : 0; - - if (GET_OPCODE(op) == SLJIT_CONV_S32_FROM_F64) - inv_bits |= W_OP; - - if (src & SLJIT_MEM) { - emit_fop_mem(compiler, (op & SLJIT_32) ? INT_SIZE : WORD_SIZE, TMP_FREG1, src, srcw); - src = TMP_FREG1; - } - - FAIL_IF(push_inst(compiler, (FCVTZS ^ inv_bits) | RD(dst_r) | VN(src))); - - if (dst & SLJIT_MEM) - return emit_op_mem(compiler, ((GET_OPCODE(op) == SLJIT_CONV_S32_FROM_F64) ? INT_SIZE : WORD_SIZE) | STORE, TMP_REG1, dst, dstw, TMP_REG2); - return SLJIT_SUCCESS; -} - -static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src, sljit_sw srcw) -{ - sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1; - sljit_ins inv_bits = (op & SLJIT_32) ? (1 << 22) : 0; - - if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32) - inv_bits |= W_OP; - - if (src & SLJIT_MEM) { - emit_op_mem(compiler, ((GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32) ? INT_SIZE : WORD_SIZE), TMP_REG1, src, srcw, TMP_REG1); - src = TMP_REG1; - } else if (src & SLJIT_IMM) { - if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32) - srcw = (sljit_s32)srcw; - - FAIL_IF(load_immediate(compiler, TMP_REG1, srcw)); - src = TMP_REG1; - } - - FAIL_IF(push_inst(compiler, (SCVTF ^ inv_bits) | VD(dst_r) | RN(src))); - - if (dst & SLJIT_MEM) - return emit_fop_mem(compiler, ((op & SLJIT_32) ? INT_SIZE : WORD_SIZE) | STORE, TMP_FREG1, dst, dstw); - return SLJIT_SUCCESS; -} - -static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - sljit_s32 mem_flags = (op & SLJIT_32) ? INT_SIZE : WORD_SIZE; - sljit_ins inv_bits = (op & SLJIT_32) ? (1 << 22) : 0; - - if (src1 & SLJIT_MEM) { - emit_fop_mem(compiler, mem_flags, TMP_FREG1, src1, src1w); - src1 = TMP_FREG1; - } - - if (src2 & SLJIT_MEM) { - emit_fop_mem(compiler, mem_flags, TMP_FREG2, src2, src2w); - src2 = TMP_FREG2; - } - - return push_inst(compiler, (FCMP ^ inv_bits) | VN(src1) | VM(src2)); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src, sljit_sw srcw) -{ - sljit_s32 dst_r, mem_flags = (op & SLJIT_32) ? INT_SIZE : WORD_SIZE; - sljit_ins inv_bits; - - CHECK_ERROR(); - - SLJIT_COMPILE_ASSERT((INT_SIZE ^ 0x1) == WORD_SIZE, must_be_one_bit_difference); - SELECT_FOP1_OPERATION_WITH_CHECKS(compiler, op, dst, dstw, src, srcw); - - inv_bits = (op & SLJIT_32) ? (1 << 22) : 0; - dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1; - - if (src & SLJIT_MEM) { - emit_fop_mem(compiler, (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_F32) ? (mem_flags ^ 0x1) : mem_flags, dst_r, src, srcw); - src = dst_r; - } - - switch (GET_OPCODE(op)) { - case SLJIT_MOV_F64: - if (src != dst_r) { - if (dst_r != TMP_FREG1) - FAIL_IF(push_inst(compiler, (FMOV ^ inv_bits) | VD(dst_r) | VN(src))); - else - dst_r = src; - } - break; - case SLJIT_NEG_F64: - FAIL_IF(push_inst(compiler, (FNEG ^ inv_bits) | VD(dst_r) | VN(src))); - break; - case SLJIT_ABS_F64: - FAIL_IF(push_inst(compiler, (FABS ^ inv_bits) | VD(dst_r) | VN(src))); - break; - case SLJIT_CONV_F64_FROM_F32: - FAIL_IF(push_inst(compiler, FCVT | (sljit_ins)((op & SLJIT_32) ? (1 << 22) : (1 << 15)) | VD(dst_r) | VN(src))); - break; - } - - if (dst & SLJIT_MEM) - return emit_fop_mem(compiler, mem_flags | STORE, dst_r, dst, dstw); - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - sljit_s32 dst_r, mem_flags = (op & SLJIT_32) ? INT_SIZE : WORD_SIZE; - sljit_ins inv_bits = (op & SLJIT_32) ? (1 << 22) : 0; - - CHECK_ERROR(); - CHECK(check_sljit_emit_fop2(compiler, op, dst, dstw, src1, src1w, src2, src2w)); - ADJUST_LOCAL_OFFSET(dst, dstw); - ADJUST_LOCAL_OFFSET(src1, src1w); - ADJUST_LOCAL_OFFSET(src2, src2w); - - dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1; - if (src1 & SLJIT_MEM) { - emit_fop_mem(compiler, mem_flags, TMP_FREG1, src1, src1w); - src1 = TMP_FREG1; - } - if (src2 & SLJIT_MEM) { - emit_fop_mem(compiler, mem_flags, TMP_FREG2, src2, src2w); - src2 = TMP_FREG2; - } - - switch (GET_OPCODE(op)) { - case SLJIT_ADD_F64: - FAIL_IF(push_inst(compiler, (FADD ^ inv_bits) | VD(dst_r) | VN(src1) | VM(src2))); - break; - case SLJIT_SUB_F64: - FAIL_IF(push_inst(compiler, (FSUB ^ inv_bits) | VD(dst_r) | VN(src1) | VM(src2))); - break; - case SLJIT_MUL_F64: - FAIL_IF(push_inst(compiler, (FMUL ^ inv_bits) | VD(dst_r) | VN(src1) | VM(src2))); - break; - case SLJIT_DIV_F64: - FAIL_IF(push_inst(compiler, (FDIV ^ inv_bits) | VD(dst_r) | VN(src1) | VM(src2))); - break; - } - - if (!(dst & SLJIT_MEM)) - return SLJIT_SUCCESS; - return emit_fop_mem(compiler, mem_flags | STORE, TMP_FREG1, dst, dstw); -} - -/* --------------------------------------------------------------------- */ -/* Other instructions */ -/* --------------------------------------------------------------------- */ - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw) -{ - CHECK_ERROR(); - CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw)); - ADJUST_LOCAL_OFFSET(dst, dstw); - - if (FAST_IS_REG(dst)) - return push_inst(compiler, ORR | RD(dst) | RN(TMP_ZERO) | RM(TMP_LR)); - - /* Memory. */ - return emit_op_mem(compiler, WORD_SIZE | STORE, TMP_LR, dst, dstw, TMP_REG1); -} - -/* --------------------------------------------------------------------- */ -/* Conditional instructions */ -/* --------------------------------------------------------------------- */ - -static sljit_ins get_cc(struct sljit_compiler *compiler, sljit_s32 type) -{ - switch (type) { - case SLJIT_EQUAL: - case SLJIT_F_EQUAL: - case SLJIT_ORDERED_EQUAL: - case SLJIT_UNORDERED_OR_EQUAL: /* Not supported. */ - return 0x1; - - case SLJIT_NOT_EQUAL: - case SLJIT_F_NOT_EQUAL: - case SLJIT_UNORDERED_OR_NOT_EQUAL: - case SLJIT_ORDERED_NOT_EQUAL: /* Not supported. */ - return 0x0; - - case SLJIT_CARRY: - if (compiler->status_flags_state & SLJIT_CURRENT_FLAGS_ADD) - return 0x3; - /* fallthrough */ - - case SLJIT_LESS: - return 0x2; - - case SLJIT_NOT_CARRY: - if (compiler->status_flags_state & SLJIT_CURRENT_FLAGS_ADD) - return 0x2; - /* fallthrough */ - - case SLJIT_GREATER_EQUAL: - return 0x3; - - case SLJIT_GREATER: - case SLJIT_UNORDERED_OR_GREATER: - return 0x9; - - case SLJIT_LESS_EQUAL: - case SLJIT_F_LESS_EQUAL: - case SLJIT_ORDERED_LESS_EQUAL: - return 0x8; - - case SLJIT_SIG_LESS: - case SLJIT_UNORDERED_OR_LESS: - return 0xa; - - case SLJIT_SIG_GREATER_EQUAL: - case SLJIT_F_GREATER_EQUAL: - case SLJIT_ORDERED_GREATER_EQUAL: - return 0xb; - - case SLJIT_SIG_GREATER: - case SLJIT_F_GREATER: - case SLJIT_ORDERED_GREATER: - return 0xd; - - case SLJIT_SIG_LESS_EQUAL: - case SLJIT_UNORDERED_OR_LESS_EQUAL: - return 0xc; - - case SLJIT_OVERFLOW: - if (!(compiler->status_flags_state & (SLJIT_CURRENT_FLAGS_ADD | SLJIT_CURRENT_FLAGS_SUB))) - return 0x0; - /* fallthrough */ - - case SLJIT_UNORDERED: - return 0x7; - - case SLJIT_NOT_OVERFLOW: - if (!(compiler->status_flags_state & (SLJIT_CURRENT_FLAGS_ADD | SLJIT_CURRENT_FLAGS_SUB))) - return 0x1; - /* fallthrough */ - - case SLJIT_ORDERED: - return 0x6; - - case SLJIT_F_LESS: - case SLJIT_ORDERED_LESS: - return 0x5; - - case SLJIT_UNORDERED_OR_GREATER_EQUAL: - return 0x4; - - default: - SLJIT_UNREACHABLE(); - return 0xe; - } -} - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compiler *compiler) -{ - struct sljit_label *label; - - CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_label(compiler)); - - if (compiler->last_label && compiler->last_label->size == compiler->size) - return compiler->last_label; - - label = (struct sljit_label*)ensure_abuf(compiler, sizeof(struct sljit_label)); - PTR_FAIL_IF(!label); - set_label(label, compiler); - return label; -} - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type) -{ - struct sljit_jump *jump; - - CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_jump(compiler, type)); - - jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump)); - PTR_FAIL_IF(!jump); - set_jump(jump, compiler, type & SLJIT_REWRITABLE_JUMP); - type &= 0xff; - - 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) - 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))); - - return jump; -} - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_call(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 arg_types) -{ - SLJIT_UNUSED_ARG(arg_types); - CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_call(compiler, type, arg_types)); - - if (type & SLJIT_CALL_RETURN) { - PTR_FAIL_IF(emit_stack_frame_release(compiler, 0)); - type = SLJIT_JUMP | (type & SLJIT_REWRITABLE_JUMP); - } - - SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_jump(compiler, type); -} - -static SLJIT_INLINE struct sljit_jump* emit_cmp_to0(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 src, sljit_sw srcw) -{ - struct sljit_jump *jump; - sljit_ins inv_bits = (type & SLJIT_32) ? W_OP : 0; - - SLJIT_ASSERT((type & 0xff) == SLJIT_EQUAL || (type & 0xff) == SLJIT_NOT_EQUAL); - ADJUST_LOCAL_OFFSET(src, srcw); - - jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump)); - PTR_FAIL_IF(!jump); - set_jump(jump, compiler, type & SLJIT_REWRITABLE_JUMP); - jump->flags |= IS_CBZ | IS_COND; - - if (src & SLJIT_MEM) { - PTR_FAIL_IF(emit_op_mem(compiler, inv_bits ? INT_SIZE : WORD_SIZE, TMP_REG1, src, srcw, TMP_REG1)); - src = TMP_REG1; - } - else if (src & SLJIT_IMM) { - PTR_FAIL_IF(load_immediate(compiler, TMP_REG1, srcw)); - src = TMP_REG1; - } - - SLJIT_ASSERT(FAST_IS_REG(src)); - - if ((type & 0xff) == SLJIT_EQUAL) - 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))); - return jump; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 src, sljit_sw srcw) -{ - struct sljit_jump *jump; - - CHECK_ERROR(); - CHECK(check_sljit_emit_ijump(compiler, type, src, srcw)); - - 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; - } - return push_inst(compiler, ((type >= SLJIT_FAST_CALL) ? BLR : BR) | RN(src)); - } - - /* These jumps are converted to jump/call instructions when possible. */ - jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump)); - FAIL_IF(!jump); - 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)); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 arg_types, - sljit_s32 src, sljit_sw srcw) -{ - SLJIT_UNUSED_ARG(arg_types); - CHECK_ERROR(); - CHECK(check_sljit_emit_icall(compiler, type, arg_types, src, srcw)); - - 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; - } - - if (type & SLJIT_CALL_RETURN) { - if (src >= SLJIT_FIRST_SAVED_REG && src <= (SLJIT_S0 - SLJIT_KEPT_SAVEDS_COUNT(compiler->options))) { - FAIL_IF(push_inst(compiler, ORR | RD(TMP_REG1) | RN(TMP_ZERO) | RM(src))); - src = TMP_REG1; - } - - FAIL_IF(emit_stack_frame_release(compiler, 0)); - type = SLJIT_JUMP; - } - - SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_ijump(compiler, type, src, srcw); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 type) -{ - sljit_s32 dst_r, src_r, flags, mem_flags; - sljit_ins cc; - - CHECK_ERROR(); - CHECK(check_sljit_emit_op_flags(compiler, op, dst, dstw, type)); - ADJUST_LOCAL_OFFSET(dst, dstw); - - cc = get_cc(compiler, type); - dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1; - - 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) { - 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); - } - - return SLJIT_SUCCESS; - } - - flags = HAS_FLAGS(op) ? SET_FLAGS : 0; - mem_flags = WORD_SIZE; - - if (op & SLJIT_32) { - flags |= INT_OP; - mem_flags = INT_SIZE; - } - - src_r = dst; - - if (dst & SLJIT_MEM) { - FAIL_IF(emit_op_mem(compiler, mem_flags, TMP_REG1, dst, dstw, TMP_REG1)); - src_r = TMP_REG1; - } - - FAIL_IF(push_inst(compiler, CSINC | (cc << 12) | RD(TMP_REG2) | RN(TMP_ZERO) | RM(TMP_ZERO))); - emit_op_imm(compiler, flags | GET_OPCODE(op), dst_r, src_r, TMP_REG2); - - if (dst & SLJIT_MEM) - return emit_op_mem(compiler, mem_flags | STORE, TMP_REG1, dst, dstw, TMP_REG2); - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 dst_reg, - sljit_s32 src, sljit_sw srcw) -{ - sljit_ins inv_bits = (type & SLJIT_32) ? W_OP : 0; - sljit_ins cc; - - CHECK_ERROR(); - CHECK(check_sljit_emit_cmov(compiler, type, dst_reg, src, srcw)); - - if (SLJIT_UNLIKELY(src & SLJIT_IMM)) { - if (type & SLJIT_32) - srcw = (sljit_s32)srcw; - FAIL_IF(load_immediate(compiler, TMP_REG1, srcw)); - src = TMP_REG1; - srcw = 0; - } - - cc = get_cc(compiler, type & ~SLJIT_32); - - return push_inst(compiler, (CSEL ^ inv_bits) | (cc << 12) | RD(dst_reg) | RN(dst_reg) | RM(src)); -} - -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) -{ - sljit_u32 inst; - - CHECK_ERROR(); - CHECK(check_sljit_emit_mem(compiler, type, reg, mem, memw)); - - if (!(reg & REG_PAIR_MASK)) - return sljit_emit_mem_unaligned(compiler, type, reg, mem, memw); - - ADJUST_LOCAL_OFFSET(mem, memw); - - if (!(mem & REG_MASK)) { - FAIL_IF(load_immediate(compiler, TMP_REG1, memw & ~0x1f8)); - - mem = SLJIT_MEM1(TMP_REG1); - memw &= 0x1f8; - } else if (mem & OFFS_REG_MASK) { - FAIL_IF(push_inst(compiler, ADD | RD(TMP_REG1) | RN(mem & REG_MASK) | RM(OFFS_REG(mem)) | ((sljit_ins)(memw & 0x3) << 10))); - - mem = SLJIT_MEM1(TMP_REG1); - memw = 0; - } else if ((memw & 0x7) != 0 || memw > 0x1f8 || memw < -0x200) { - inst = ADDI; - - if (memw < 0) { - /* Remains negative for integer min. */ - memw = -memw; - inst = SUBI; - } else if ((memw & 0x7) == 0 && memw <= 0x7ff0) { - if (!(type & SLJIT_MEM_STORE) && (mem & REG_MASK) == REG_PAIR_FIRST(reg)) { - FAIL_IF(push_inst(compiler, LDRI | RD(REG_PAIR_SECOND(reg)) | RN(mem & REG_MASK) | ((sljit_ins)memw << 7))); - return push_inst(compiler, LDRI | RD(REG_PAIR_FIRST(reg)) | RN(mem & REG_MASK) | ((sljit_ins)(memw + 0x8) << 7)); - } - - inst = (type & SLJIT_MEM_STORE) ? STRI : LDRI; - - FAIL_IF(push_inst(compiler, inst | RD(REG_PAIR_FIRST(reg)) | RN(mem & REG_MASK) | ((sljit_ins)memw << 7))); - return push_inst(compiler, inst | RD(REG_PAIR_SECOND(reg)) | RN(mem & REG_MASK) | ((sljit_ins)(memw + 0x8) << 7)); - } - - if ((sljit_uw)memw <= 0xfff) { - FAIL_IF(push_inst(compiler, inst | RD(TMP_REG1) | RN(mem & REG_MASK) | ((sljit_ins)memw << 10))); - memw = 0; - } else if ((sljit_uw)memw <= 0xffffff) { - FAIL_IF(push_inst(compiler, inst | (1 << 22) | RD(TMP_REG1) | RN(mem & REG_MASK) | (((sljit_ins)memw >> 12) << 10))); - - if ((memw & 0xe07) != 0) { - FAIL_IF(push_inst(compiler, inst | RD(TMP_REG1) | RN(TMP_REG1) | (((sljit_ins)memw & 0xfff) << 10))); - memw = 0; - } else { - memw &= 0xfff; - } - } else { - FAIL_IF(load_immediate(compiler, TMP_REG1, memw)); - FAIL_IF(push_inst(compiler, (inst == ADDI ? ADD : SUB) | RD(TMP_REG1) | RN(mem & REG_MASK) | RM(TMP_REG1))); - memw = 0; - } - - mem = SLJIT_MEM1(TMP_REG1); - - if (inst == SUBI) - memw = -memw; - } - - SLJIT_ASSERT((memw & 0x7) == 0 && memw <= 0x1f8 && memw >= -0x200); - return push_inst(compiler, ((type & SLJIT_MEM_STORE) ? STP : LDP) | RT(REG_PAIR_FIRST(reg)) | RT2(REG_PAIR_SECOND(reg)) | RN(mem & REG_MASK) | (sljit_ins)((memw & 0x3f8) << 12)); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem_update(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 reg, - sljit_s32 mem, sljit_sw memw) -{ - sljit_u32 sign = 0, inst; - - CHECK_ERROR(); - CHECK(check_sljit_emit_mem_update(compiler, type, reg, mem, memw)); - - if ((mem & OFFS_REG_MASK) || (memw > 255 || memw < -256)) - return SLJIT_ERR_UNSUPPORTED; - - if (type & SLJIT_MEM_SUPP) - return SLJIT_SUCCESS; - - switch (type & 0xff) { - case SLJIT_MOV: - case SLJIT_MOV_P: - inst = STURBI | (MEM_SIZE_SHIFT(WORD_SIZE) << 30) | 0x400; - break; - case SLJIT_MOV_S8: - sign = 1; - /* fallthrough */ - case SLJIT_MOV_U8: - inst = STURBI | (MEM_SIZE_SHIFT(BYTE_SIZE) << 30) | 0x400; - break; - case SLJIT_MOV_S16: - sign = 1; - /* fallthrough */ - case SLJIT_MOV_U16: - inst = STURBI | (MEM_SIZE_SHIFT(HALF_SIZE) << 30) | 0x400; - break; - case SLJIT_MOV_S32: - sign = 1; - /* fallthrough */ - case SLJIT_MOV_U32: - case SLJIT_MOV32: - inst = STURBI | (MEM_SIZE_SHIFT(INT_SIZE) << 30) | 0x400; - break; - default: - SLJIT_UNREACHABLE(); - inst = STURBI | (MEM_SIZE_SHIFT(WORD_SIZE) << 30) | 0x400; - break; - } - - if (!(type & SLJIT_MEM_STORE)) - inst |= sign ? 0x00800000 : 0x00400000; - - if (!(type & SLJIT_MEM_POST)) - inst |= 0x800; - - return push_inst(compiler, inst | RT(reg) | RN(mem & REG_MASK) | (sljit_ins)((memw & 0x1ff) << 12)); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fmem_update(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 freg, - sljit_s32 mem, sljit_sw memw) -{ - sljit_u32 inst; - - CHECK_ERROR(); - CHECK(check_sljit_emit_fmem_update(compiler, type, freg, mem, memw)); - - if ((mem & OFFS_REG_MASK) || (memw > 255 || memw < -256)) - return SLJIT_ERR_UNSUPPORTED; - - if (type & SLJIT_MEM_SUPP) - return SLJIT_SUCCESS; - - inst = STUR_FI | 0x80000400; - - if (!(type & SLJIT_32)) - inst |= 0x40000000; - - if (!(type & SLJIT_MEM_STORE)) - inst |= 0x00400000; - - if (!(type & SLJIT_MEM_POST)) - inst |= 0x800; - - return push_inst(compiler, inst | VT(freg) | RN(mem & REG_MASK) | (sljit_ins)((memw & 0x1ff) << 12)); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_local_base(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw offset) -{ - sljit_s32 dst_reg; - sljit_ins ins; - - CHECK_ERROR(); - CHECK(check_sljit_get_local_base(compiler, dst, dstw, offset)); - ADJUST_LOCAL_OFFSET(SLJIT_MEM1(SLJIT_SP), offset); - - dst_reg = FAST_IS_REG(dst) ? dst : TMP_REG1; - - /* Not all instruction forms support accessing SP register. */ - if (offset <= 0xffffff && offset >= -0xffffff) { - ins = ADDI; - if (offset < 0) { - offset = -offset; - ins = SUBI; - } - - if (offset <= 0xfff) - FAIL_IF(push_inst(compiler, ins | RD(dst_reg) | RN(SLJIT_SP) | (sljit_ins)(offset << 10))); - else { - FAIL_IF(push_inst(compiler, ins | RD(dst_reg) | RN(SLJIT_SP) | (sljit_ins)((offset & 0xfff000) >> (12 - 10)) | (1 << 22))); - - offset &= 0xfff; - if (offset != 0) - FAIL_IF(push_inst(compiler, ins | RD(dst_reg) | RN(dst_reg) | (sljit_ins)(offset << 10))); - } - } - else { - FAIL_IF(load_immediate (compiler, dst_reg, offset)); - /* Add extended register form. */ - FAIL_IF(push_inst(compiler, ADDE | (0x3 << 13) | RD(dst_reg) | RN(SLJIT_SP) | RM(dst_reg))); - } - - if (SLJIT_UNLIKELY(dst & SLJIT_MEM)) - return emit_op_mem(compiler, WORD_SIZE | STORE, dst_reg, dst, dstw, TMP_REG1); - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value) -{ - struct sljit_const *const_; - sljit_s32 dst_r; - - CHECK_ERROR_PTR(); - 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_REG1; - PTR_FAIL_IF(emit_imm64_const(compiler, dst_r, (sljit_uw)init_value)); - - if (dst & SLJIT_MEM) - PTR_FAIL_IF(emit_op_mem(compiler, WORD_SIZE | STORE, dst_r, dst, dstw, TMP_REG2)); - return const_; -} - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label* sljit_emit_put_label(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw) -{ - struct sljit_put_label *put_label; - sljit_s32 dst_r; - - CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_put_label(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)); - - 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); - - if (dst & SLJIT_MEM) - PTR_FAIL_IF(emit_op_mem(compiler, WORD_SIZE | STORE, dst_r, dst, dstw, TMP_REG2)); - - return put_label; -} - -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset) -{ - sljit_ins* inst = (sljit_ins*)addr; - sljit_u32 dst; - SLJIT_UNUSED_ARG(executable_offset); - - SLJIT_UPDATE_WX_FLAGS(inst, inst + 4, 0); - - dst = inst[0] & 0x1f; - SLJIT_ASSERT((inst[0] & 0xffe00000) == MOVZ && (inst[1] & 0xffe00000) == (MOVK | (1 << 21))); - inst[0] = MOVZ | dst | (((sljit_u32)new_target & 0xffff) << 5); - inst[1] = MOVK | dst | (((sljit_u32)(new_target >> 16) & 0xffff) << 5) | (1 << 21); - inst[2] = MOVK | dst | (((sljit_u32)(new_target >> 32) & 0xffff) << 5) | (2 << 21); - inst[3] = MOVK | dst | ((sljit_u32)(new_target >> 48) << 5) | (3 << 21); - - SLJIT_UPDATE_WX_FLAGS(inst, inst + 4, 1); - inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset); - SLJIT_CACHE_FLUSH(inst, inst + 4); -} - -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset) -{ - sljit_set_jump_addr(addr, (sljit_uw)new_constant, executable_offset); -} diff --git a/modules/regex/pcre2/src/sljit/sljitNativeARM_T2_32.c b/modules/regex/pcre2/src/sljit/sljitNativeARM_T2_32.c deleted file mode 100644 index 7d6bac0..0000000 --- a/modules/regex/pcre2/src/sljit/sljitNativeARM_T2_32.c +++ /dev/null @@ -1,3150 +0,0 @@ -/* - * 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 const char* sljit_get_platform_name(void) -{ -#ifdef __SOFTFP__ - return "ARM-Thumb2" SLJIT_CPUINFO " ABI:softfp"; -#else - return "ARM-Thumb2" SLJIT_CPUINFO " ABI:hardfp"; -#endif -} - -/* Length of an instruction word. */ -typedef sljit_u32 sljit_ins; - -/* Last register + 1. */ -#define TMP_REG1 (SLJIT_NUMBER_OF_REGISTERS + 2) -#define TMP_REG2 (SLJIT_NUMBER_OF_REGISTERS + 3) -#define TMP_PC (SLJIT_NUMBER_OF_REGISTERS + 4) - -#define TMP_FREG1 (SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1) -#define TMP_FREG2 (SLJIT_NUMBER_OF_FLOAT_REGISTERS + 2) - -/* See sljit_emit_enter and sljit_emit_op0 if you want to change them. */ -static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 5] = { - 0, 0, 1, 2, 3, 11, 10, 9, 8, 7, 6, 5, 4, 13, 12, 14, 15 -}; - -static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 3] = { - 0, 0, 1, 2, 3, 4, 5, 15, 14, 13, 12, 11, 10, 9, 8, 6, 7 -}; - -#define COPY_BITS(src, from, to, bits) \ - ((from >= to ? ((sljit_ins)(src) >> (from - to)) : ((sljit_ins)(src) << (to - from))) & (((1 << bits) - 1) << to)) - -#define NEGATE(uimm) ((sljit_uw)-(sljit_sw)(uimm)) - -/* Thumb16 encodings. */ -#define RD3(rd) ((sljit_ins)reg_map[rd]) -#define RN3(rn) ((sljit_ins)reg_map[rn] << 3) -#define RM3(rm) ((sljit_ins)reg_map[rm] << 6) -#define RDN3(rdn) ((sljit_ins)reg_map[rdn] << 8) -#define IMM3(imm) ((sljit_ins)imm << 6) -#define IMM8(imm) ((sljit_ins)imm) - -/* Thumb16 helpers. */ -#define SET_REGS44(rd, rn) \ - (((sljit_ins)reg_map[rn] << 3) | ((sljit_ins)reg_map[rd] & 0x7) | (((sljit_ins)reg_map[rd] & 0x8) << 4)) -#define IS_2_LO_REGS(reg1, reg2) \ - (reg_map[reg1] <= 7 && reg_map[reg2] <= 7) -#define IS_3_LO_REGS(reg1, reg2, reg3) \ - (reg_map[reg1] <= 7 && reg_map[reg2] <= 7 && reg_map[reg3] <= 7) - -/* Thumb32 encodings. */ -#define RD4(rd) ((sljit_ins)reg_map[rd] << 8) -#define RN4(rn) ((sljit_ins)reg_map[rn] << 16) -#define RM4(rm) ((sljit_ins)reg_map[rm]) -#define RT4(rt) ((sljit_ins)reg_map[rt] << 12) -#define DD4(dd) ((sljit_ins)freg_map[dd] << 12) -#define DN4(dn) ((sljit_ins)freg_map[dn] << 16) -#define DM4(dm) ((sljit_ins)freg_map[dm]) -#define IMM5(imm) \ - (COPY_BITS(imm, 2, 12, 3) | (((sljit_ins)imm & 0x3) << 6)) -#define IMM12(imm) \ - (COPY_BITS(imm, 11, 26, 1) | COPY_BITS(imm, 8, 12, 3) | ((sljit_ins)imm & 0xff)) - -/* --------------------------------------------------------------------- */ -/* Instrucion forms */ -/* --------------------------------------------------------------------- */ - -/* dot '.' changed to _ - I immediate form (possibly followed by number of immediate bits). */ -#define ADCI 0xf1400000 -#define ADCS 0x4140 -#define ADC_W 0xeb400000 -#define ADD 0x4400 -#define ADDS 0x1800 -#define ADDSI3 0x1c00 -#define ADDSI8 0x3000 -#define ADDWI 0xf2000000 -#define ADD_SP 0x4485 -#define ADD_SP_I 0xb000 -#define ADD_W 0xeb000000 -#define ADD_WI 0xf1000000 -#define ANDI 0xf0000000 -#define ANDS 0x4000 -#define AND_W 0xea000000 -#define ASRS 0x4100 -#define ASRSI 0x1000 -#define ASR_W 0xfa40f000 -#define ASR_WI 0xea4f0020 -#define BCC 0xd000 -#define BICI 0xf0200000 -#define BKPT 0xbe00 -#define BLX 0x4780 -#define BX 0x4700 -#define CLZ 0xfab0f080 -#define CMNI_W 0xf1100f00 -#define CMP 0x4280 -#define CMPI 0x2800 -#define CMPI_W 0xf1b00f00 -#define CMP_X 0x4500 -#define CMP_W 0xebb00f00 -#define EORI 0xf0800000 -#define EORS 0x4040 -#define EOR_W 0xea800000 -#define IT 0xbf00 -#define LDR_SP 0x9800 -#define LDR 0xf8d00000 -#define LDRD 0xe9500000 -#define LDRI 0xf8500800 -#define LSLS 0x4080 -#define LSLSI 0x0000 -#define LSL_W 0xfa00f000 -#define LSL_WI 0xea4f0000 -#define LSRS 0x40c0 -#define LSRSI 0x0800 -#define LSR_W 0xfa20f000 -#define LSR_WI 0xea4f0010 -#define MOV 0x4600 -#define MOVS 0x0000 -#define MOVSI 0x2000 -#define MOVT 0xf2c00000 -#define MOVW 0xf2400000 -#define MOV_W 0xea4f0000 -#define MOV_WI 0xf04f0000 -#define MUL 0xfb00f000 -#define MVNS 0x43c0 -#define MVN_W 0xea6f0000 -#define MVN_WI 0xf06f0000 -#define NOP 0xbf00 -#define ORNI 0xf0600000 -#define ORRI 0xf0400000 -#define ORRS 0x4300 -#define ORR_W 0xea400000 -#define POP 0xbc00 -#define POP_W 0xe8bd0000 -#define PUSH 0xb400 -#define PUSH_W 0xe92d0000 -#define RBIT 0xfa90f0a0 -#define RORS 0x41c0 -#define ROR_W 0xfa60f000 -#define ROR_WI 0xea4f0030 -#define RSB_WI 0xf1c00000 -#define RSBSI 0x4240 -#define SBCI 0xf1600000 -#define SBCS 0x4180 -#define SBC_W 0xeb600000 -#define SDIV 0xfb90f0f0 -#define SMULL 0xfb800000 -#define STRD 0xe9400000 -#define STR_SP 0x9000 -#define SUBS 0x1a00 -#define SUBSI3 0x1e00 -#define SUBSI8 0x3800 -#define SUB_W 0xeba00000 -#define SUBWI 0xf2a00000 -#define SUB_SP_I 0xb080 -#define SUB_WI 0xf1a00000 -#define SXTB 0xb240 -#define SXTB_W 0xfa4ff080 -#define SXTH 0xb200 -#define SXTH_W 0xfa0ff080 -#define TST 0x4200 -#define TSTI 0xf0000f00 -#define TST_W 0xea000f00 -#define UDIV 0xfbb0f0f0 -#define UMULL 0xfba00000 -#define UXTB 0xb2c0 -#define UXTB_W 0xfa5ff080 -#define UXTH 0xb280 -#define UXTH_W 0xfa1ff080 -#define VABS_F32 0xeeb00ac0 -#define VADD_F32 0xee300a00 -#define VCMP_F32 0xeeb40a40 -#define VCVT_F32_S32 0xeeb80ac0 -#define VCVT_F64_F32 0xeeb70ac0 -#define VCVT_S32_F32 0xeebd0ac0 -#define VDIV_F32 0xee800a00 -#define VLDR_F32 0xed100a00 -#define VMOV_F32 0xeeb00a40 -#define VMOV 0xee000a10 -#define VMOV2 0xec400a10 -#define VMRS 0xeef1fa10 -#define VMUL_F32 0xee200a00 -#define VNEG_F32 0xeeb10a40 -#define VPOP 0xecbd0b00 -#define VPUSH 0xed2d0b00 -#define VSTR_F32 0xed000a00 -#define VSUB_F32 0xee300a40 - -static sljit_s32 push_inst16(struct sljit_compiler *compiler, sljit_ins inst) -{ - sljit_u16 *ptr; - SLJIT_ASSERT(!(inst & 0xffff0000)); - - ptr = (sljit_u16*)ensure_buf(compiler, sizeof(sljit_u16)); - FAIL_IF(!ptr); - *ptr = (sljit_u16)(inst); - compiler->size++; - return SLJIT_SUCCESS; -} - -static sljit_s32 push_inst32(struct sljit_compiler *compiler, sljit_ins inst) -{ - sljit_u16 *ptr = (sljit_u16*)ensure_buf(compiler, sizeof(sljit_ins)); - FAIL_IF(!ptr); - *ptr++ = (sljit_u16)(inst >> 16); - *ptr = (sljit_u16)(inst); - compiler->size += 2; - return SLJIT_SUCCESS; -} - -static SLJIT_INLINE 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))); - return push_inst32(compiler, MOVT | RD4(dst) - | 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) -{ - 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) -{ - sljit_sw diff; - - if (jump->flags & SLJIT_REWRITABLE_JUMP) - return 0; - - 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; - } - - if (jump->flags & IS_COND) { - SLJIT_ASSERT(!(jump->flags & IS_BL)); - if (diff <= 127 && diff >= -128) { - jump->flags |= PATCH_TYPE1; - return 5; - } - if (diff <= 524287 && diff >= -524288) { - jump->flags |= PATCH_TYPE2; - return 4; - } - /* +1 comes from the prefix IT instruction. */ - diff--; - if (diff <= 8388607 && diff >= -8388608) { - jump->flags |= PATCH_TYPE3; - return 3; - } - } - else if (jump->flags & IS_BL) { - if (diff <= 8388607 && diff >= -8388608) { - jump->flags |= PATCH_BL; - return 3; - } - } - else { - if (diff <= 1023 && diff >= -1024) { - jump->flags |= PATCH_TYPE4; - return 4; - } - if (diff <= 8388607 && diff >= -8388608) { - jump->flags |= PATCH_TYPE5; - return 3; - } - } - - return 0; -} - -static SLJIT_INLINE void set_jump_instruction(struct sljit_jump *jump, sljit_sw executable_offset) -{ - sljit_s32 type = (jump->flags >> 4) & 0xf; - sljit_sw diff; - sljit_u16 *jump_inst; - sljit_s32 s, j1, j2; - - if (SLJIT_UNLIKELY(type == 0)) { - modify_imm32_const((sljit_u16*)jump->addr, (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target); - 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; - } - jump_inst = (sljit_u16*)jump->addr; - - switch (type) { - case 1: - /* Encoding T1 of 'B' instruction */ - SLJIT_ASSERT(diff <= 127 && diff >= -128 && (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)); - 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)); - jump_inst[0] = (sljit_u16)(0xe000 | (diff & 0x7ff)); - return; - } - - SLJIT_ASSERT(diff <= 8388607 && diff >= -8388608); - - /* 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)); - - /* The others have a common form. */ - if (type == 5) /* Encoding T4 of 'B' instruction */ - jump_inst[1] |= 0x9000; - else if (type == 6) /* Encoding T1 of 'BL' instruction */ - jump_inst[1] |= 0xd000; - else - SLJIT_UNREACHABLE(); -} - -SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler) -{ - struct sljit_memory_fragment *buf; - sljit_u16 *code; - sljit_u16 *code_ptr; - sljit_u16 *buf_ptr; - sljit_u16 *buf_end; - sljit_uw half_count; - sljit_uw next_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); - PTR_FAIL_WITH_EXEC_IF(code); - 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; - - 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) { - 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; - label->size = (sljit_uw)(code_ptr - code); - label = label->next; - } - 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) { - const_->addr = (sljit_uw)code_ptr; - const_ = const_->next; - } - 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); - } - code_ptr++; - half_count++; - } while (buf_ptr < buf_end); - - buf = buf->next; - } while (buf); - - if (label && label->size == half_count) { - label->addr = ((sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset)) | 0x1; - label->size = (sljit_uw)(code_ptr - code); - label = label->next; - } - - 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); - 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); - - 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); - - /* Set thumb mode flag. */ - return (void*)((sljit_uw)code | 0x1); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type) -{ - switch (feature_type) { - case SLJIT_HAS_FPU: -#ifdef SLJIT_IS_FPU_AVAILABLE - return SLJIT_IS_FPU_AVAILABLE; -#else - /* Available by default. */ - return 1; -#endif - - case SLJIT_HAS_CLZ: - case SLJIT_HAS_CTZ: - case SLJIT_HAS_ROT: - case SLJIT_HAS_CMOV: - case SLJIT_HAS_PREFETCH: - return 1; - - default: - return 0; - } -} - -/* --------------------------------------------------------------------- */ -/* Core code generator functions. */ -/* --------------------------------------------------------------------- */ - -#define INVALID_IMM 0x80000000 -static sljit_uw get_imm(sljit_uw imm) -{ - /* Thumb immediate form. */ - sljit_s32 counter; - - if (imm <= 0xff) - return imm; - - if ((imm & 0xffff) == (imm >> 16)) { - /* Some special cases. */ - if (!(imm & 0xff00)) - return (1 << 12) | (imm & 0xff); - if (!(imm & 0xff)) - return (2 << 12) | ((imm >> 8) & 0xff); - if ((imm & 0xff00) == ((imm & 0xff) << 8)) - return (3 << 12) | (imm & 0xff); - } - - /* Assembly optimization: count leading zeroes? */ - counter = 8; - if (!(imm & 0xffff0000)) { - counter += 16; - imm <<= 16; - } - if (!(imm & 0xff000000)) { - counter += 8; - imm <<= 8; - } - if (!(imm & 0xf0000000)) { - counter += 4; - imm <<= 4; - } - if (!(imm & 0xc0000000)) { - counter += 2; - imm <<= 2; - } - if (!(imm & 0x80000000)) { - counter += 1; - imm <<= 1; - } - /* Since imm >= 128, this must be true. */ - SLJIT_ASSERT(counter <= 31); - - if (imm & 0x00ffffff) - return INVALID_IMM; /* Cannot be encoded. */ - - return ((imm >> 24) & 0x7f) | COPY_BITS(counter, 4, 26, 1) | COPY_BITS(counter, 1, 12, 3) | COPY_BITS(counter, 0, 7, 1); -} - -static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst, sljit_uw imm) -{ - sljit_uw tmp; - - /* MOVS cannot be used since it destroy flags. */ - - if (imm >= 0x10000) { - tmp = get_imm(imm); - if (tmp != INVALID_IMM) - return push_inst32(compiler, MOV_WI | RD4(dst) | tmp); - tmp = get_imm(~imm); - if (tmp != INVALID_IMM) - return push_inst32(compiler, MVN_WI | RD4(dst) | tmp); - } - - /* set low 16 bits, set hi 16 bits to 0. */ - 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))); - - /* set hi 16 bit if needed. */ - if (imm >= 0x10000) - return push_inst32(compiler, MOVT | RD4(dst) - | COPY_BITS(imm, 12 + 16, 16, 4) | COPY_BITS(imm, 11 + 16, 26, 1) | COPY_BITS(imm, 8 + 16, 12, 3) | ((imm & 0xff0000) >> 16)); - return SLJIT_SUCCESS; -} - -#define ARG1_IMM 0x0010000 -#define ARG2_IMM 0x0020000 -/* 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 - -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 - arg1 must be register, imm - arg2 must be register, imm */ - sljit_s32 reg; - sljit_uw imm, imm2; - - if (SLJIT_UNLIKELY((flags & (ARG1_IMM | ARG2_IMM)) == (ARG1_IMM | ARG2_IMM))) { - /* Both are immediates, no temporaries are used. */ - flags &= ~ARG1_IMM; - FAIL_IF(load_immediate(compiler, TMP_REG1, arg1)); - arg1 = TMP_REG1; - } - - if (flags & (ARG1_IMM | ARG2_IMM)) { - reg = (sljit_s32)((flags & ARG2_IMM) ? arg1 : arg2); - imm = (flags & ARG2_IMM) ? arg2 : arg1; - - switch (flags & 0xffff) { - case SLJIT_CLZ: - case SLJIT_CTZ: - case SLJIT_MUL: - /* No form with immediate operand. */ - break; - case SLJIT_MOV: - SLJIT_ASSERT(!(flags & SET_FLAGS) && (flags & ARG2_IMM) && arg1 == TMP_REG2); - return load_immediate(compiler, dst, imm); - case SLJIT_NOT: - if (!(flags & SET_FLAGS)) - return load_immediate(compiler, dst, ~imm); - /* Since the flags should be set, we just fallback to the register mode. - Although some clever things could be done here, "NOT IMM" does not worth the efforts. */ - break; - case SLJIT_ADD: - compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD; - imm2 = NEGATE(imm); - if (IS_2_LO_REGS(reg, dst)) { - if (imm <= 0x7) - return push_inst16(compiler, ADDSI3 | IMM3(imm) | RD3(dst) | RN3(reg)); - if (imm2 <= 0x7) - return push_inst16(compiler, SUBSI3 | IMM3(imm2) | RD3(dst) | RN3(reg)); - if (reg == dst) { - if (imm <= 0xff) - return push_inst16(compiler, ADDSI8 | IMM8(imm) | RDN3(dst)); - if (imm2 <= 0xff) - return push_inst16(compiler, SUBSI8 | IMM8(imm2) | RDN3(dst)); - } - } - if (!(flags & SET_FLAGS)) { - if (imm <= 0xfff) - return push_inst32(compiler, ADDWI | RD4(dst) | RN4(reg) | IMM12(imm)); - if (imm2 <= 0xfff) - return push_inst32(compiler, SUBWI | RD4(dst) | RN4(reg) | IMM12(imm2)); - } - imm2 = get_imm(imm); - if (imm2 != INVALID_IMM) - return push_inst32(compiler, ADD_WI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | imm2); - imm = get_imm(NEGATE(imm)); - if (imm != INVALID_IMM) - return push_inst32(compiler, SUB_WI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | imm); - break; - case SLJIT_ADDC: - compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD; - imm = get_imm(imm); - if (imm != INVALID_IMM) - return push_inst32(compiler, ADCI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | imm); - break; - case SLJIT_SUB: - compiler->status_flags_state = SLJIT_CURRENT_FLAGS_SUB; - if (flags & ARG1_IMM) { - if (imm == 0 && IS_2_LO_REGS(reg, dst)) - return push_inst16(compiler, RSBSI | RD3(dst) | RN3(reg)); - imm = get_imm(imm); - if (imm != INVALID_IMM) - return push_inst32(compiler, RSB_WI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | imm); - break; - } - if (flags & UNUSED_RETURN) { - if (imm <= 0xff && reg_map[reg] <= 7) - return push_inst16(compiler, CMPI | IMM8(imm) | RDN3(reg)); - imm2 = get_imm(imm); - if (imm2 != INVALID_IMM) - return push_inst32(compiler, CMPI_W | RN4(reg) | imm2); - imm = get_imm(NEGATE(imm)); - if (imm != INVALID_IMM) - return push_inst32(compiler, CMNI_W | RN4(reg) | imm); - break; - } - imm2 = NEGATE(imm); - if (IS_2_LO_REGS(reg, dst)) { - if (imm <= 0x7) - return push_inst16(compiler, SUBSI3 | IMM3(imm) | RD3(dst) | RN3(reg)); - if (imm2 <= 0x7) - return push_inst16(compiler, ADDSI3 | IMM3(imm2) | RD3(dst) | RN3(reg)); - if (reg == dst) { - if (imm <= 0xff) - return push_inst16(compiler, SUBSI8 | IMM8(imm) | RDN3(dst)); - if (imm2 <= 0xff) - return push_inst16(compiler, ADDSI8 | IMM8(imm2) | RDN3(dst)); - } - } - if (!(flags & SET_FLAGS)) { - if (imm <= 0xfff) - return push_inst32(compiler, SUBWI | RD4(dst) | RN4(reg) | IMM12(imm)); - if (imm2 <= 0xfff) - return push_inst32(compiler, ADDWI | RD4(dst) | RN4(reg) | IMM12(imm2)); - } - imm2 = get_imm(imm); - if (imm2 != INVALID_IMM) - return push_inst32(compiler, SUB_WI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | imm2); - imm = get_imm(NEGATE(imm)); - if (imm != INVALID_IMM) - return push_inst32(compiler, ADD_WI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | imm); - break; - case SLJIT_SUBC: - compiler->status_flags_state = SLJIT_CURRENT_FLAGS_SUB; - if (flags & ARG1_IMM) - break; - imm = get_imm(imm); - if (imm != INVALID_IMM) - return push_inst32(compiler, SBCI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | imm); - break; - case SLJIT_AND: - imm2 = get_imm(imm); - if (imm2 != INVALID_IMM) - return push_inst32(compiler, ((flags & UNUSED_RETURN) ? TSTI : ANDI) | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | imm2); - imm = get_imm(~imm); - if (imm != INVALID_IMM) - return push_inst32(compiler, BICI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | imm); - break; - case SLJIT_OR: - imm2 = get_imm(imm); - if (imm2 != INVALID_IMM) - return push_inst32(compiler, ORRI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | imm2); - imm = get_imm(~imm); - if (imm != INVALID_IMM) - return push_inst32(compiler, ORNI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | imm); - break; - case SLJIT_XOR: - imm = get_imm(imm); - if (imm != INVALID_IMM) - return push_inst32(compiler, EORI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | imm); - break; - case SLJIT_SHL: - case SLJIT_MSHL: - case SLJIT_LSHR: - case SLJIT_MLSHR: - case SLJIT_ASHR: - case SLJIT_MASHR: - case SLJIT_ROTL: - case SLJIT_ROTR: - if (flags & ARG1_IMM) - break; - imm &= 0x1f; - - if (imm == 0) { - if (!(flags & SET_FLAGS)) - return push_inst16(compiler, MOV | SET_REGS44(dst, reg)); - if (IS_2_LO_REGS(dst, reg)) - return push_inst16(compiler, MOVS | RD3(dst) | RN3(reg)); - return push_inst32(compiler, MOV_W | SET_FLAGS | RD4(dst) | RM4(reg)); - } - - switch (flags & 0xffff) { - case SLJIT_SHL: - case SLJIT_MSHL: - if (IS_2_LO_REGS(dst, reg)) - return push_inst16(compiler, LSLSI | RD3(dst) | RN3(reg) | (imm << 6)); - return push_inst32(compiler, LSL_WI | (flags & SET_FLAGS) | RD4(dst) | RM4(reg) | IMM5(imm)); - case SLJIT_LSHR: - case SLJIT_MLSHR: - if (IS_2_LO_REGS(dst, reg)) - return push_inst16(compiler, LSRSI | RD3(dst) | RN3(reg) | (imm << 6)); - return push_inst32(compiler, LSR_WI | (flags & SET_FLAGS) | RD4(dst) | RM4(reg) | IMM5(imm)); - case SLJIT_ASHR: - case SLJIT_MASHR: - if (IS_2_LO_REGS(dst, reg)) - return push_inst16(compiler, ASRSI | RD3(dst) | RN3(reg) | (imm << 6)); - return push_inst32(compiler, ASR_WI | (flags & SET_FLAGS) | RD4(dst) | RM4(reg) | IMM5(imm)); - case SLJIT_ROTL: - imm = (imm ^ 0x1f) + 1; - /* fallthrough */ - default: /* SLJIT_ROTR */ - return push_inst32(compiler, ROR_WI | RD4(dst) | RM4(reg) | IMM5(imm)); - } - default: - SLJIT_UNREACHABLE(); - break; - } - - if (flags & ARG2_IMM) { - imm = arg2; - arg2 = (arg1 == TMP_REG1) ? TMP_REG2 : TMP_REG1; - FAIL_IF(load_immediate(compiler, (sljit_s32)arg2, imm)); - } - else { - imm = arg1; - arg1 = (arg2 == TMP_REG1) ? TMP_REG2 : TMP_REG1; - FAIL_IF(load_immediate(compiler, (sljit_s32)arg1, imm)); - } - - SLJIT_ASSERT(arg1 != arg2); - } - - /* Both arguments are registers. */ - switch (flags & 0xffff) { - case SLJIT_MOV: - case SLJIT_MOV_U32: - case SLJIT_MOV_S32: - case SLJIT_MOV32: - case SLJIT_MOV_P: - SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG2); - if (dst == (sljit_s32)arg2) - return SLJIT_SUCCESS; - return push_inst16(compiler, MOV | SET_REGS44(dst, arg2)); - case SLJIT_MOV_U8: - SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG2); - if (IS_2_LO_REGS(dst, arg2)) - return push_inst16(compiler, UXTB | RD3(dst) | RN3(arg2)); - return push_inst32(compiler, UXTB_W | RD4(dst) | RM4(arg2)); - case SLJIT_MOV_S8: - SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG2); - if (IS_2_LO_REGS(dst, arg2)) - return push_inst16(compiler, SXTB | RD3(dst) | RN3(arg2)); - return push_inst32(compiler, SXTB_W | RD4(dst) | RM4(arg2)); - case SLJIT_MOV_U16: - SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG2); - if (IS_2_LO_REGS(dst, arg2)) - return push_inst16(compiler, UXTH | RD3(dst) | RN3(arg2)); - return push_inst32(compiler, UXTH_W | RD4(dst) | RM4(arg2)); - case SLJIT_MOV_S16: - SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG2); - if (IS_2_LO_REGS(dst, arg2)) - return push_inst16(compiler, SXTH | RD3(dst) | RN3(arg2)); - return push_inst32(compiler, SXTH_W | RD4(dst) | RM4(arg2)); - case SLJIT_NOT: - SLJIT_ASSERT(arg1 == TMP_REG2); - if (IS_2_LO_REGS(dst, arg2)) - return push_inst16(compiler, MVNS | RD3(dst) | RN3(arg2)); - return push_inst32(compiler, MVN_W | (flags & SET_FLAGS) | RD4(dst) | RM4(arg2)); - case SLJIT_CLZ: - SLJIT_ASSERT(arg1 == TMP_REG2); - return push_inst32(compiler, CLZ | RN4(arg2) | RD4(dst) | RM4(arg2)); - case SLJIT_CTZ: - SLJIT_ASSERT(arg1 == TMP_REG2); - FAIL_IF(push_inst32(compiler, RBIT | RN4(arg2) | RD4(dst) | RM4(arg2))); - return push_inst32(compiler, CLZ | RN4(dst) | RD4(dst) | RM4(dst)); - case SLJIT_ADD: - compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD; - if (IS_3_LO_REGS(dst, arg1, arg2)) - return push_inst16(compiler, ADDS | RD3(dst) | RN3(arg1) | RM3(arg2)); - if (dst == (sljit_s32)arg1 && !(flags & SET_FLAGS)) - return push_inst16(compiler, ADD | SET_REGS44(dst, arg2)); - return push_inst32(compiler, ADD_W | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2)); - case SLJIT_ADDC: - compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD; - if (dst == (sljit_s32)arg1 && IS_2_LO_REGS(dst, arg2)) - return push_inst16(compiler, ADCS | RD3(dst) | RN3(arg2)); - return push_inst32(compiler, ADC_W | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2)); - case SLJIT_SUB: - compiler->status_flags_state = SLJIT_CURRENT_FLAGS_SUB; - if (flags & UNUSED_RETURN) { - if (IS_2_LO_REGS(arg1, arg2)) - return push_inst16(compiler, CMP | RD3(arg1) | RN3(arg2)); - return push_inst16(compiler, CMP_X | SET_REGS44(arg1, arg2)); - } - if (IS_3_LO_REGS(dst, arg1, arg2)) - return push_inst16(compiler, SUBS | RD3(dst) | RN3(arg1) | RM3(arg2)); - return push_inst32(compiler, SUB_W | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2)); - case SLJIT_SUBC: - compiler->status_flags_state = SLJIT_CURRENT_FLAGS_SUB; - if (dst == (sljit_s32)arg1 && IS_2_LO_REGS(dst, arg2)) - return push_inst16(compiler, SBCS | RD3(dst) | RN3(arg2)); - return push_inst32(compiler, SBC_W | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2)); - case SLJIT_MUL: - 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))); - /* cmp TMP_REG2, dst asr #31. */ - return push_inst32(compiler, CMP_W | RN4(TMP_REG2) | 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)); - if ((flags & UNUSED_RETURN) && IS_2_LO_REGS(arg1, arg2)) - return push_inst16(compiler, TST | RD3(arg1) | RN3(arg2)); - return push_inst32(compiler, ((flags & UNUSED_RETURN) ? TST_W : AND_W) | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2)); - case SLJIT_OR: - if (dst == (sljit_s32)arg1 && IS_2_LO_REGS(dst, arg2)) - return push_inst16(compiler, ORRS | RD3(dst) | RN3(arg2)); - return push_inst32(compiler, ORR_W | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2)); - case SLJIT_XOR: - if (dst == (sljit_s32)arg1 && IS_2_LO_REGS(dst, arg2)) - 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; - /* 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; - /* 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; - /* 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; - /* 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)); - } - - SLJIT_UNREACHABLE(); - return SLJIT_SUCCESS; -} - -#define STORE 0x01 -#define SIGNED 0x02 - -#define WORD_SIZE 0x00 -#define BYTE_SIZE 0x04 -#define HALF_SIZE 0x08 -#define PRELOAD 0x0c - -#define IS_WORD_SIZE(flags) (!((flags) & (BYTE_SIZE | HALF_SIZE))) -#define ALIGN_CHECK(argw, imm, shift) (!((argw) & ~((imm) << (shift)))) - -/* - 1st letter: - w = word - b = byte - h = half - - 2nd letter: - s = signed - u = unsigned - - 3rd letter: - l = load - s = store -*/ - -static const sljit_ins sljit_mem16[12] = { -/* w u l */ 0x5800 /* ldr */, -/* w u s */ 0x5000 /* str */, -/* w s l */ 0x5800 /* ldr */, -/* w s s */ 0x5000 /* str */, - -/* b u l */ 0x5c00 /* ldrb */, -/* b u s */ 0x5400 /* strb */, -/* b s l */ 0x5600 /* ldrsb */, -/* b s s */ 0x5400 /* strb */, - -/* h u l */ 0x5a00 /* ldrh */, -/* h u s */ 0x5200 /* strh */, -/* h s l */ 0x5e00 /* ldrsh */, -/* h s s */ 0x5200 /* strh */, -}; - -static const sljit_ins sljit_mem16_imm5[12] = { -/* w u l */ 0x6800 /* ldr imm5 */, -/* w u s */ 0x6000 /* str imm5 */, -/* w s l */ 0x6800 /* ldr imm5 */, -/* w s s */ 0x6000 /* str imm5 */, - -/* b u l */ 0x7800 /* ldrb imm5 */, -/* b u s */ 0x7000 /* strb imm5 */, -/* b s l */ 0x0000 /* not allowed */, -/* b s s */ 0x7000 /* strb imm5 */, - -/* h u l */ 0x8800 /* ldrh imm5 */, -/* h u s */ 0x8000 /* strh imm5 */, -/* h s l */ 0x0000 /* not allowed */, -/* h s s */ 0x8000 /* strh imm5 */, -}; - -#define MEM_IMM8 0xc00 -#define MEM_IMM12 0x800000 -static const sljit_ins sljit_mem32[13] = { -/* w u l */ 0xf8500000 /* ldr.w */, -/* w u s */ 0xf8400000 /* str.w */, -/* w s l */ 0xf8500000 /* ldr.w */, -/* w s s */ 0xf8400000 /* str.w */, - -/* b u l */ 0xf8100000 /* ldrb.w */, -/* b u s */ 0xf8000000 /* strb.w */, -/* b s l */ 0xf9100000 /* ldrsb.w */, -/* b s s */ 0xf8000000 /* strb.w */, - -/* h u l */ 0xf8300000 /* ldrh.w */, -/* h u s */ 0xf8200000 /* strsh.w */, -/* h s l */ 0xf9300000 /* ldrsh.w */, -/* h s s */ 0xf8200000 /* strsh.w */, - -/* p u l */ 0xf8100000 /* pld */, -}; - -/* Helper function. Dst should be reg + value, using at most 1 instruction, flags does not set. */ -static sljit_s32 emit_set_delta(struct sljit_compiler *compiler, sljit_s32 dst, sljit_s32 reg, sljit_sw value) -{ - sljit_uw imm; - - if (value >= 0) { - if (value <= 0xfff) - return push_inst32(compiler, ADDWI | RD4(dst) | RN4(reg) | IMM12(value)); - imm = get_imm((sljit_uw)value); - if (imm != INVALID_IMM) - return push_inst32(compiler, ADD_WI | RD4(dst) | RN4(reg) | imm); - } - else { - value = -value; - if (value <= 0xfff) - return push_inst32(compiler, SUBWI | RD4(dst) | RN4(reg) | IMM12(value)); - imm = get_imm((sljit_uw)value); - if (imm != INVALID_IMM) - return push_inst32(compiler, SUB_WI | RD4(dst) | RN4(reg) | imm); - } - return SLJIT_ERR_UNSUPPORTED; -} - -static SLJIT_INLINE 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) -{ - sljit_s32 other_r; - sljit_uw imm, tmp; - - SLJIT_ASSERT(arg & SLJIT_MEM); - SLJIT_ASSERT((arg & REG_MASK) != tmp_reg || (arg == SLJIT_MEM1(tmp_reg) && argw >= -0xff && argw <= 0xfff)); - - if (SLJIT_UNLIKELY(!(arg & REG_MASK))) { - imm = get_imm((sljit_uw)argw & ~(sljit_uw)0xfff); - if (imm != INVALID_IMM) { - FAIL_IF(push_inst32(compiler, MOV_WI | RD4(tmp_reg) | imm)); - return push_inst32(compiler, sljit_mem32[flags] | MEM_IMM12 | RT4(reg) | RN4(tmp_reg) | (argw & 0xfff)); - } - - FAIL_IF(load_immediate(compiler, tmp_reg, (sljit_uw)argw)); - if (IS_2_LO_REGS(reg, tmp_reg) && sljit_mem16_imm5[flags]) - return push_inst16(compiler, sljit_mem16_imm5[flags] | RD3(reg) | RN3(tmp_reg)); - return push_inst32(compiler, sljit_mem32[flags] | MEM_IMM12 | RT4(reg) | RN4(tmp_reg)); - } - - if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) { - argw &= 0x3; - other_r = OFFS_REG(arg); - arg &= REG_MASK; - - if (!argw && IS_3_LO_REGS(reg, arg, other_r)) - return push_inst16(compiler, sljit_mem16[flags] | RD3(reg) | RN3(arg) | RM3(other_r)); - return push_inst32(compiler, sljit_mem32[flags] | RT4(reg) | RN4(arg) | RM4(other_r) | ((sljit_ins)argw << 4)); - } - - arg &= REG_MASK; - - if (argw > 0xfff) { - imm = get_imm((sljit_uw)(argw & ~0xfff)); - if (imm != INVALID_IMM) { - push_inst32(compiler, ADD_WI | RD4(tmp_reg) | RN4(arg) | imm); - arg = tmp_reg; - argw = argw & 0xfff; - } - } - else if (argw < -0xff) { - tmp = (sljit_uw)((-argw + 0xfff) & ~0xfff); - SLJIT_ASSERT(tmp >= (sljit_uw)-argw); - imm = get_imm(tmp); - - if (imm != INVALID_IMM) { - push_inst32(compiler, SUB_WI | RD4(tmp_reg) | RN4(arg) | imm); - arg = tmp_reg; - argw += (sljit_sw)tmp; - - SLJIT_ASSERT(argw >= 0 && argw <= 0xfff); - } - } - - /* 16 bit instruction forms. */ - if (IS_2_LO_REGS(reg, arg) && sljit_mem16_imm5[flags]) { - tmp = 3; - if (IS_WORD_SIZE(flags)) { - if (ALIGN_CHECK(argw, 0x1f, 2)) - tmp = 2; - } - else if (flags & BYTE_SIZE) - { - if (ALIGN_CHECK(argw, 0x1f, 0)) - tmp = 0; - } - else { - SLJIT_ASSERT(flags & HALF_SIZE); - if (ALIGN_CHECK(argw, 0x1f, 1)) - tmp = 1; - } - - if (tmp < 3) - return push_inst16(compiler, sljit_mem16_imm5[flags] | RD3(reg) | RN3(arg) | ((sljit_ins)argw << (6 - tmp))); - } - else if (SLJIT_UNLIKELY(arg == SLJIT_SP) && IS_WORD_SIZE(flags) && ALIGN_CHECK(argw, 0xff, 2) && reg_map[reg] <= 7) { - /* SP based immediate. */ - return push_inst16(compiler, STR_SP | (sljit_ins)((flags & STORE) ? 0 : 0x800) | RDN3(reg) | ((sljit_ins)argw >> 2)); - } - - if (argw >= 0 && argw <= 0xfff) - return push_inst32(compiler, sljit_mem32[flags] | MEM_IMM12 | RT4(reg) | RN4(arg) | (sljit_ins)argw); - else if (argw < 0 && argw >= -0xff) - return push_inst32(compiler, sljit_mem32[flags] | MEM_IMM8 | RT4(reg) | RN4(arg) | (sljit_ins)-argw); - - SLJIT_ASSERT(arg != tmp_reg); - - FAIL_IF(load_immediate(compiler, tmp_reg, (sljit_uw)argw)); - if (IS_3_LO_REGS(reg, arg, tmp_reg)) - return push_inst16(compiler, sljit_mem16[flags] | RD3(reg) | RN3(arg) | RM3(tmp_reg)); - return push_inst32(compiler, sljit_mem32[flags] | RT4(reg) | RN4(arg) | RM4(tmp_reg)); -} - -#undef ALIGN_CHECK -#undef IS_WORD_SIZE - -/* --------------------------------------------------------------------- */ -/* Entry, exit */ -/* --------------------------------------------------------------------- */ - -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, - sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size) -{ - sljit_s32 size, i, tmp, word_arg_count; - sljit_s32 saved_arg_count = SLJIT_KEPT_SAVEDS_COUNT(options); - sljit_uw offset; - sljit_uw imm = 0; -#ifdef __SOFTFP__ - sljit_u32 float_arg_count; -#else - sljit_u32 old_offset, f32_offset; - sljit_u32 remap[3]; - sljit_u32 *remap_ptr = remap; -#endif - - CHECK_ERROR(); - CHECK(check_sljit_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size)); - set_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size); - - tmp = SLJIT_S0 - saveds; - for (i = SLJIT_S0 - saved_arg_count; i > tmp; i--) - imm |= (sljit_uw)1 << reg_map[i]; - - for (i = scratches; i >= SLJIT_FIRST_SAVED_REG; i--) - imm |= (sljit_uw)1 << reg_map[i]; - - /* At least two registers must be set for PUSH_W and one for PUSH instruction. */ - FAIL_IF((imm & 0xff00) - ? push_inst32(compiler, PUSH_W | (1 << 14) | imm) - : push_inst16(compiler, PUSH | (1 << 8) | imm)); - - /* Stack must be aligned to 8 bytes: (LR, R4) */ - size = GET_SAVED_REGISTERS_SIZE(scratches, saveds - saved_arg_count, 1); - - if (fsaveds > 0 || fscratches >= SLJIT_FIRST_SAVED_FLOAT_REG) { - if ((size & SSIZE_OF(sw)) != 0) { - FAIL_IF(push_inst16(compiler, SUB_SP_I | (sizeof(sljit_sw) >> 2))); - size += SSIZE_OF(sw); - } - - if (fsaveds + fscratches >= SLJIT_NUMBER_OF_FLOAT_REGISTERS) { - FAIL_IF(push_inst32(compiler, VPUSH | DD4(SLJIT_FS0) | ((sljit_uw)SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS << 1))); - } else { - if (fsaveds > 0) - FAIL_IF(push_inst32(compiler, VPUSH | DD4(SLJIT_FS0) | ((sljit_uw)fsaveds << 1))); - if (fscratches >= SLJIT_FIRST_SAVED_FLOAT_REG) - FAIL_IF(push_inst32(compiler, VPUSH | DD4(fscratches) | ((sljit_uw)(fscratches - (SLJIT_FIRST_SAVED_FLOAT_REG - 1)) << 1))); - } - } - - local_size = ((size + local_size + 0x7) & ~0x7) - size; - compiler->local_size = local_size; - - if (options & SLJIT_ENTER_REG_ARG) - arg_types = 0; - - arg_types >>= SLJIT_ARG_SHIFT; - word_arg_count = 0; - saved_arg_count = 0; -#ifdef __SOFTFP__ - SLJIT_COMPILE_ASSERT(SLJIT_FR0 == 1, float_register_index_start); - - offset = 0; - float_arg_count = 0; - - while (arg_types) { - switch (arg_types & SLJIT_ARG_MASK) { - case SLJIT_ARG_TYPE_F64: - if (offset & 0x7) - offset += sizeof(sljit_sw); - - if (offset < 4 * sizeof(sljit_sw)) - FAIL_IF(push_inst32(compiler, VMOV2 | (offset << 10) | ((offset + sizeof(sljit_sw)) << 14) | float_arg_count)); - else - FAIL_IF(push_inst32(compiler, VLDR_F32 | 0x800100 | RN4(SLJIT_SP) - | (float_arg_count << 12) | ((offset + (sljit_uw)size - 4 * sizeof(sljit_sw)) >> 2))); - float_arg_count++; - offset += sizeof(sljit_f64) - sizeof(sljit_sw); - break; - case SLJIT_ARG_TYPE_F32: - if (offset < 4 * sizeof(sljit_sw)) - FAIL_IF(push_inst32(compiler, VMOV | (float_arg_count << 16) | (offset << 10))); - else - FAIL_IF(push_inst32(compiler, VLDR_F32 | 0x800000 | RN4(SLJIT_SP) - | (float_arg_count << 12) | ((offset + (sljit_uw)size - 4 * sizeof(sljit_sw)) >> 2))); - float_arg_count++; - break; - default: - word_arg_count++; - - if (!(arg_types & SLJIT_ARG_TYPE_SCRATCH_REG)) { - tmp = SLJIT_S0 - saved_arg_count; - saved_arg_count++; - } else if (word_arg_count - 1 != (sljit_s32)(offset >> 2)) - tmp = word_arg_count; - else - break; - - if (offset < 4 * sizeof(sljit_sw)) - FAIL_IF(push_inst16(compiler, MOV | ((sljit_ins)reg_map[tmp] & 0x7) | (((sljit_ins)reg_map[tmp] & 0x8) << 4) | (offset << 1))); - else if (reg_map[tmp] <= 7) - FAIL_IF(push_inst16(compiler, LDR_SP | RDN3(tmp) - | ((offset + (sljit_uw)size - 4 * sizeof(sljit_sw)) >> 2))); - else - FAIL_IF(push_inst32(compiler, LDR | RT4(tmp) | RN4(SLJIT_SP) - | ((offset + (sljit_uw)size - 4 * sizeof(sljit_sw))))); - break; - } - - offset += sizeof(sljit_sw); - arg_types >>= SLJIT_ARG_SHIFT; - } - - compiler->args_size = offset; -#else - offset = SLJIT_FR0; - old_offset = SLJIT_FR0; - f32_offset = 0; - - while (arg_types) { - switch (arg_types & SLJIT_ARG_MASK) { - case SLJIT_ARG_TYPE_F64: - if (offset != old_offset) - *remap_ptr++ = VMOV_F32 | SLJIT_32 | DD4(offset) | DM4(old_offset); - old_offset++; - offset++; - break; - case SLJIT_ARG_TYPE_F32: - if (f32_offset != 0) { - *remap_ptr++ = VMOV_F32 | 0x20 | DD4(offset) | DM4(f32_offset); - f32_offset = 0; - } else { - if (offset != old_offset) - *remap_ptr++ = VMOV_F32 | DD4(offset) | DM4(old_offset); - f32_offset = old_offset; - old_offset++; - } - offset++; - break; - default: - if (!(arg_types & SLJIT_ARG_TYPE_SCRATCH_REG)) { - FAIL_IF(push_inst16(compiler, MOV | SET_REGS44(SLJIT_S0 - saved_arg_count, SLJIT_R0 + word_arg_count))); - saved_arg_count++; - } - - word_arg_count++; - break; - } - arg_types >>= SLJIT_ARG_SHIFT; - } - - SLJIT_ASSERT((sljit_uw)(remap_ptr - remap) <= sizeof(remap)); - - while (remap_ptr > remap) - FAIL_IF(push_inst32(compiler, *(--remap_ptr))); -#endif - -#ifdef _WIN32 - if (local_size >= 4096) { - imm = get_imm(4096); - SLJIT_ASSERT(imm != INVALID_IMM); - - FAIL_IF(push_inst32(compiler, SUB_WI | RD4(SLJIT_SP) | RN4(SLJIT_SP) | imm)); - - if (local_size < 4 * 4096) { - if (local_size > 2 * 4096) { - if (local_size > 3 * 4096) { - FAIL_IF(push_inst32(compiler, LDRI | 0x400 | RT4(TMP_REG1) | RN4(SLJIT_SP))); - FAIL_IF(push_inst32(compiler, SUB_WI | RD4(SLJIT_SP) | RN4(SLJIT_SP) | imm)); - } - - FAIL_IF(push_inst32(compiler, LDRI | 0x400 | RT4(TMP_REG1) | RN4(SLJIT_SP))); - FAIL_IF(push_inst32(compiler, SUB_WI | RD4(SLJIT_SP) | RN4(SLJIT_SP) | imm)); - } - } else { - FAIL_IF(load_immediate(compiler, TMP_REG2, ((sljit_uw)local_size >> 12) - 1)); - FAIL_IF(push_inst32(compiler, LDRI | 0x400 | RT4(TMP_REG1) | RN4(SLJIT_SP))); - FAIL_IF(push_inst32(compiler, SUB_WI | RD4(SLJIT_SP) | RN4(SLJIT_SP) | imm)); - FAIL_IF(push_inst32(compiler, SUB_WI | SET_FLAGS | RD4(TMP_REG2) | RN4(TMP_REG2) | 1)); - FAIL_IF(push_inst16(compiler, BCC | (0x1 << 8) /* not-equal */ | (-8 & 0xff))); - } - - FAIL_IF(push_inst32(compiler, LDRI | 0x400 | RT4(TMP_REG1) | RN4(SLJIT_SP))); - local_size &= 0xfff; - } - - if (local_size >= 256) { - SLJIT_ASSERT(local_size < 4096); - - if (local_size <= (127 << 2)) - FAIL_IF(push_inst16(compiler, SUB_SP_I | ((sljit_uw)local_size >> 2))); - else - FAIL_IF(emit_op_imm(compiler, SLJIT_SUB | ARG2_IMM, SLJIT_SP, SLJIT_SP, (sljit_uw)local_size)); - - FAIL_IF(push_inst32(compiler, LDRI | 0x400 | RT4(TMP_REG1) | RN4(SLJIT_SP))); - } else if (local_size > 0) - FAIL_IF(push_inst32(compiler, LDRI | 0x500 | RT4(TMP_REG1) | RN4(SLJIT_SP) | (sljit_uw)local_size)); -#else /* !_WIN32 */ - if (local_size > 0) { - if (local_size <= (127 << 2)) - FAIL_IF(push_inst16(compiler, SUB_SP_I | ((sljit_uw)local_size >> 2))); - else - FAIL_IF(emit_op_imm(compiler, SLJIT_SUB | ARG2_IMM, SLJIT_SP, SLJIT_SP, (sljit_uw)local_size)); - } -#endif /* _WIN32 */ - - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(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) -{ - sljit_s32 size; - - CHECK_ERROR(); - CHECK(check_sljit_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size)); - set_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size); - - size = GET_SAVED_REGISTERS_SIZE(scratches, saveds - SLJIT_KEPT_SAVEDS_COUNT(options), 1); - - if ((size & SSIZE_OF(sw)) != 0 && (fsaveds > 0 || fscratches >= SLJIT_FIRST_SAVED_FLOAT_REG)) - size += SSIZE_OF(sw); - - compiler->local_size = ((size + local_size + 0x7) & ~0x7) - size; - return SLJIT_SUCCESS; -} - -static sljit_s32 emit_add_sp(struct sljit_compiler *compiler, sljit_uw imm) -{ - sljit_uw imm2; - - /* The TMP_REG1 register must keep its value. */ - if (imm <= (127u << 2)) - return push_inst16(compiler, ADD_SP_I | (imm >> 2)); - - if (imm <= 0xfff) - return push_inst32(compiler, ADDWI | RD4(SLJIT_SP) | RN4(SLJIT_SP) | IMM12(imm)); - - imm2 = get_imm(imm); - - if (imm2 != INVALID_IMM) - return push_inst32(compiler, ADD_WI | RD4(SLJIT_SP) | RN4(SLJIT_SP) | imm2); - - FAIL_IF(load_immediate(compiler, TMP_REG2, imm)); - return push_inst16(compiler, ADD_SP | RN3(TMP_REG2)); -} - -static sljit_s32 emit_stack_frame_release(struct sljit_compiler *compiler, sljit_s32 frame_size) -{ - sljit_s32 local_size, fscratches, fsaveds, i, tmp; - sljit_s32 restored_reg = 0; - sljit_s32 lr_dst = TMP_PC; - sljit_uw reg_list = 0; - - SLJIT_ASSERT(reg_map[TMP_REG2] == 14 && frame_size <= 128); - - local_size = compiler->local_size; - fscratches = compiler->fscratches; - fsaveds = compiler->fsaveds; - - if (fsaveds > 0 || fscratches >= SLJIT_FIRST_SAVED_FLOAT_REG) { - if (local_size > 0) - FAIL_IF(emit_add_sp(compiler, (sljit_uw)local_size)); - - if (fsaveds + fscratches >= SLJIT_NUMBER_OF_FLOAT_REGISTERS) { - FAIL_IF(push_inst32(compiler, VPOP | DD4(SLJIT_FS0) | ((sljit_uw)SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS << 1))); - } else { - if (fscratches >= SLJIT_FIRST_SAVED_FLOAT_REG) - FAIL_IF(push_inst32(compiler, VPOP | DD4(fscratches) | ((sljit_uw)(fscratches - (SLJIT_FIRST_SAVED_FLOAT_REG - 1)) << 1))); - if (fsaveds > 0) - FAIL_IF(push_inst32(compiler, VPOP | DD4(SLJIT_FS0) | ((sljit_uw)fsaveds << 1))); - } - - local_size = GET_SAVED_REGISTERS_SIZE(compiler->scratches, compiler->saveds, 1) & 0x7; - } - - if (frame_size < 0) { - lr_dst = TMP_REG2; - frame_size = 0; - } else if (frame_size > 0) { - SLJIT_ASSERT(frame_size == 1 || (frame_size & 0x7) == 0); - lr_dst = 0; - frame_size &= ~0x7; - } - - tmp = SLJIT_S0 - compiler->saveds; - i = SLJIT_S0 - SLJIT_KEPT_SAVEDS_COUNT(compiler->options); - if (tmp < i) { - restored_reg = i; - do { - reg_list |= (sljit_uw)1 << reg_map[i]; - } while (--i > tmp); - } - - i = compiler->scratches; - if (i >= SLJIT_FIRST_SAVED_REG) { - restored_reg = i; - do { - reg_list |= (sljit_uw)1 << reg_map[i]; - } while (--i >= SLJIT_FIRST_SAVED_REG); - } - - if (lr_dst == TMP_REG2 && reg_list == 0) { - reg_list |= (sljit_uw)1 << reg_map[TMP_REG2]; - restored_reg = TMP_REG2; - lr_dst = 0; - } - - if (lr_dst == 0 && (reg_list & (reg_list - 1)) == 0) { - /* The local_size does not include the saved registers. */ - tmp = 0; - if (reg_list != 0) { - tmp = 2; - if (local_size <= 0xfff) { - if (local_size == 0) { - SLJIT_ASSERT(restored_reg != TMP_REG2); - if (frame_size == 0) - return push_inst32(compiler, LDRI | RT4(restored_reg) | RN4(SLJIT_SP) | 0x308); - if (frame_size > 2 * SSIZE_OF(sw)) - return push_inst32(compiler, LDRI | RT4(restored_reg) | RN4(SLJIT_SP) | 0x100 | (sljit_ins)(frame_size - (2 * SSIZE_OF(sw)))); - } - - if (reg_map[restored_reg] <= 7 && local_size <= 0x3fc) - FAIL_IF(push_inst16(compiler, STR_SP | 0x800 | RDN3(restored_reg) | (sljit_ins)(local_size >> 2))); - else - FAIL_IF(push_inst32(compiler, LDR | RT4(restored_reg) | RN4(SLJIT_SP) | (sljit_ins)local_size)); - tmp = 1; - } else if (frame_size == 0) { - frame_size = (restored_reg == TMP_REG2) ? SSIZE_OF(sw) : 2 * SSIZE_OF(sw); - tmp = 3; - } - - /* Place for the saved register. */ - if (restored_reg != TMP_REG2) - local_size += SSIZE_OF(sw); - } - - /* Place for the lr register. */ - local_size += SSIZE_OF(sw); - - if (frame_size > local_size) - FAIL_IF(push_inst16(compiler, SUB_SP_I | ((sljit_ins)(frame_size - local_size) >> 2))); - else if (frame_size < local_size) - FAIL_IF(emit_add_sp(compiler, (sljit_uw)(local_size - frame_size))); - - if (tmp <= 1) - return SLJIT_SUCCESS; - - if (tmp == 2) { - frame_size -= SSIZE_OF(sw); - if (restored_reg != TMP_REG2) - frame_size -= SSIZE_OF(sw); - - if (reg_map[restored_reg] <= 7) - return push_inst16(compiler, STR_SP | 0x800 | RDN3(restored_reg) | (sljit_ins)(frame_size >> 2)); - - return push_inst32(compiler, LDR | RT4(restored_reg) | RN4(SLJIT_SP) | (sljit_ins)frame_size); - } - - tmp = (restored_reg == TMP_REG2) ? 0x304 : 0x308; - return push_inst32(compiler, LDRI | RT4(restored_reg) | RN4(SLJIT_SP) | (sljit_ins)tmp); - } - - if (local_size > 0) - FAIL_IF(emit_add_sp(compiler, (sljit_uw)local_size)); - - if (!(reg_list & 0xff00) && lr_dst != TMP_REG2) { - if (lr_dst == TMP_PC) - reg_list |= 1u << 8; - - /* At least one register must be set for POP instruction. */ - SLJIT_ASSERT(reg_list != 0); - - FAIL_IF(push_inst16(compiler, POP | reg_list)); - } else { - if (lr_dst != 0) - reg_list |= (sljit_uw)1 << reg_map[lr_dst]; - - /* At least two registers must be set for POP_W instruction. */ - SLJIT_ASSERT((reg_list & (reg_list - 1)) != 0); - - FAIL_IF(push_inst32(compiler, POP_W | reg_list)); - } - - if (frame_size > 0) - return push_inst16(compiler, SUB_SP_I | (((sljit_ins)frame_size - sizeof(sljit_sw)) >> 2)); - - if (lr_dst != 0) - return SLJIT_SUCCESS; - - return push_inst16(compiler, ADD_SP_I | 1); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_void(struct sljit_compiler *compiler) -{ - CHECK_ERROR(); - CHECK(check_sljit_emit_return_void(compiler)); - - return emit_stack_frame_release(compiler, 0); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_to(struct sljit_compiler *compiler, - sljit_s32 src, sljit_sw srcw) -{ - CHECK_ERROR(); - CHECK(check_sljit_emit_return_to(compiler, src, srcw)); - - if (src & SLJIT_MEM) { - FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG1, src, srcw, TMP_REG1)); - src = TMP_REG1; - srcw = 0; - } else if (src >= SLJIT_FIRST_SAVED_REG && src <= (SLJIT_S0 - SLJIT_KEPT_SAVEDS_COUNT(compiler->options))) { - FAIL_IF(push_inst16(compiler, MOV | SET_REGS44(TMP_REG1, src))); - src = TMP_REG1; - srcw = 0; - } - - FAIL_IF(emit_stack_frame_release(compiler, 1)); - - SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_ijump(compiler, SLJIT_JUMP, src, srcw); -} - -/* --------------------------------------------------------------------- */ -/* Operators */ -/* --------------------------------------------------------------------- */ - -#if !(defined __ARM_FEATURE_IDIV) && !(defined __ARM_ARCH_EXT_IDIV__) - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef _WIN32 -extern unsigned long long __rt_udiv(unsigned int denominator, unsigned int numerator); -extern long long __rt_sdiv(int denominator, int numerator); -#elif defined(__GNUC__) -extern unsigned int __aeabi_uidivmod(unsigned int numerator, int unsigned denominator); -extern int __aeabi_idivmod(int numerator, int denominator); -#else -#error "Software divmod functions are needed" -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* !__ARM_FEATURE_IDIV && !__ARM_ARCH_EXT_IDIV__ */ - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compiler, sljit_s32 op) -{ -#if !(defined __ARM_FEATURE_IDIV) && !(defined __ARM_ARCH_EXT_IDIV__) - sljit_uw saved_reg_list[3]; - sljit_uw saved_reg_count; -#endif - - CHECK_ERROR(); - CHECK(check_sljit_emit_op0(compiler, op)); - - op = GET_OPCODE(op); - switch (op) { - case SLJIT_BREAKPOINT: - return push_inst16(compiler, BKPT); - case SLJIT_NOP: - return push_inst16(compiler, NOP); - case SLJIT_LMUL_UW: - case SLJIT_LMUL_SW: - return push_inst32(compiler, (op == SLJIT_LMUL_UW ? UMULL : SMULL) - | RD4(SLJIT_R1) | RT4(SLJIT_R0) | RN4(SLJIT_R0) | RM4(SLJIT_R1)); -#if (defined __ARM_FEATURE_IDIV) || (defined __ARM_ARCH_EXT_IDIV__) - case SLJIT_DIVMOD_UW: - case SLJIT_DIVMOD_SW: - FAIL_IF(push_inst16(compiler, MOV | SET_REGS44(TMP_REG1, SLJIT_R0))); - FAIL_IF(push_inst32(compiler, (op == SLJIT_DIVMOD_UW ? UDIV : SDIV) | RD4(SLJIT_R0) | RN4(SLJIT_R0) | RM4(SLJIT_R1))); - FAIL_IF(push_inst32(compiler, MUL | RD4(SLJIT_R1) | RN4(SLJIT_R0) | RM4(SLJIT_R1))); - return push_inst32(compiler, SUB_W | RD4(SLJIT_R1) | RN4(TMP_REG1) | RM4(SLJIT_R1)); - case SLJIT_DIV_UW: - case SLJIT_DIV_SW: - return push_inst32(compiler, (op == SLJIT_DIV_UW ? UDIV : SDIV) | RD4(SLJIT_R0) | RN4(SLJIT_R0) | RM4(SLJIT_R1)); -#else /* !__ARM_FEATURE_IDIV && !__ARM_ARCH_EXT_IDIV__ */ - case SLJIT_DIVMOD_UW: - case SLJIT_DIVMOD_SW: - case SLJIT_DIV_UW: - case SLJIT_DIV_SW: - SLJIT_COMPILE_ASSERT((SLJIT_DIVMOD_UW & 0x2) == 0 && SLJIT_DIV_UW - 0x2 == SLJIT_DIVMOD_UW, bad_div_opcode_assignments); - SLJIT_ASSERT(reg_map[2] == 1 && reg_map[3] == 2 && reg_map[4] == 3); - - saved_reg_count = 0; - if (compiler->scratches >= 4) - saved_reg_list[saved_reg_count++] = 3; - if (compiler->scratches >= 3) - saved_reg_list[saved_reg_count++] = 2; - if (op >= SLJIT_DIV_UW) - saved_reg_list[saved_reg_count++] = 1; - - if (saved_reg_count > 0) { - FAIL_IF(push_inst32(compiler, 0xf84d0d00 | (saved_reg_count >= 3 ? 16 : 8) - | (saved_reg_list[0] << 12) /* str rX, [sp, #-8/-16]! */)); - if (saved_reg_count >= 2) { - SLJIT_ASSERT(saved_reg_list[1] < 8); - FAIL_IF(push_inst16(compiler, 0x9001 | (saved_reg_list[1] << 8) /* str rX, [sp, #4] */)); - } - if (saved_reg_count >= 3) { - SLJIT_ASSERT(saved_reg_list[2] < 8); - FAIL_IF(push_inst16(compiler, 0x9002 | (saved_reg_list[2] << 8) /* str rX, [sp, #8] */)); - } - } - -#ifdef _WIN32 - FAIL_IF(push_inst16(compiler, MOV | SET_REGS44(TMP_REG1, SLJIT_R0))); - FAIL_IF(push_inst16(compiler, MOV | SET_REGS44(SLJIT_R0, SLJIT_R1))); - FAIL_IF(push_inst16(compiler, MOV | SET_REGS44(SLJIT_R1, TMP_REG1))); - FAIL_IF(sljit_emit_ijump(compiler, SLJIT_FAST_CALL, SLJIT_IMM, - ((op | 0x2) == SLJIT_DIV_UW ? SLJIT_FUNC_ADDR(__rt_udiv) : SLJIT_FUNC_ADDR(__rt_sdiv)))); -#elif defined(__GNUC__) - FAIL_IF(sljit_emit_ijump(compiler, SLJIT_FAST_CALL, SLJIT_IMM, - ((op | 0x2) == SLJIT_DIV_UW ? SLJIT_FUNC_ADDR(__aeabi_uidivmod) : SLJIT_FUNC_ADDR(__aeabi_idivmod)))); -#else -#error "Software divmod functions are needed" -#endif - - if (saved_reg_count > 0) { - if (saved_reg_count >= 3) { - SLJIT_ASSERT(saved_reg_list[2] < 8); - FAIL_IF(push_inst16(compiler, 0x9802 | (saved_reg_list[2] << 8) /* ldr rX, [sp, #8] */)); - } - if (saved_reg_count >= 2) { - SLJIT_ASSERT(saved_reg_list[1] < 8); - FAIL_IF(push_inst16(compiler, 0x9801 | (saved_reg_list[1] << 8) /* ldr rX, [sp, #4] */)); - } - return push_inst32(compiler, 0xf85d0b00 | (saved_reg_count >= 3 ? 16 : 8) - | (saved_reg_list[0] << 12) /* ldr rX, [sp], #8/16 */); - } - return SLJIT_SUCCESS; -#endif /* __ARM_FEATURE_IDIV || __ARM_ARCH_EXT_IDIV__ */ - case SLJIT_ENDBR: - case SLJIT_SKIP_FRAMES_BEFORE_RETURN: - return SLJIT_SUCCESS; - } - - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - 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; - - op = GET_OPCODE(op); - if (op >= SLJIT_MOV && op <= SLJIT_MOV_P) { - switch (op) { - case SLJIT_MOV: - case SLJIT_MOV_U32: - case SLJIT_MOV_S32: - case SLJIT_MOV32: - case SLJIT_MOV_P: - flags = WORD_SIZE; - break; - case SLJIT_MOV_U8: - flags = BYTE_SIZE; - if (src & SLJIT_IMM) - srcw = (sljit_u8)srcw; - break; - case SLJIT_MOV_S8: - flags = BYTE_SIZE | SIGNED; - if (src & SLJIT_IMM) - srcw = (sljit_s8)srcw; - break; - case SLJIT_MOV_U16: - flags = HALF_SIZE; - if (src & SLJIT_IMM) - srcw = (sljit_u16)srcw; - break; - case SLJIT_MOV_S16: - flags = HALF_SIZE | SIGNED; - if (src & SLJIT_IMM) - srcw = (sljit_s16)srcw; - break; - default: - SLJIT_UNREACHABLE(); - flags = 0; - break; - } - - 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) { - 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); - dst_r = src; - } - - if (!(dst & SLJIT_MEM)) - return SLJIT_SUCCESS; - - return emit_op_mem(compiler, flags | STORE, dst_r, dst, dstw, TMP_REG2); - } - - flags = HAS_FLAGS(op_flags) ? SET_FLAGS : 0; - - if (src & SLJIT_MEM) { - FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG1, src, srcw, TMP_REG1)); - src = TMP_REG1; - } - - emit_op_imm(compiler, flags | 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 SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - sljit_s32 dst_reg, flags, src2_reg; - - CHECK_ERROR(); - CHECK(check_sljit_emit_op2(compiler, op, 0, dst, dstw, src1, src1w, src2, src2w)); - ADJUST_LOCAL_OFFSET(dst, dstw); - ADJUST_LOCAL_OFFSET(src1, src1w); - ADJUST_LOCAL_OFFSET(src2, src2w); - - dst_reg = FAST_IS_REG(dst) ? dst : TMP_REG1; - flags = HAS_FLAGS(op) ? SET_FLAGS : 0; - - if (dst == TMP_REG1) - flags |= UNUSED_RETURN; - - 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 - 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); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - 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, TMP_REG1, 0, src1, src1w, src2, src2w); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 src_dst, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - sljit_s32 is_left; - - CHECK_ERROR(); - CHECK(check_sljit_emit_shift_into(compiler, op, src_dst, src1, src1w, src2, src2w)); - - op = GET_OPCODE(op); - is_left = (op == SLJIT_SHL || op == SLJIT_MSHL); - - if (src_dst == src1) { - SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_op2(compiler, is_left ? SLJIT_ROTL : SLJIT_ROTR, src_dst, 0, src_dst, 0, src2, src2w); - } - - ADJUST_LOCAL_OFFSET(src1, src1w); - ADJUST_LOCAL_OFFSET(src2, src2w); - - if (src2 & SLJIT_IMM) { - src2w &= 0x1f; - - if (src2w == 0) - return SLJIT_SUCCESS; - } else if (src2 & SLJIT_MEM) { - FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG2, src2, src2w, TMP_REG2)); - src2 = TMP_REG2; - } - - if (src1 & SLJIT_MEM) { - FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG1, src1, src1w, TMP_REG1)); - src1 = TMP_REG1; - } else if (src1 & SLJIT_IMM) { - FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)src1w)); - src1 = TMP_REG1; - } - - if (src2 & SLJIT_IMM) { - if (reg_map[src_dst] <= 7) - FAIL_IF(push_inst16(compiler, (is_left ? LSLSI : LSRSI) | RD3(src_dst) | RN3(src_dst) | ((sljit_ins)src2w << 6))); - else - FAIL_IF(push_inst32(compiler, (is_left ? LSL_WI : LSR_WI) | RD4(src_dst) | RM4(src_dst) | IMM5(src2w))); - - src2w = (src2w ^ 0x1f) + 1; - return push_inst32(compiler, ORR_W | RD4(src_dst) | RN4(src_dst) | RM4(src1) | (is_left ? 0x10 : 0x0) | IMM5(src2w)); - } - - if (op == SLJIT_MSHL || op == SLJIT_MLSHR) { - FAIL_IF(push_inst32(compiler, ANDI | RD4(TMP_REG2) | RN4(src2) | 0x1f)); - src2 = TMP_REG2; - } - - if (IS_2_LO_REGS(src_dst, src2)) - FAIL_IF(push_inst16(compiler, (is_left ? LSLS : LSRS) | RD3(src_dst) | RN3(src2))); - else - FAIL_IF(push_inst32(compiler, (is_left ? LSL_W : LSR_W) | RD4(src_dst) | RN4(src_dst) | RM4(src2))); - - FAIL_IF(push_inst32(compiler, (is_left ? LSR_WI : LSL_WI) | RD4(TMP_REG1) | RM4(src1) | (1 << 6))); - FAIL_IF(push_inst32(compiler, EORI | RD4(TMP_REG2) | RN4(src2) | 0x1f)); - FAIL_IF(push_inst32(compiler, (is_left ? LSR_W : LSL_W) | RD4(TMP_REG1) | RN4(TMP_REG1) | RM4(TMP_REG2))); - return push_inst32(compiler, ORR_W | RD4(src_dst) | RN4(src_dst) | RM4(TMP_REG1)); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 src, sljit_sw srcw) -{ - CHECK_ERROR(); - CHECK(check_sljit_emit_op_src(compiler, op, src, srcw)); - ADJUST_LOCAL_OFFSET(src, srcw); - - switch (op) { - case SLJIT_FAST_RETURN: - SLJIT_ASSERT(reg_map[TMP_REG2] == 14); - - if (FAST_IS_REG(src)) - FAIL_IF(push_inst16(compiler, MOV | SET_REGS44(TMP_REG2, src))); - else - FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG2, src, srcw, TMP_REG2)); - - return push_inst16(compiler, BX | RN3(TMP_REG2)); - case SLJIT_SKIP_FRAMES_BEFORE_FAST_RETURN: - return SLJIT_SUCCESS; - case SLJIT_PREFETCH_L1: - case SLJIT_PREFETCH_L2: - case SLJIT_PREFETCH_L3: - case SLJIT_PREFETCH_ONCE: - return emit_op_mem(compiler, PRELOAD, TMP_PC, src, srcw, TMP_REG1); - } - - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 reg) -{ - CHECK_REG_INDEX(check_sljit_get_register_index(reg)); - return reg_map[reg]; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_float_register_index(sljit_s32 reg) -{ - CHECK_REG_INDEX(check_sljit_get_float_register_index(reg)); - return (freg_map[reg] << 1); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler, - void *instruction, sljit_u32 size) -{ - CHECK_ERROR(); - CHECK(check_sljit_emit_op_custom(compiler, instruction, size)); - - if (size == 2) - return push_inst16(compiler, *(sljit_u16*)instruction); - return push_inst32(compiler, *(sljit_ins*)instruction); -} - -/* --------------------------------------------------------------------- */ -/* Floating point operators */ -/* --------------------------------------------------------------------- */ - -#define FPU_LOAD (1 << 20) - -static sljit_s32 emit_fop_mem(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg, sljit_sw argw) -{ - sljit_uw imm; - sljit_ins inst = VSTR_F32 | (flags & (SLJIT_32 | FPU_LOAD)); - - SLJIT_ASSERT(arg & SLJIT_MEM); - - /* Fast loads and stores. */ - if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) { - FAIL_IF(push_inst32(compiler, ADD_W | RD4(TMP_REG1) | RN4(arg & REG_MASK) | RM4(OFFS_REG(arg)) | (((sljit_uw)argw & 0x3) << 6))); - arg = SLJIT_MEM | TMP_REG1; - argw = 0; - } - - if ((arg & REG_MASK) && (argw & 0x3) == 0) { - if (!(argw & ~0x3fc)) - return push_inst32(compiler, inst | 0x800000 | RN4(arg & REG_MASK) | DD4(reg) | ((sljit_uw)argw >> 2)); - if (!(-argw & ~0x3fc)) - return push_inst32(compiler, inst | RN4(arg & REG_MASK) | DD4(reg) | ((sljit_uw)-argw >> 2)); - } - - if (arg & REG_MASK) { - if (emit_set_delta(compiler, TMP_REG1, arg & REG_MASK, argw) != SLJIT_ERR_UNSUPPORTED) { - FAIL_IF(compiler->error); - return push_inst32(compiler, inst | 0x800000 | RN4(TMP_REG1) | DD4(reg)); - } - - imm = get_imm((sljit_uw)argw & ~(sljit_uw)0x3fc); - if (imm != INVALID_IMM) { - FAIL_IF(push_inst32(compiler, ADD_WI | RD4(TMP_REG1) | RN4(arg & REG_MASK) | imm)); - return push_inst32(compiler, inst | 0x800000 | RN4(TMP_REG1) | DD4(reg) | (((sljit_uw)argw & 0x3fc) >> 2)); - } - - imm = get_imm((sljit_uw)-argw & ~(sljit_uw)0x3fc); - if (imm != INVALID_IMM) { - argw = -argw; - FAIL_IF(push_inst32(compiler, SUB_WI | RD4(TMP_REG1) | RN4(arg & REG_MASK) | imm)); - return push_inst32(compiler, inst | RN4(TMP_REG1) | DD4(reg) | (((sljit_uw)argw & 0x3fc) >> 2)); - } - } - - FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)argw)); - if (arg & REG_MASK) - FAIL_IF(push_inst16(compiler, ADD | SET_REGS44(TMP_REG1, (arg & REG_MASK)))); - return push_inst32(compiler, inst | 0x800000 | RN4(TMP_REG1) | DD4(reg)); -} - -static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src, sljit_sw srcw) -{ - op ^= SLJIT_32; - - if (src & SLJIT_MEM) { - FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_32) | FPU_LOAD, TMP_FREG1, src, srcw)); - src = TMP_FREG1; - } - - FAIL_IF(push_inst32(compiler, VCVT_S32_F32 | (op & SLJIT_32) | DD4(TMP_FREG1) | DM4(src))); - - if (FAST_IS_REG(dst)) - return push_inst32(compiler, VMOV | (1 << 20) | RT4(dst) | DN4(TMP_FREG1)); - - /* Store the integer value from a VFP register. */ - return emit_fop_mem(compiler, 0, TMP_FREG1, dst, dstw); -} - -static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src, sljit_sw srcw) -{ - sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1; - - op ^= SLJIT_32; - - if (FAST_IS_REG(src)) - FAIL_IF(push_inst32(compiler, VMOV | RT4(src) | DN4(TMP_FREG1))); - else if (src & SLJIT_MEM) { - /* Load the integer value into a VFP register. */ - FAIL_IF(emit_fop_mem(compiler, FPU_LOAD, TMP_FREG1, src, srcw)); - } - else { - FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)srcw)); - FAIL_IF(push_inst32(compiler, VMOV | RT4(TMP_REG1) | DN4(TMP_FREG1))); - } - - FAIL_IF(push_inst32(compiler, VCVT_F32_S32 | (op & SLJIT_32) | DD4(dst_r) | DM4(TMP_FREG1))); - - if (dst & SLJIT_MEM) - return emit_fop_mem(compiler, (op & SLJIT_32), TMP_FREG1, dst, dstw); - return SLJIT_SUCCESS; -} - -static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - op ^= SLJIT_32; - - if (src1 & SLJIT_MEM) { - emit_fop_mem(compiler, (op & SLJIT_32) | FPU_LOAD, TMP_FREG1, src1, src1w); - src1 = TMP_FREG1; - } - - if (src2 & SLJIT_MEM) { - emit_fop_mem(compiler, (op & SLJIT_32) | FPU_LOAD, TMP_FREG2, src2, src2w); - src2 = TMP_FREG2; - } - - FAIL_IF(push_inst32(compiler, VCMP_F32 | (op & SLJIT_32) | DD4(src1) | DM4(src2))); - return push_inst32(compiler, VMRS); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src, sljit_sw srcw) -{ - sljit_s32 dst_r; - - CHECK_ERROR(); - - SLJIT_COMPILE_ASSERT((SLJIT_32 == 0x100), float_transfer_bit_error); - SELECT_FOP1_OPERATION_WITH_CHECKS(compiler, op, dst, dstw, src, srcw); - - dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1; - - if (GET_OPCODE(op) != SLJIT_CONV_F64_FROM_F32) - op ^= SLJIT_32; - - if (src & SLJIT_MEM) { - emit_fop_mem(compiler, (op & SLJIT_32) | FPU_LOAD, dst_r, src, srcw); - src = dst_r; - } - - switch (GET_OPCODE(op)) { - case SLJIT_MOV_F64: - if (src != dst_r) { - if (dst_r != TMP_FREG1) - FAIL_IF(push_inst32(compiler, VMOV_F32 | (op & SLJIT_32) | DD4(dst_r) | DM4(src))); - else - dst_r = src; - } - break; - case SLJIT_NEG_F64: - FAIL_IF(push_inst32(compiler, VNEG_F32 | (op & SLJIT_32) | DD4(dst_r) | DM4(src))); - break; - case SLJIT_ABS_F64: - FAIL_IF(push_inst32(compiler, VABS_F32 | (op & SLJIT_32) | DD4(dst_r) | DM4(src))); - break; - case SLJIT_CONV_F64_FROM_F32: - FAIL_IF(push_inst32(compiler, VCVT_F64_F32 | (op & SLJIT_32) | DD4(dst_r) | DM4(src))); - op ^= SLJIT_32; - break; - } - - if (dst & SLJIT_MEM) - return emit_fop_mem(compiler, (op & SLJIT_32), dst_r, dst, dstw); - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - sljit_s32 dst_r; - - CHECK_ERROR(); - CHECK(check_sljit_emit_fop2(compiler, op, dst, dstw, src1, src1w, src2, src2w)); - ADJUST_LOCAL_OFFSET(dst, dstw); - ADJUST_LOCAL_OFFSET(src1, src1w); - ADJUST_LOCAL_OFFSET(src2, src2w); - - op ^= SLJIT_32; - - dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1; - if (src1 & SLJIT_MEM) { - emit_fop_mem(compiler, (op & SLJIT_32) | FPU_LOAD, TMP_FREG1, src1, src1w); - src1 = TMP_FREG1; - } - if (src2 & SLJIT_MEM) { - emit_fop_mem(compiler, (op & SLJIT_32) | FPU_LOAD, TMP_FREG2, src2, src2w); - src2 = TMP_FREG2; - } - - switch (GET_OPCODE(op)) { - case SLJIT_ADD_F64: - FAIL_IF(push_inst32(compiler, VADD_F32 | (op & SLJIT_32) | DD4(dst_r) | DN4(src1) | DM4(src2))); - break; - case SLJIT_SUB_F64: - FAIL_IF(push_inst32(compiler, VSUB_F32 | (op & SLJIT_32) | DD4(dst_r) | DN4(src1) | DM4(src2))); - break; - case SLJIT_MUL_F64: - FAIL_IF(push_inst32(compiler, VMUL_F32 | (op & SLJIT_32) | DD4(dst_r) | DN4(src1) | DM4(src2))); - break; - case SLJIT_DIV_F64: - FAIL_IF(push_inst32(compiler, VDIV_F32 | (op & SLJIT_32) | DD4(dst_r) | DN4(src1) | DM4(src2))); - break; - } - - if (!(dst & SLJIT_MEM)) - return SLJIT_SUCCESS; - return emit_fop_mem(compiler, (op & SLJIT_32), TMP_FREG1, dst, dstw); -} - -/* --------------------------------------------------------------------- */ -/* Other instructions */ -/* --------------------------------------------------------------------- */ - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw) -{ - CHECK_ERROR(); - CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw)); - ADJUST_LOCAL_OFFSET(dst, dstw); - - SLJIT_ASSERT(reg_map[TMP_REG2] == 14); - - if (FAST_IS_REG(dst)) - return push_inst16(compiler, MOV | SET_REGS44(dst, TMP_REG2)); - - /* Memory. */ - return emit_op_mem(compiler, WORD_SIZE | STORE, TMP_REG2, dst, dstw, TMP_REG1); -} - -/* --------------------------------------------------------------------- */ -/* Conditional instructions */ -/* --------------------------------------------------------------------- */ - -static sljit_uw get_cc(struct sljit_compiler *compiler, sljit_s32 type) -{ - switch (type) { - case SLJIT_EQUAL: - case SLJIT_F_EQUAL: - case SLJIT_ORDERED_EQUAL: - case SLJIT_UNORDERED_OR_EQUAL: /* Not supported. */ - return 0x0; - - case SLJIT_NOT_EQUAL: - case SLJIT_F_NOT_EQUAL: - case SLJIT_UNORDERED_OR_NOT_EQUAL: - case SLJIT_ORDERED_NOT_EQUAL: /* Not supported. */ - return 0x1; - - case SLJIT_CARRY: - if (compiler->status_flags_state & SLJIT_CURRENT_FLAGS_ADD) - return 0x2; - /* fallthrough */ - - case SLJIT_LESS: - return 0x3; - - case SLJIT_NOT_CARRY: - if (compiler->status_flags_state & SLJIT_CURRENT_FLAGS_ADD) - return 0x3; - /* fallthrough */ - - case SLJIT_GREATER_EQUAL: - return 0x2; - - case SLJIT_GREATER: - case SLJIT_UNORDERED_OR_GREATER: - return 0x8; - - case SLJIT_LESS_EQUAL: - case SLJIT_F_LESS_EQUAL: - case SLJIT_ORDERED_LESS_EQUAL: - return 0x9; - - case SLJIT_SIG_LESS: - case SLJIT_UNORDERED_OR_LESS: - return 0xb; - - case SLJIT_SIG_GREATER_EQUAL: - case SLJIT_F_GREATER_EQUAL: - case SLJIT_ORDERED_GREATER_EQUAL: - return 0xa; - - case SLJIT_SIG_GREATER: - case SLJIT_F_GREATER: - case SLJIT_ORDERED_GREATER: - return 0xc; - - case SLJIT_SIG_LESS_EQUAL: - case SLJIT_UNORDERED_OR_LESS_EQUAL: - return 0xd; - - case SLJIT_OVERFLOW: - if (!(compiler->status_flags_state & (SLJIT_CURRENT_FLAGS_ADD | SLJIT_CURRENT_FLAGS_SUB))) - return 0x1; - /* fallthrough */ - - case SLJIT_UNORDERED: - return 0x6; - - case SLJIT_NOT_OVERFLOW: - if (!(compiler->status_flags_state & (SLJIT_CURRENT_FLAGS_ADD | SLJIT_CURRENT_FLAGS_SUB))) - return 0x0; - /* fallthrough */ - - case SLJIT_ORDERED: - return 0x7; - - case SLJIT_F_LESS: - case SLJIT_ORDERED_LESS: - return 0x4; - - case SLJIT_UNORDERED_OR_GREATER_EQUAL: - return 0x5; - - default: /* SLJIT_JUMP */ - SLJIT_UNREACHABLE(); - return 0xe; - } -} - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compiler *compiler) -{ - struct sljit_label *label; - - CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_label(compiler)); - - if (compiler->last_label && compiler->last_label->size == compiler->size) - return compiler->last_label; - - label = (struct sljit_label*)ensure_abuf(compiler, sizeof(struct sljit_label)); - PTR_FAIL_IF(!label); - set_label(label, compiler); - return label; -} - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type) -{ - struct sljit_jump *jump; - sljit_ins cc; - - CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_jump(compiler, type)); - - jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump)); - PTR_FAIL_IF(!jump); - 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); - jump->flags |= cc << 8; - PTR_FAIL_IF(push_inst16(compiler, IT | (cc << 4) | 0x8)); - } - - jump->addr = compiler->size; - if (type <= SLJIT_JUMP) - PTR_FAIL_IF(push_inst16(compiler, BX | RN3(TMP_REG1))); - else { - jump->flags |= IS_BL; - PTR_FAIL_IF(push_inst16(compiler, BLX | RN3(TMP_REG1))); - } - - return jump; -} - -#ifdef __SOFTFP__ - -static sljit_s32 softfloat_call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_types, sljit_s32 *src, sljit_u32 *extra_space) -{ - sljit_u32 is_tail_call = *extra_space & SLJIT_CALL_RETURN; - sljit_u32 offset = 0; - sljit_u32 word_arg_offset = 0; - sljit_u32 float_arg_count = 0; - sljit_s32 types = 0; - sljit_u32 src_offset = 4 * sizeof(sljit_sw); - sljit_u8 offsets[4]; - sljit_u8 *offset_ptr = offsets; - - if (src && FAST_IS_REG(*src)) - src_offset = (sljit_u32)reg_map[*src] * sizeof(sljit_sw); - - arg_types >>= SLJIT_ARG_SHIFT; - - while (arg_types) { - types = (types << SLJIT_ARG_SHIFT) | (arg_types & SLJIT_ARG_MASK); - - switch (arg_types & SLJIT_ARG_MASK) { - case SLJIT_ARG_TYPE_F64: - if (offset & 0x7) - offset += sizeof(sljit_sw); - *offset_ptr++ = (sljit_u8)offset; - offset += sizeof(sljit_f64); - float_arg_count++; - break; - case SLJIT_ARG_TYPE_F32: - *offset_ptr++ = (sljit_u8)offset; - offset += sizeof(sljit_f32); - float_arg_count++; - break; - default: - *offset_ptr++ = (sljit_u8)offset; - offset += sizeof(sljit_sw); - word_arg_offset += sizeof(sljit_sw); - break; - } - - arg_types >>= SLJIT_ARG_SHIFT; - } - - if (offset > 4 * sizeof(sljit_sw) && (!is_tail_call || offset > compiler->args_size)) { - /* Keep lr register on the stack. */ - if (is_tail_call) - offset += sizeof(sljit_sw); - - offset = ((offset - 4 * sizeof(sljit_sw)) + 0x7) & ~(sljit_uw)0x7; - - *extra_space = offset; - - if (is_tail_call) - FAIL_IF(emit_stack_frame_release(compiler, (sljit_s32)offset)); - else - FAIL_IF(push_inst16(compiler, SUB_SP_I | (offset >> 2))); - } else { - if (is_tail_call) - FAIL_IF(emit_stack_frame_release(compiler, -1)); - *extra_space = 0; - } - - SLJIT_ASSERT(reg_map[TMP_REG1] == 12); - - /* Process arguments in reversed direction. */ - while (types) { - switch (types & SLJIT_ARG_MASK) { - case SLJIT_ARG_TYPE_F64: - float_arg_count--; - offset = *(--offset_ptr); - - SLJIT_ASSERT((offset & 0x7) == 0); - - if (offset < 4 * sizeof(sljit_sw)) { - if (src_offset == offset || src_offset == offset + sizeof(sljit_sw)) { - FAIL_IF(push_inst16(compiler, MOV | (src_offset << 1) | 4 | (1 << 7))); - *src = TMP_REG1; - } - FAIL_IF(push_inst32(compiler, VMOV2 | 0x100000 | (offset << 10) | ((offset + sizeof(sljit_sw)) << 14) | float_arg_count)); - } else - FAIL_IF(push_inst32(compiler, VSTR_F32 | 0x800100 | RN4(SLJIT_SP) - | (float_arg_count << 12) | ((offset - 4 * sizeof(sljit_sw)) >> 2))); - break; - case SLJIT_ARG_TYPE_F32: - float_arg_count--; - offset = *(--offset_ptr); - - if (offset < 4 * sizeof(sljit_sw)) { - if (src_offset == offset) { - FAIL_IF(push_inst16(compiler, MOV | (src_offset << 1) | 4 | (1 << 7))); - *src = TMP_REG1; - } - FAIL_IF(push_inst32(compiler, VMOV | 0x100000 | (float_arg_count << 16) | (offset << 10))); - } else - FAIL_IF(push_inst32(compiler, VSTR_F32 | 0x800000 | RN4(SLJIT_SP) - | (float_arg_count << 12) | ((offset - 4 * sizeof(sljit_sw)) >> 2))); - break; - default: - word_arg_offset -= sizeof(sljit_sw); - offset = *(--offset_ptr); - - SLJIT_ASSERT(offset >= word_arg_offset); - - if (offset != word_arg_offset) { - if (offset < 4 * sizeof(sljit_sw)) { - if (src_offset == offset) { - FAIL_IF(push_inst16(compiler, MOV | (src_offset << 1) | 4 | (1 << 7))); - *src = TMP_REG1; - } - else if (src_offset == word_arg_offset) { - *src = (sljit_s32)(1 + (offset >> 2)); - src_offset = offset; - } - FAIL_IF(push_inst16(compiler, MOV | (offset >> 2) | (word_arg_offset << 1))); - } else - FAIL_IF(push_inst16(compiler, STR_SP | (word_arg_offset << 6) | ((offset - 4 * sizeof(sljit_sw)) >> 2))); - } - break; - } - - types >>= SLJIT_ARG_SHIFT; - } - - return SLJIT_SUCCESS; -} - -static sljit_s32 softfloat_post_call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_types) -{ - if ((arg_types & SLJIT_ARG_MASK) == SLJIT_ARG_TYPE_F64) - FAIL_IF(push_inst32(compiler, VMOV2 | (1 << 16) | (0 << 12) | 0)); - if ((arg_types & SLJIT_ARG_MASK) == SLJIT_ARG_TYPE_F32) - FAIL_IF(push_inst32(compiler, VMOV | (0 << 16) | (0 << 12))); - - return SLJIT_SUCCESS; -} - -#else - -static sljit_s32 hardfloat_call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_types) -{ - sljit_u32 offset = SLJIT_FR0; - sljit_u32 new_offset = SLJIT_FR0; - sljit_u32 f32_offset = 0; - - /* Remove return value. */ - arg_types >>= SLJIT_ARG_SHIFT; - - while (arg_types) { - switch (arg_types & SLJIT_ARG_MASK) { - case SLJIT_ARG_TYPE_F64: - if (offset != new_offset) - FAIL_IF(push_inst32(compiler, VMOV_F32 | SLJIT_32 | DD4(new_offset) | DM4(offset))); - - new_offset++; - offset++; - break; - case SLJIT_ARG_TYPE_F32: - if (f32_offset != 0) { - FAIL_IF(push_inst32(compiler, VMOV_F32 | 0x400000 | DD4(f32_offset) | DM4(offset))); - f32_offset = 0; - } else { - if (offset != new_offset) - FAIL_IF(push_inst32(compiler, VMOV_F32 | 0x400000 | DD4(new_offset) | DM4(offset))); - f32_offset = new_offset; - new_offset++; - } - offset++; - break; - } - arg_types >>= SLJIT_ARG_SHIFT; - } - - return SLJIT_SUCCESS; -} - -#endif - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_call(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 arg_types) -{ -#ifdef __SOFTFP__ - struct sljit_jump *jump; - sljit_u32 extra_space = (sljit_u32)type; -#endif - - CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_call(compiler, type, arg_types)); - -#ifdef __SOFTFP__ - if ((type & 0xff) != SLJIT_CALL_REG_ARG) { - PTR_FAIL_IF(softfloat_call_with_args(compiler, arg_types, NULL, &extra_space)); - SLJIT_ASSERT((extra_space & 0x7) == 0); - - if ((type & SLJIT_CALL_RETURN) && extra_space == 0) - type = SLJIT_JUMP | (type & SLJIT_REWRITABLE_JUMP); - - SLJIT_SKIP_CHECKS(compiler); - jump = sljit_emit_jump(compiler, type); - PTR_FAIL_IF(jump == NULL); - - if (extra_space > 0) { - if (type & SLJIT_CALL_RETURN) - PTR_FAIL_IF(push_inst32(compiler, LDR | RT4(TMP_REG2) - | RN4(SLJIT_SP) | (extra_space - sizeof(sljit_sw)))); - - PTR_FAIL_IF(push_inst16(compiler, ADD_SP_I | (extra_space >> 2))); - - if (type & SLJIT_CALL_RETURN) { - PTR_FAIL_IF(push_inst16(compiler, BX | RN3(TMP_REG2))); - return jump; - } - } - - SLJIT_ASSERT(!(type & SLJIT_CALL_RETURN)); - PTR_FAIL_IF(softfloat_post_call_with_args(compiler, arg_types)); - return jump; - } -#endif /* __SOFTFP__ */ - - if (type & SLJIT_CALL_RETURN) { - /* ldmia sp!, {..., lr} */ - PTR_FAIL_IF(emit_stack_frame_release(compiler, -1)); - type = SLJIT_JUMP | (type & SLJIT_REWRITABLE_JUMP); - } - -#ifndef __SOFTFP__ - if ((type & 0xff) != SLJIT_CALL_REG_ARG) - PTR_FAIL_IF(hardfloat_call_with_args(compiler, arg_types)); -#endif /* !__SOFTFP__ */ - - SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_jump(compiler, type); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 src, sljit_sw srcw) -{ - struct sljit_jump *jump; - - CHECK_ERROR(); - CHECK(check_sljit_emit_ijump(compiler, type, src, srcw)); - ADJUST_LOCAL_OFFSET(src, srcw); - - SLJIT_ASSERT(reg_map[TMP_REG1] != 14); - - if (!(src & SLJIT_IMM)) { - if (FAST_IS_REG(src)) { - SLJIT_ASSERT(reg_map[src] != 14); - return push_inst16(compiler, (type <= SLJIT_JUMP ? BX : BLX) | RN3(src)); - } - - FAIL_IF(emit_op_mem(compiler, WORD_SIZE, type <= SLJIT_JUMP ? TMP_PC : TMP_REG1, src, srcw, TMP_REG1)); - if (type >= SLJIT_FAST_CALL) - return push_inst16(compiler, BLX | RN3(TMP_REG1)); - } - - /* These jumps are converted to jump/call instructions when possible. */ - jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump)); - FAIL_IF(!jump); - 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; - return push_inst16(compiler, (type <= SLJIT_JUMP ? BX : BLX) | RN3(TMP_REG1)); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 arg_types, - sljit_s32 src, sljit_sw srcw) -{ -#ifdef __SOFTFP__ - sljit_u32 extra_space = (sljit_u32)type; -#endif - - CHECK_ERROR(); - CHECK(check_sljit_emit_icall(compiler, type, arg_types, src, srcw)); - - if (src & SLJIT_MEM) { - FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG1, src, srcw, TMP_REG1)); - src = TMP_REG1; - } - - if ((type & SLJIT_CALL_RETURN) && (src >= SLJIT_FIRST_SAVED_REG && src <= (SLJIT_S0 - SLJIT_KEPT_SAVEDS_COUNT(compiler->options)))) { - FAIL_IF(push_inst16(compiler, MOV | SET_REGS44(TMP_REG1, src))); - src = TMP_REG1; - } - -#ifdef __SOFTFP__ - if ((type & 0xff) != SLJIT_CALL_REG_ARG) { - FAIL_IF(softfloat_call_with_args(compiler, arg_types, &src, &extra_space)); - SLJIT_ASSERT((extra_space & 0x7) == 0); - - if ((type & SLJIT_CALL_RETURN) && extra_space == 0) - type = SLJIT_JUMP; - - SLJIT_SKIP_CHECKS(compiler); - FAIL_IF(sljit_emit_ijump(compiler, type, src, srcw)); - - if (extra_space > 0) { - if (type & SLJIT_CALL_RETURN) - FAIL_IF(push_inst32(compiler, LDR | RT4(TMP_REG2) - | RN4(SLJIT_SP) | (extra_space - sizeof(sljit_sw)))); - - FAIL_IF(push_inst16(compiler, ADD_SP_I | (extra_space >> 2))); - - if (type & SLJIT_CALL_RETURN) - return push_inst16(compiler, BX | RN3(TMP_REG2)); - } - - SLJIT_ASSERT(!(type & SLJIT_CALL_RETURN)); - return softfloat_post_call_with_args(compiler, arg_types); - } -#endif /* __SOFTFP__ */ - - if (type & SLJIT_CALL_RETURN) { - /* ldmia sp!, {..., lr} */ - FAIL_IF(emit_stack_frame_release(compiler, -1)); - type = SLJIT_JUMP; - } - -#ifndef __SOFTFP__ - if ((type & 0xff) != SLJIT_CALL_REG_ARG) - FAIL_IF(hardfloat_call_with_args(compiler, arg_types)); -#endif /* !__SOFTFP__ */ - - SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_ijump(compiler, type, src, srcw); -} - -#ifdef __SOFTFP__ - -static SLJIT_INLINE sljit_s32 emit_fmov_before_return(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw) -{ - if (compiler->options & SLJIT_ENTER_REG_ARG) { - if (src == SLJIT_FR0) - return SLJIT_SUCCESS; - - SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_fop1(compiler, op, SLJIT_RETURN_FREG, 0, src, srcw); - } - - if (FAST_IS_REG(src)) { - if (op & SLJIT_32) - return push_inst32(compiler, VMOV | (1 << 20) | DN4(src) | RT4(SLJIT_R0)); - return push_inst32(compiler, VMOV2 | (1 << 20) | DM4(src) | RT4(SLJIT_R0) | RN4(SLJIT_R1)); - } - - SLJIT_SKIP_CHECKS(compiler); - - if (op & SLJIT_32) - return sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_R0, 0, src, srcw); - return sljit_emit_mem(compiler, SLJIT_MOV, SLJIT_REG_PAIR(SLJIT_R0, SLJIT_R1), src, srcw); -} - -#endif /* __SOFTFP__ */ - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 type) -{ - sljit_s32 dst_r, flags = GET_ALL_FLAGS(op); - sljit_ins cc; - - CHECK_ERROR(); - CHECK(check_sljit_emit_op_flags(compiler, op, dst, dstw, type)); - ADJUST_LOCAL_OFFSET(dst, dstw); - - op = GET_OPCODE(op); - cc = get_cc(compiler, type); - dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1; - - if (op < SLJIT_ADD) { - FAIL_IF(push_inst16(compiler, IT | (cc << 4) | (((cc & 0x1) ^ 0x1) << 3) | 0x4)); - if (reg_map[dst_r] > 7) { - FAIL_IF(push_inst32(compiler, MOV_WI | RD4(dst_r) | 1)); - FAIL_IF(push_inst32(compiler, MOV_WI | RD4(dst_r) | 0)); - } else { - /* The movsi (immediate) instruction does not set flags in IT block. */ - FAIL_IF(push_inst16(compiler, MOVSI | RDN3(dst_r) | 1)); - FAIL_IF(push_inst16(compiler, MOVSI | RDN3(dst_r) | 0)); - } - if (!(dst & SLJIT_MEM)) - return SLJIT_SUCCESS; - return emit_op_mem(compiler, WORD_SIZE | STORE, TMP_REG1, dst, dstw, TMP_REG2); - } - - if (dst & SLJIT_MEM) - FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG1, dst, dstw, TMP_REG2)); - - if (op == SLJIT_AND) { - FAIL_IF(push_inst16(compiler, IT | (cc << 4) | (((cc & 0x1) ^ 0x1) << 3) | 0x4)); - FAIL_IF(push_inst32(compiler, ANDI | RN4(dst_r) | RD4(dst_r) | 1)); - FAIL_IF(push_inst32(compiler, ANDI | RN4(dst_r) | RD4(dst_r) | 0)); - } - else { - FAIL_IF(push_inst16(compiler, IT | (cc << 4) | 0x8)); - FAIL_IF(push_inst32(compiler, ((op == SLJIT_OR) ? ORRI : EORI) | RN4(dst_r) | RD4(dst_r) | 1)); - } - - if (dst & SLJIT_MEM) - FAIL_IF(emit_op_mem(compiler, WORD_SIZE | STORE, TMP_REG1, dst, dstw, TMP_REG2)); - - if (!(flags & SLJIT_SET_Z)) - return SLJIT_SUCCESS; - - /* The condition must always be set, even if the ORR/EORI is not executed above. */ - return push_inst32(compiler, MOV_W | SET_FLAGS | RD4(TMP_REG1) | RM4(dst_r)); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 dst_reg, - sljit_s32 src, sljit_sw srcw) -{ - sljit_uw cc, tmp; - - CHECK_ERROR(); - CHECK(check_sljit_emit_cmov(compiler, type, dst_reg, src, srcw)); - - cc = get_cc(compiler, type & ~SLJIT_32); - - if (!(src & SLJIT_IMM)) { - FAIL_IF(push_inst16(compiler, IT | (cc << 4) | 0x8)); - return push_inst16(compiler, MOV | SET_REGS44(dst_reg, src)); - } - - tmp = (sljit_uw) srcw; - - if (tmp < 0x10000) { - /* set low 16 bits, set hi 16 bits to 0. */ - FAIL_IF(push_inst16(compiler, IT | (cc << 4) | 0x8)); - return push_inst32(compiler, MOVW | RD4(dst_reg) - | COPY_BITS(tmp, 12, 16, 4) | COPY_BITS(tmp, 11, 26, 1) | COPY_BITS(tmp, 8, 12, 3) | (tmp & 0xff)); - } - - tmp = get_imm((sljit_uw)srcw); - if (tmp != INVALID_IMM) { - FAIL_IF(push_inst16(compiler, IT | (cc << 4) | 0x8)); - return push_inst32(compiler, MOV_WI | RD4(dst_reg) | tmp); - } - - tmp = get_imm(~(sljit_uw)srcw); - if (tmp != INVALID_IMM) { - FAIL_IF(push_inst16(compiler, IT | (cc << 4) | 0x8)); - return push_inst32(compiler, MVN_WI | RD4(dst_reg) | tmp); - } - - FAIL_IF(push_inst16(compiler, IT | (cc << 4) | ((cc & 0x1) << 3) | 0x4)); - - tmp = (sljit_uw) srcw; - FAIL_IF(push_inst32(compiler, MOVW | RD4(dst_reg) - | COPY_BITS(tmp, 12, 16, 4) | COPY_BITS(tmp, 11, 26, 1) | COPY_BITS(tmp, 8, 12, 3) | (tmp & 0xff))); - return push_inst32(compiler, MOVT | RD4(dst_reg) - | COPY_BITS(tmp, 12 + 16, 16, 4) | COPY_BITS(tmp, 11 + 16, 26, 1) | COPY_BITS(tmp, 8 + 16, 12, 3) | ((tmp & 0xff0000) >> 16)); -} - -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) -{ - sljit_s32 flags; - sljit_uw imm, tmp; - - CHECK_ERROR(); - CHECK(check_sljit_emit_mem(compiler, type, reg, mem, memw)); - - if (!(reg & REG_PAIR_MASK)) - return sljit_emit_mem_unaligned(compiler, type, reg, mem, memw); - - if (type & (SLJIT_MEM_UNALIGNED | SLJIT_MEM_UNALIGNED_16 | SLJIT_MEM_UNALIGNED_32)) { - if ((mem & REG_MASK) == 0) { - if ((memw & 0xfff) >= (0x1000 - SSIZE_OF(sw))) { - imm = get_imm((sljit_uw)((memw + 0x1000) & ~0xfff)); - - if (imm != INVALID_IMM) - memw = (memw & 0xfff) - 0x1000; - } else { - imm = get_imm((sljit_uw)(memw & ~0xfff)); - - if (imm != INVALID_IMM) - memw &= 0xff; - } - - if (imm == INVALID_IMM) { - FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)memw)); - memw = 0; - } else - FAIL_IF(push_inst32(compiler, MOV_WI | RD4(TMP_REG1) | imm)); - - mem = SLJIT_MEM1(TMP_REG1); - } else if (mem & OFFS_REG_MASK) { - FAIL_IF(push_inst32(compiler, ADD_W | RD4(TMP_REG1) | RN4(mem & REG_MASK) | RM4(OFFS_REG(mem)) | ((sljit_uw)(memw & 0x3) << 6))); - memw = 0; - mem = SLJIT_MEM1(TMP_REG1); - } else if (memw < -0xff) { - /* Zero value can be included in the first case. */ - if ((-memw & 0xfff) <= SSIZE_OF(sw)) - tmp = (sljit_uw)((-memw + 0x7ff) & ~0x7ff); - else - tmp = (sljit_uw)((-memw + 0xfff) & ~0xfff); - - SLJIT_ASSERT(tmp >= (sljit_uw)-memw); - imm = get_imm(tmp); - - if (imm != INVALID_IMM) { - FAIL_IF(push_inst32(compiler, SUB_WI | RD4(TMP_REG1) | RN4(mem & REG_MASK) | imm)); - memw += (sljit_sw)tmp; - SLJIT_ASSERT(memw >= 0 && memw <= 0xfff - SSIZE_OF(sw)); - } else { - FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)memw)); - FAIL_IF(push_inst16(compiler, ADD | SET_REGS44(TMP_REG1, mem & REG_MASK))); - memw = 0; - } - - mem = SLJIT_MEM1(TMP_REG1); - } else if (memw >= (0x1000 - SSIZE_OF(sw))) { - if ((memw & 0xfff) >= (0x1000 - SSIZE_OF(sw))) { - imm = get_imm((sljit_uw)((memw + 0x1000) & ~0xfff)); - - if (imm != INVALID_IMM) - memw = (memw & 0xfff) - 0x1000; - } else { - imm = get_imm((sljit_uw)(memw & ~0xfff)); - - if (imm != INVALID_IMM) - memw &= 0xfff; - } - - if (imm != INVALID_IMM) { - SLJIT_ASSERT(memw >= -0xff && memw <= 0xfff); - FAIL_IF(push_inst32(compiler, ADD_WI | RD4(TMP_REG1) | RN4(mem & REG_MASK) | imm)); - } else { - FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)memw)); - FAIL_IF(push_inst16(compiler, ADD | SET_REGS44(TMP_REG1, mem & REG_MASK))); - memw = 0; - } - - mem = SLJIT_MEM1(TMP_REG1); - } - - flags = WORD_SIZE; - - SLJIT_ASSERT(memw <= 0xfff - SSIZE_OF(sw) && memw >= -0xff); - - if (type & SLJIT_MEM_STORE) { - flags |= STORE; - } else if (REG_PAIR_FIRST(reg) == (mem & REG_MASK)) { - FAIL_IF(emit_op_mem(compiler, WORD_SIZE, REG_PAIR_SECOND(reg), mem, memw + SSIZE_OF(sw), TMP_REG2)); - return emit_op_mem(compiler, WORD_SIZE, REG_PAIR_FIRST(reg), mem, memw, TMP_REG2); - } - - FAIL_IF(emit_op_mem(compiler, flags, REG_PAIR_FIRST(reg), mem, memw, TMP_REG2)); - return emit_op_mem(compiler, flags, REG_PAIR_SECOND(reg), mem, memw + SSIZE_OF(sw), TMP_REG2); - } - - flags = 1 << 23; - - if ((mem & REG_MASK) == 0) { - tmp = (sljit_uw)(memw & 0x7fc); - imm = get_imm((sljit_uw)((memw + (tmp <= 0x400 ? 0 : 0x400)) & ~0x3fc)); - - if (imm == INVALID_IMM) { - FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)memw)); - memw = 0; - } else { - FAIL_IF(push_inst32(compiler, MOV_WI | RD4(TMP_REG1) | imm)); - memw = (memw & 0x3fc) >> 2; - - if (tmp > 0x400) { - memw = 0x100 - memw; - flags = 0; - } - - SLJIT_ASSERT(memw >= 0 && memw <= 0xff); - } - - mem = SLJIT_MEM1(TMP_REG1); - } else if (mem & OFFS_REG_MASK) { - FAIL_IF(push_inst32(compiler, ADD_W | RD4(TMP_REG1) | RN4(mem & REG_MASK) | RM4(OFFS_REG(mem)) | ((sljit_uw)(memw & 0x3) << 6))); - memw = 0; - mem = SLJIT_MEM1(TMP_REG1); - } else if (memw < 0) { - if ((-memw & ~0x3fc) == 0) { - flags = 0; - memw = -memw >> 2; - } else { - tmp = (sljit_uw)(-memw & 0x7fc); - imm = get_imm((sljit_uw)((-memw + (tmp <= 0x400 ? 0 : 0x400)) & ~0x3fc)); - - if (imm != INVALID_IMM) { - FAIL_IF(push_inst32(compiler, SUB_WI | RD4(TMP_REG1) | RN4(mem & REG_MASK) | imm)); - memw = (-memw & 0x3fc) >> 2; - - if (tmp <= 0x400) - flags = 0; - else - memw = 0x100 - memw; - } else { - FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)memw)); - FAIL_IF(push_inst16(compiler, ADD | SET_REGS44(TMP_REG1, mem & REG_MASK))); - memw = 0; - } - - mem = SLJIT_MEM1(TMP_REG1); - } - } else if ((memw & ~0x3fc) != 0) { - tmp = (sljit_uw)(memw & 0x7fc); - imm = get_imm((sljit_uw)((memw + (tmp <= 0x400 ? 0 : 0x400)) & ~0x3fc)); - - if (imm != INVALID_IMM) { - FAIL_IF(push_inst32(compiler, ADD_WI | RD4(TMP_REG1) | RN4(mem & REG_MASK) | imm)); - memw = (memw & 0x3fc) >> 2; - - if (tmp > 0x400) { - memw = 0x100 - memw; - flags = 0; - } - } else { - FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)memw)); - FAIL_IF(push_inst16(compiler, ADD | SET_REGS44(TMP_REG1, mem & REG_MASK))); - memw = 0; - } - - mem = SLJIT_MEM1(TMP_REG1); - } else - memw >>= 2; - - SLJIT_ASSERT(memw >= 0 && memw <= 0xff); - return push_inst32(compiler, ((type & SLJIT_MEM_STORE) ? STRD : LDRD) | (sljit_ins)flags | RN4(mem & REG_MASK) | RT4(REG_PAIR_FIRST(reg)) | RD4(REG_PAIR_SECOND(reg)) | (sljit_ins)memw); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem_update(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 reg, - sljit_s32 mem, sljit_sw memw) -{ - sljit_s32 flags; - sljit_ins inst; - - CHECK_ERROR(); - CHECK(check_sljit_emit_mem_update(compiler, type, reg, mem, memw)); - - if ((mem & OFFS_REG_MASK) || (memw > 255 || memw < -255)) - return SLJIT_ERR_UNSUPPORTED; - - if (type & SLJIT_MEM_SUPP) - return SLJIT_SUCCESS; - - switch (type & 0xff) { - case SLJIT_MOV: - case SLJIT_MOV_U32: - case SLJIT_MOV_S32: - case SLJIT_MOV32: - case SLJIT_MOV_P: - flags = WORD_SIZE; - break; - case SLJIT_MOV_U8: - flags = BYTE_SIZE; - break; - case SLJIT_MOV_S8: - flags = BYTE_SIZE | SIGNED; - break; - case SLJIT_MOV_U16: - flags = HALF_SIZE; - break; - case SLJIT_MOV_S16: - flags = HALF_SIZE | SIGNED; - break; - default: - SLJIT_UNREACHABLE(); - flags = WORD_SIZE; - break; - } - - if (type & SLJIT_MEM_STORE) - flags |= STORE; - - inst = sljit_mem32[flags] | 0x900; - - if (!(type & SLJIT_MEM_POST)) - inst |= 0x400; - - if (memw >= 0) - inst |= 0x200; - else - memw = -memw; - - return push_inst32(compiler, inst | RT4(reg) | RN4(mem & REG_MASK) | (sljit_ins)memw); -} - -static sljit_s32 update_mem_addr(struct sljit_compiler *compiler, sljit_s32 *mem, sljit_sw *memw, sljit_s32 max_offset) -{ - sljit_s32 arg = *mem; - sljit_sw argw = *memw; - sljit_uw imm; - - *mem = TMP_REG1; - - if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) { - *memw = 0; - return push_inst32(compiler, ADD_W | RD4(TMP_REG1) | RN4(arg & REG_MASK) | RM4(OFFS_REG(arg)) | ((sljit_uw)(argw & 0x3) << 6)); - } - - arg &= REG_MASK; - - if (arg) { - if (argw <= max_offset && argw >= -0xff) { - *mem = arg; - return SLJIT_SUCCESS; - } - - if (argw < 0) { - imm = get_imm((sljit_uw)(-argw & ~0xff)); - - if (imm) { - *memw = -(-argw & 0xff); - return push_inst32(compiler, SUB_WI | RD4(TMP_REG1) | RN4(arg) | imm); - } - } else if ((argw & 0xfff) <= max_offset) { - imm = get_imm((sljit_uw)(argw & ~0xfff)); - - if (imm) { - *memw = argw & 0xfff; - return push_inst32(compiler, ADD_WI | RD4(TMP_REG1) | RN4(arg) | imm); - } - } else { - imm = get_imm((sljit_uw)((argw | 0xfff) + 1)); - - if (imm) { - *memw = (argw & 0xfff) - 0x1000; - return push_inst32(compiler, ADD_WI | RD4(TMP_REG1) | RN4(arg) | imm); - } - } - } - - imm = (sljit_uw)(argw & ~0xfff); - - if ((argw & 0xfff) > max_offset) { - imm += 0x1000; - *memw = (argw & 0xfff) - 0x1000; - } else - *memw = argw & 0xfff; - - FAIL_IF(load_immediate(compiler, TMP_REG1, imm)); - - if (arg == 0) - return SLJIT_SUCCESS; - - return push_inst16(compiler, ADD | SET_REGS44(TMP_REG1, arg)); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fmem(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 freg, - sljit_s32 mem, sljit_sw memw) -{ - CHECK_ERROR(); - CHECK(check_sljit_emit_fmem(compiler, type, freg, mem, memw)); - - if (type & SLJIT_MEM_UNALIGNED_32) - return emit_fop_mem(compiler, ((type ^ SLJIT_32) & SLJIT_32) | ((type & SLJIT_MEM_STORE) ? 0 : FPU_LOAD), freg, mem, memw); - - if (type & SLJIT_MEM_STORE) { - FAIL_IF(push_inst32(compiler, VMOV | (1 << 20) | DN4(freg) | RT4(TMP_REG2))); - - if (type & SLJIT_32) - return emit_op_mem(compiler, WORD_SIZE | STORE, TMP_REG2, mem, memw, TMP_REG1); - - FAIL_IF(update_mem_addr(compiler, &mem, &memw, 0xfff - 4)); - mem |= SLJIT_MEM; - - FAIL_IF(emit_op_mem(compiler, WORD_SIZE | STORE, TMP_REG2, mem, memw, TMP_REG1)); - FAIL_IF(push_inst32(compiler, VMOV | (1 << 20) | DN4(freg) | 0x80 | RT4(TMP_REG2))); - return emit_op_mem(compiler, WORD_SIZE | STORE, TMP_REG2, mem, memw + 4, TMP_REG1); - } - - if (type & SLJIT_32) { - FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG2, mem, memw, TMP_REG1)); - return push_inst32(compiler, VMOV | DN4(freg) | RT4(TMP_REG2)); - } - - FAIL_IF(update_mem_addr(compiler, &mem, &memw, 0xfff - 4)); - mem |= SLJIT_MEM; - - FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG2, mem, memw, TMP_REG1)); - FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG1, mem, memw + 4, TMP_REG1)); - return push_inst32(compiler, VMOV2 | DM4(freg) | RT4(TMP_REG2) | RN4(TMP_REG1)); -} - -#undef FPU_LOAD - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value) -{ - struct sljit_const *const_; - sljit_s32 dst_r; - - CHECK_ERROR_PTR(); - 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_REG1; - PTR_FAIL_IF(emit_imm32_const(compiler, dst_r, (sljit_uw)init_value)); - - if (dst & SLJIT_MEM) - PTR_FAIL_IF(emit_op_mem(compiler, WORD_SIZE | STORE, dst_r, dst, dstw, TMP_REG2)); - return const_; -} - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label* sljit_emit_put_label(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw) -{ - struct sljit_put_label *put_label; - sljit_s32 dst_r; - - CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_put_label(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); - - dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1; - PTR_FAIL_IF(emit_imm32_const(compiler, dst_r, 0)); - - if (dst & SLJIT_MEM) - PTR_FAIL_IF(emit_op_mem(compiler, WORD_SIZE | STORE, dst_r, dst, dstw, TMP_REG2)); - return put_label; -} - -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset) -{ - sljit_u16 *inst = (sljit_u16*)addr; - SLJIT_UNUSED_ARG(executable_offset); - - SLJIT_UPDATE_WX_FLAGS(inst, inst + 4, 0); - modify_imm32_const(inst, new_target); - SLJIT_UPDATE_WX_FLAGS(inst, inst + 4, 1); - inst = (sljit_u16 *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset); - SLJIT_CACHE_FLUSH(inst, inst + 4); -} - -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset) -{ - sljit_set_jump_addr(addr, (sljit_uw)new_constant, executable_offset); -} diff --git a/modules/regex/pcre2/src/sljit/sljitNativeMIPS_32.c b/modules/regex/pcre2/src/sljit/sljitNativeMIPS_32.c deleted file mode 100644 index e6853c9..0000000 --- a/modules/regex/pcre2/src/sljit/sljitNativeMIPS_32.c +++ /dev/null @@ -1,314 +0,0 @@ -/* - * 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. - */ - -/* mips 32-bit arch dependent functions. */ - -static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_ar, sljit_sw imm) -{ - if (!(imm & ~0xffff)) - return push_inst(compiler, ORI | SA(0) | TA(dst_ar) | IMM(imm), dst_ar); - - if (imm < 0 && imm >= SIMM_MIN) - return push_inst(compiler, ADDIU | SA(0) | TA(dst_ar) | IMM(imm), dst_ar); - - FAIL_IF(push_inst(compiler, LUI | TA(dst_ar) | IMM(imm >> 16), dst_ar)); - return (imm & 0xffff) ? push_inst(compiler, ORI | SA(dst_ar) | TA(dst_ar) | IMM(imm), dst_ar) : SLJIT_SUCCESS; -} - -static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw init_value) -{ - FAIL_IF(push_inst(compiler, LUI | T(dst) | IMM(init_value >> 16), DR(dst))); - return push_inst(compiler, ORI | S(dst) | T(dst) | IMM(init_value), DR(dst)); -} - -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset) -{ - sljit_ins *inst = (sljit_ins *)addr; - SLJIT_UNUSED_ARG(executable_offset); - - SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 0); - SLJIT_ASSERT((inst[0] & 0xffe00000) == LUI && (inst[1] & 0xfc000000) == ORI); - inst[0] = (inst[0] & 0xffff0000) | ((new_target >> 16) & 0xffff); - inst[1] = (inst[1] & 0xffff0000) | (new_target & 0xffff); - SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 1); - inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset); - SLJIT_CACHE_FLUSH(inst, inst + 2); -} - -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset) -{ - sljit_set_jump_addr(addr, (sljit_uw)new_constant, executable_offset); -} - -static sljit_s32 call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_types, sljit_ins *ins_ptr, sljit_u32 *extra_space) -{ - sljit_u32 is_tail_call = *extra_space & SLJIT_CALL_RETURN; - sljit_u32 offset = 0; - sljit_s32 float_arg_count = 0; - sljit_s32 word_arg_count = 0; - sljit_s32 types = 0; - sljit_ins prev_ins = NOP; - sljit_ins ins = NOP; - sljit_u8 offsets[4]; - sljit_u8 *offsets_ptr = offsets; - - SLJIT_ASSERT(reg_map[TMP_REG1] == 4 && freg_map[TMP_FREG1] == 12); - - arg_types >>= SLJIT_ARG_SHIFT; - - /* See ABI description in sljit_emit_enter. */ - - while (arg_types) { - types = (types << SLJIT_ARG_SHIFT) | (arg_types & SLJIT_ARG_MASK); - *offsets_ptr = (sljit_u8)offset; - - switch (arg_types & SLJIT_ARG_MASK) { - case SLJIT_ARG_TYPE_F64: - if (offset & 0x7) { - offset += sizeof(sljit_sw); - *offsets_ptr = (sljit_u8)offset; - } - - if (word_arg_count == 0 && float_arg_count <= 1) - *offsets_ptr = (sljit_u8)(254 + float_arg_count); - - offset += sizeof(sljit_f64); - float_arg_count++; - break; - case SLJIT_ARG_TYPE_F32: - if (word_arg_count == 0 && float_arg_count <= 1) - *offsets_ptr = (sljit_u8)(254 + float_arg_count); - - offset += sizeof(sljit_f32); - float_arg_count++; - break; - default: - offset += sizeof(sljit_sw); - word_arg_count++; - break; - } - - arg_types >>= SLJIT_ARG_SHIFT; - offsets_ptr++; - } - - /* Stack is aligned to 16 bytes. */ - SLJIT_ASSERT(offset <= 8 * sizeof(sljit_sw)); - - if (offset > 4 * sizeof(sljit_sw) && (!is_tail_call || offset > compiler->args_size)) { - if (is_tail_call) { - offset = (offset + sizeof(sljit_sw) + 15) & ~(sljit_uw)0xf; - FAIL_IF(emit_stack_frame_release(compiler, (sljit_s32)offset, &prev_ins)); - *extra_space = offset; - } else { - FAIL_IF(push_inst(compiler, ADDIU | S(SLJIT_SP) | T(SLJIT_SP) | IMM(-16), DR(SLJIT_SP))); - *extra_space = 16; - } - } else { - if (is_tail_call) - FAIL_IF(emit_stack_frame_release(compiler, 0, &prev_ins)); - *extra_space = 0; - } - - while (types) { - --offsets_ptr; - - switch (types & SLJIT_ARG_MASK) { - case SLJIT_ARG_TYPE_F64: - if (*offsets_ptr < 4 * sizeof (sljit_sw)) { - if (prev_ins != NOP) - FAIL_IF(push_inst(compiler, prev_ins, MOVABLE_INS)); - - /* Must be preceded by at least one other argument, - * and its starting offset must be 8 because of alignment. */ - SLJIT_ASSERT((*offsets_ptr >> 2) == 2); - - prev_ins = MFC1 | TA(6) | FS(float_arg_count) | (1 << 11); - ins = MFC1 | TA(7) | FS(float_arg_count); - } else if (*offsets_ptr < 254) - ins = SDC1 | S(SLJIT_SP) | FT(float_arg_count) | IMM(*offsets_ptr); - else if (*offsets_ptr == 254) - ins = MOV_S | FMT_D | FS(SLJIT_FR0) | FD(TMP_FREG1); - - float_arg_count--; - break; - case SLJIT_ARG_TYPE_F32: - if (*offsets_ptr < 4 * sizeof (sljit_sw)) - ins = MFC1 | TA(4 + (*offsets_ptr >> 2)) | FS(float_arg_count); - else if (*offsets_ptr < 254) - ins = SWC1 | S(SLJIT_SP) | FT(float_arg_count) | IMM(*offsets_ptr); - else if (*offsets_ptr == 254) - ins = MOV_S | FMT_S | FS(SLJIT_FR0) | FD(TMP_FREG1); - - float_arg_count--; - break; - default: - if (*offsets_ptr >= 4 * sizeof (sljit_sw)) - ins = SW | S(SLJIT_SP) | T(word_arg_count) | IMM(*offsets_ptr); - else if ((*offsets_ptr >> 2) != word_arg_count - 1) - ins = ADDU | S(word_arg_count) | TA(0) | DA(4 + (*offsets_ptr >> 2)); - else if (*offsets_ptr == 0) - ins = ADDU | S(SLJIT_R0) | TA(0) | DA(4); - - word_arg_count--; - break; - } - - if (ins != NOP) { - if (prev_ins != NOP) - FAIL_IF(push_inst(compiler, prev_ins, MOVABLE_INS)); - prev_ins = ins; - ins = NOP; - } - - types >>= SLJIT_ARG_SHIFT; - } - - *ins_ptr = prev_ins; - - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_call(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 arg_types) -{ - struct sljit_jump *jump; - sljit_u32 extra_space = 0; - sljit_ins ins = NOP; - - CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_call(compiler, type, arg_types)); - - jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump)); - PTR_FAIL_IF(!jump); - set_jump(jump, compiler, type & SLJIT_REWRITABLE_JUMP); - - if ((type & 0xff) != SLJIT_CALL_REG_ARG) { - extra_space = (sljit_u32)type; - PTR_FAIL_IF(call_with_args(compiler, arg_types, &ins, &extra_space)); - } 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); - - if (ins == NOP && compiler->delay_slot != UNMOVABLE_INS) - jump->flags |= IS_MOVABLE; - - if (!(type & SLJIT_CALL_RETURN) || extra_space > 0) { - jump->flags |= IS_JAL; - - if ((type & 0xff) != SLJIT_CALL_REG_ARG) - jump->flags |= IS_CALL; - - PTR_FAIL_IF(push_inst(compiler, JALR | S(PIC_ADDR_REG) | DA(RETURN_ADDR_REG), UNMOVABLE_INS)); - } else - PTR_FAIL_IF(push_inst(compiler, JR | S(PIC_ADDR_REG), UNMOVABLE_INS)); - - jump->addr = compiler->size; - PTR_FAIL_IF(push_inst(compiler, ins, UNMOVABLE_INS)); - - /* Maximum number of instructions required for generating a constant. */ - compiler->size += 2; - - if (extra_space == 0) - return jump; - - if (type & SLJIT_CALL_RETURN) - PTR_FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, RETURN_ADDR_REG, - SLJIT_MEM1(SLJIT_SP), (sljit_sw)(extra_space - sizeof(sljit_sw)))); - - if (type & SLJIT_CALL_RETURN) - PTR_FAIL_IF(push_inst(compiler, JR | SA(RETURN_ADDR_REG), UNMOVABLE_INS)); - - PTR_FAIL_IF(push_inst(compiler, ADDIU | S(SLJIT_SP) | T(SLJIT_SP) | IMM(extra_space), - (type & SLJIT_CALL_RETURN) ? UNMOVABLE_INS : DR(SLJIT_SP))); - return jump; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 arg_types, - sljit_s32 src, sljit_sw srcw) -{ - sljit_u32 extra_space = (sljit_u32)type; - sljit_ins ins; - - CHECK_ERROR(); - CHECK(check_sljit_emit_icall(compiler, type, arg_types, src, srcw)); - - if (src & SLJIT_MEM) { - ADJUST_LOCAL_OFFSET(src, srcw); - FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, DR(PIC_ADDR_REG), src, srcw)); - src = PIC_ADDR_REG; - srcw = 0; - } - - if ((type & 0xff) == SLJIT_CALL_REG_ARG) { - if (type & SLJIT_CALL_RETURN) { - if (src >= SLJIT_FIRST_SAVED_REG && src <= (SLJIT_S0 - SLJIT_KEPT_SAVEDS_COUNT(compiler->options))) { - FAIL_IF(push_inst(compiler, ADDU | S(src) | TA(0) | D(PIC_ADDR_REG), DR(PIC_ADDR_REG))); - src = PIC_ADDR_REG; - srcw = 0; - } - - FAIL_IF(emit_stack_frame_release(compiler, 0, &ins)); - - if (ins != NOP) - FAIL_IF(push_inst(compiler, ins, MOVABLE_INS)); - } - - SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_ijump(compiler, type, src, srcw); - } - - SLJIT_ASSERT(DR(PIC_ADDR_REG) == 25 && PIC_ADDR_REG == TMP_REG2); - - if (src & SLJIT_IMM) - FAIL_IF(load_immediate(compiler, DR(PIC_ADDR_REG), srcw)); - else if (src != PIC_ADDR_REG) - FAIL_IF(push_inst(compiler, ADDU | S(src) | TA(0) | D(PIC_ADDR_REG), DR(PIC_ADDR_REG))); - - FAIL_IF(call_with_args(compiler, arg_types, &ins, &extra_space)); - - /* Register input. */ - if (!(type & SLJIT_CALL_RETURN) || extra_space > 0) - FAIL_IF(push_inst(compiler, JALR | S(PIC_ADDR_REG) | DA(RETURN_ADDR_REG), UNMOVABLE_INS)); - else - FAIL_IF(push_inst(compiler, JR | S(PIC_ADDR_REG), UNMOVABLE_INS)); - FAIL_IF(push_inst(compiler, ins, UNMOVABLE_INS)); - - if (extra_space == 0) - return SLJIT_SUCCESS; - - if (type & SLJIT_CALL_RETURN) - FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, RETURN_ADDR_REG, - SLJIT_MEM1(SLJIT_SP), (sljit_sw)(extra_space - sizeof(sljit_sw)))); - - if (type & SLJIT_CALL_RETURN) - FAIL_IF(push_inst(compiler, JR | SA(RETURN_ADDR_REG), UNMOVABLE_INS)); - - return push_inst(compiler, ADDIU | S(SLJIT_SP) | T(SLJIT_SP) | IMM(extra_space), - (type & SLJIT_CALL_RETURN) ? UNMOVABLE_INS : DR(SLJIT_SP)); -} diff --git a/modules/regex/pcre2/src/sljit/sljitNativeMIPS_64.c b/modules/regex/pcre2/src/sljit/sljitNativeMIPS_64.c deleted file mode 100644 index d2a5924..0000000 --- a/modules/regex/pcre2/src/sljit/sljitNativeMIPS_64.c +++ /dev/null @@ -1,319 +0,0 @@ -/* - * 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. - */ - -/* mips 64-bit arch dependent functions. */ - -static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_ar, sljit_sw imm) -{ - sljit_s32 shift = 32; - sljit_s32 shift2; - sljit_s32 inv = 0; - sljit_ins ins; - sljit_uw uimm; - - if (!(imm & ~0xffff)) - return push_inst(compiler, ORI | SA(0) | TA(dst_ar) | IMM(imm), dst_ar); - - if (imm < 0 && imm >= SIMM_MIN) - return push_inst(compiler, ADDIU | SA(0) | TA(dst_ar) | IMM(imm), dst_ar); - - if (imm <= 0x7fffffffl && imm >= -0x80000000l) { - FAIL_IF(push_inst(compiler, LUI | TA(dst_ar) | IMM(imm >> 16), dst_ar)); - return (imm & 0xffff) ? push_inst(compiler, ORI | SA(dst_ar) | TA(dst_ar) | IMM(imm), dst_ar) : SLJIT_SUCCESS; - } - - /* Zero extended number. */ - uimm = (sljit_uw)imm; - if (imm < 0) { - uimm = ~(sljit_uw)imm; - inv = 1; - } - - while (!(uimm & 0xff00000000000000l)) { - shift -= 8; - uimm <<= 8; - } - - if (!(uimm & 0xf000000000000000l)) { - shift -= 4; - uimm <<= 4; - } - - if (!(uimm & 0xc000000000000000l)) { - shift -= 2; - uimm <<= 2; - } - - if ((sljit_sw)uimm < 0) { - uimm >>= 1; - shift += 1; - } - SLJIT_ASSERT(((uimm & 0xc000000000000000l) == 0x4000000000000000l) && (shift > 0) && (shift <= 32)); - - if (inv) - uimm = ~uimm; - - FAIL_IF(push_inst(compiler, LUI | TA(dst_ar) | IMM(uimm >> 48), dst_ar)); - if (uimm & 0x0000ffff00000000l) - FAIL_IF(push_inst(compiler, ORI | SA(dst_ar) | TA(dst_ar) | IMM(uimm >> 32), dst_ar)); - - imm &= (1l << shift) - 1; - if (!(imm & ~0xffff)) { - ins = (shift == 32) ? DSLL32 : DSLL; - if (shift < 32) - ins |= SH_IMM(shift); - FAIL_IF(push_inst(compiler, ins | TA(dst_ar) | DA(dst_ar), dst_ar)); - return !(imm & 0xffff) ? SLJIT_SUCCESS : push_inst(compiler, ORI | SA(dst_ar) | TA(dst_ar) | IMM(imm), dst_ar); - } - - /* Double shifts needs to be performed. */ - uimm <<= 32; - shift2 = shift - 16; - - while (!(uimm & 0xf000000000000000l)) { - shift2 -= 4; - uimm <<= 4; - } - - if (!(uimm & 0xc000000000000000l)) { - shift2 -= 2; - uimm <<= 2; - } - - if (!(uimm & 0x8000000000000000l)) { - shift2--; - uimm <<= 1; - } - - SLJIT_ASSERT((uimm & 0x8000000000000000l) && (shift2 > 0) && (shift2 <= 16)); - - FAIL_IF(push_inst(compiler, DSLL | TA(dst_ar) | DA(dst_ar) | SH_IMM(shift - shift2), dst_ar)); - FAIL_IF(push_inst(compiler, ORI | SA(dst_ar) | TA(dst_ar) | IMM(uimm >> 48), dst_ar)); - FAIL_IF(push_inst(compiler, DSLL | TA(dst_ar) | DA(dst_ar) | SH_IMM(shift2), dst_ar)); - - imm &= (1l << shift2) - 1; - return !(imm & 0xffff) ? SLJIT_SUCCESS : push_inst(compiler, ORI | SA(dst_ar) | TA(dst_ar) | IMM(imm), dst_ar); -} - -static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw init_value) -{ - FAIL_IF(push_inst(compiler, LUI | T(dst) | IMM(init_value >> 48), DR(dst))); - FAIL_IF(push_inst(compiler, ORI | S(dst) | T(dst) | IMM(init_value >> 32), DR(dst))); - FAIL_IF(push_inst(compiler, DSLL | T(dst) | D(dst) | SH_IMM(16), DR(dst))); - FAIL_IF(push_inst(compiler, ORI | S(dst) | T(dst) | IMM(init_value >> 16), DR(dst))); - FAIL_IF(push_inst(compiler, DSLL | T(dst) | D(dst) | SH_IMM(16), DR(dst))); - return push_inst(compiler, ORI | S(dst) | T(dst) | IMM(init_value), DR(dst)); -} - -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset) -{ - sljit_ins *inst = (sljit_ins *)addr; - SLJIT_UNUSED_ARG(executable_offset); - - SLJIT_UPDATE_WX_FLAGS(inst, inst + 6, 0); - inst[0] = (inst[0] & 0xffff0000) | ((sljit_ins)(new_target >> 48) & 0xffff); - inst[1] = (inst[1] & 0xffff0000) | ((sljit_ins)(new_target >> 32) & 0xffff); - inst[3] = (inst[3] & 0xffff0000) | ((sljit_ins)(new_target >> 16) & 0xffff); - inst[5] = (inst[5] & 0xffff0000) | ((sljit_ins)new_target & 0xffff); - SLJIT_UPDATE_WX_FLAGS(inst, inst + 6, 1); - inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset); - SLJIT_CACHE_FLUSH(inst, inst + 6); -} - -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset) -{ - sljit_set_jump_addr(addr, (sljit_uw)new_constant, executable_offset); -} - -static sljit_s32 call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_types, sljit_ins *ins_ptr) -{ - sljit_s32 arg_count = 0; - sljit_s32 word_arg_count = 0; - sljit_s32 float_arg_count = 0; - sljit_s32 types = 0; - sljit_ins prev_ins = *ins_ptr; - sljit_ins ins = NOP; - - SLJIT_ASSERT(reg_map[TMP_REG1] == 4 && freg_map[TMP_FREG1] == 12); - - arg_types >>= SLJIT_ARG_SHIFT; - - while (arg_types) { - types = (types << SLJIT_ARG_SHIFT) | (arg_types & SLJIT_ARG_MASK); - - switch (arg_types & SLJIT_ARG_MASK) { - case SLJIT_ARG_TYPE_F64: - case SLJIT_ARG_TYPE_F32: - arg_count++; - float_arg_count++; - break; - default: - arg_count++; - word_arg_count++; - break; - } - - arg_types >>= SLJIT_ARG_SHIFT; - } - - while (types) { - switch (types & SLJIT_ARG_MASK) { - case SLJIT_ARG_TYPE_F64: - if (arg_count != float_arg_count) - ins = MOV_S | FMT_D | FS(float_arg_count) | FD(arg_count); - else if (arg_count == 1) - ins = MOV_S | FMT_D | FS(SLJIT_FR0) | FD(TMP_FREG1); - arg_count--; - float_arg_count--; - break; - case SLJIT_ARG_TYPE_F32: - if (arg_count != float_arg_count) - ins = MOV_S | FMT_S | FS(float_arg_count) | FD(arg_count); - else if (arg_count == 1) - ins = MOV_S | FMT_S | FS(SLJIT_FR0) | FD(TMP_FREG1); - arg_count--; - float_arg_count--; - break; - default: - if (arg_count != word_arg_count) - ins = DADDU | S(word_arg_count) | TA(0) | D(arg_count); - else if (arg_count == 1) - ins = DADDU | S(SLJIT_R0) | TA(0) | DA(4); - arg_count--; - word_arg_count--; - break; - } - - if (ins != NOP) { - if (prev_ins != NOP) - FAIL_IF(push_inst(compiler, prev_ins, MOVABLE_INS)); - prev_ins = ins; - ins = NOP; - } - - types >>= SLJIT_ARG_SHIFT; - } - - *ins_ptr = prev_ins; - - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_call(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 arg_types) -{ - struct sljit_jump *jump; - sljit_ins ins = NOP; - - CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_call(compiler, type, arg_types)); - - jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump)); - PTR_FAIL_IF(!jump); - set_jump(jump, compiler, type & SLJIT_REWRITABLE_JUMP); - - if (type & SLJIT_CALL_RETURN) - PTR_FAIL_IF(emit_stack_frame_release(compiler, 0, &ins)); - - 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); - - if (ins == NOP && compiler->delay_slot != UNMOVABLE_INS) - jump->flags |= IS_MOVABLE; - - if (!(type & SLJIT_CALL_RETURN)) { - jump->flags |= IS_JAL; - - if ((type & 0xff) != SLJIT_CALL_REG_ARG) - jump->flags |= IS_CALL; - - PTR_FAIL_IF(push_inst(compiler, JALR | S(PIC_ADDR_REG) | DA(RETURN_ADDR_REG), UNMOVABLE_INS)); - } else - PTR_FAIL_IF(push_inst(compiler, JR | S(PIC_ADDR_REG), UNMOVABLE_INS)); - - jump->addr = compiler->size; - PTR_FAIL_IF(push_inst(compiler, ins, UNMOVABLE_INS)); - - /* Maximum number of instructions required for generating a constant. */ - compiler->size += 6; - return jump; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 arg_types, - sljit_s32 src, sljit_sw srcw) -{ - sljit_ins ins = NOP; - - CHECK_ERROR(); - CHECK(check_sljit_emit_icall(compiler, type, arg_types, src, srcw)); - - if (src & SLJIT_MEM) { - ADJUST_LOCAL_OFFSET(src, srcw); - FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, DR(PIC_ADDR_REG), src, srcw)); - src = PIC_ADDR_REG; - srcw = 0; - } - - if ((type & 0xff) == SLJIT_CALL_REG_ARG) { - if (type & SLJIT_CALL_RETURN) { - if (src >= SLJIT_FIRST_SAVED_REG && src <= (SLJIT_S0 - SLJIT_KEPT_SAVEDS_COUNT(compiler->options))) { - FAIL_IF(push_inst(compiler, DADDU | S(src) | TA(0) | D(PIC_ADDR_REG), DR(PIC_ADDR_REG))); - src = PIC_ADDR_REG; - srcw = 0; - } - - FAIL_IF(emit_stack_frame_release(compiler, 0, &ins)); - - if (ins != NOP) - FAIL_IF(push_inst(compiler, ins, MOVABLE_INS)); - } - - SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_ijump(compiler, type, src, srcw); - } - - SLJIT_ASSERT(DR(PIC_ADDR_REG) == 25 && PIC_ADDR_REG == TMP_REG2); - - if (src & SLJIT_IMM) - FAIL_IF(load_immediate(compiler, DR(PIC_ADDR_REG), srcw)); - else if (src != PIC_ADDR_REG) - FAIL_IF(push_inst(compiler, DADDU | S(src) | TA(0) | D(PIC_ADDR_REG), DR(PIC_ADDR_REG))); - - if (type & SLJIT_CALL_RETURN) - FAIL_IF(emit_stack_frame_release(compiler, 0, &ins)); - - FAIL_IF(call_with_args(compiler, arg_types, &ins)); - - /* Register input. */ - if (!(type & SLJIT_CALL_RETURN)) - FAIL_IF(push_inst(compiler, JALR | S(PIC_ADDR_REG) | DA(RETURN_ADDR_REG), UNMOVABLE_INS)); - else - FAIL_IF(push_inst(compiler, JR | S(PIC_ADDR_REG), UNMOVABLE_INS)); - return push_inst(compiler, ins, UNMOVABLE_INS); -} diff --git a/modules/regex/pcre2/src/sljit/sljitNativeMIPS_common.c b/modules/regex/pcre2/src/sljit/sljitNativeMIPS_common.c deleted file mode 100644 index 9afe901..0000000 --- a/modules/regex/pcre2/src/sljit/sljitNativeMIPS_common.c +++ /dev/null @@ -1,3720 +0,0 @@ -/* - * 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. - */ - -/* Latest MIPS architecture. */ - -#ifndef __mips_hard_float -/* Disable automatic detection, covers both -msoft-float and -mno-float */ -#undef SLJIT_IS_FPU_AVAILABLE -#define SLJIT_IS_FPU_AVAILABLE 0 -#endif - -SLJIT_API_FUNC_ATTRIBUTE const char* sljit_get_platform_name(void) -{ -#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6) - -#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) - return "MIPS32-R6" SLJIT_CPUINFO; -#else /* !SLJIT_CONFIG_MIPS_32 */ - return "MIPS64-R6" SLJIT_CPUINFO; -#endif /* SLJIT_CONFIG_MIPS_32 */ - -#elif (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 2) - -#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) - return "MIPS32-R2" SLJIT_CPUINFO; -#else /* !SLJIT_CONFIG_MIPS_32 */ - return "MIPS64-R2" SLJIT_CPUINFO; -#endif /* SLJIT_CONFIG_MIPS_32 */ - -#elif (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1) - -#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) - return "MIPS32-R1" SLJIT_CPUINFO; -#else /* !SLJIT_CONFIG_MIPS_32 */ - return "MIPS64-R1" SLJIT_CPUINFO; -#endif /* SLJIT_CONFIG_MIPS_32 */ - -#else /* SLJIT_MIPS_REV < 1 */ - return "MIPS III" SLJIT_CPUINFO; -#endif /* SLJIT_MIPS_REV >= 6 */ -} - -/* Length of an instruction word - Both for mips-32 and mips-64 */ -typedef sljit_u32 sljit_ins; - -#define TMP_REG1 (SLJIT_NUMBER_OF_REGISTERS + 2) -#define TMP_REG2 (SLJIT_NUMBER_OF_REGISTERS + 3) -#define TMP_REG3 (SLJIT_NUMBER_OF_REGISTERS + 4) - -/* For position independent code, t9 must contain the function address. */ -#define PIC_ADDR_REG TMP_REG2 - -/* Floating point status register. */ -#define FCSR_REG 31 -/* Return address register. */ -#define RETURN_ADDR_REG 31 - -/* Flags are kept in volatile registers. */ -#define EQUAL_FLAG 3 -#define OTHER_FLAG 1 - -#define TMP_FREG1 (SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1) -#define TMP_FREG2 (SLJIT_NUMBER_OF_FLOAT_REGISTERS + 2) -#define TMP_FREG3 (SLJIT_NUMBER_OF_FLOAT_REGISTERS + 3) - -static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 5] = { - 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 -}; - -#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) - -static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 4] = { - 0, 0, 14, 2, 4, 6, 8, 18, 30, 28, 26, 24, 22, 20, 12, 10, 16 -}; - -#else - -static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 4] = { - 0, 0, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 1, 2, 3, 4, 5, 6, 7, 8, 9, 31, 30, 29, 28, 27, 26, 25, 24, 12, 11, 10 -}; - -#endif - -/* --------------------------------------------------------------------- */ -/* Instrucion forms */ -/* --------------------------------------------------------------------- */ - -#define S(s) ((sljit_ins)reg_map[s] << 21) -#define T(t) ((sljit_ins)reg_map[t] << 16) -#define D(d) ((sljit_ins)reg_map[d] << 11) -#define FT(t) ((sljit_ins)freg_map[t] << 16) -#define FS(s) ((sljit_ins)freg_map[s] << 11) -#define FD(d) ((sljit_ins)freg_map[d] << 6) -/* Absolute registers. */ -#define SA(s) ((sljit_ins)(s) << 21) -#define TA(t) ((sljit_ins)(t) << 16) -#define DA(d) ((sljit_ins)(d) << 11) -#define IMM(imm) ((sljit_ins)(imm) & 0xffff) -#define SH_IMM(imm) ((sljit_ins)(imm) << 6) - -#define DR(dr) (reg_map[dr]) -#define FR(dr) (freg_map[dr]) -#define HI(opcode) ((sljit_ins)(opcode) << 26) -#define LO(opcode) ((sljit_ins)(opcode)) -#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6) -/* CMP.cond.fmt */ -/* S = (20 << 21) D = (21 << 21) */ -#define CMP_FMT_S (20 << 21) -#endif /* SLJIT_MIPS_REV >= 6 */ -/* S = (16 << 21) D = (17 << 21) */ -#define FMT_S (16 << 21) -#define FMT_D (17 << 21) - -#define ABS_S (HI(17) | FMT_S | LO(5)) -#define ADD_S (HI(17) | FMT_S | LO(0)) -#define ADDIU (HI(9)) -#define ADDU (HI(0) | LO(33)) -#define AND (HI(0) | LO(36)) -#define ANDI (HI(12)) -#define B (HI(4)) -#define BAL (HI(1) | (17 << 16)) -#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6) -#define BC1EQZ (HI(17) | (9 << 21) | FT(TMP_FREG3)) -#define BC1NEZ (HI(17) | (13 << 21) | FT(TMP_FREG3)) -#else /* SLJIT_MIPS_REV < 6 */ -#define BC1F (HI(17) | (8 << 21)) -#define BC1T (HI(17) | (8 << 21) | (1 << 16)) -#endif /* SLJIT_MIPS_REV >= 6 */ -#define BEQ (HI(4)) -#define BGEZ (HI(1) | (1 << 16)) -#define BGTZ (HI(7)) -#define BLEZ (HI(6)) -#define BLTZ (HI(1) | (0 << 16)) -#define BNE (HI(5)) -#define BREAK (HI(0) | LO(13)) -#define CFC1 (HI(17) | (2 << 21)) -#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6) -#define C_EQ_S (HI(17) | CMP_FMT_S | LO(2)) -#define C_OLE_S (HI(17) | CMP_FMT_S | LO(6)) -#define C_OLT_S (HI(17) | CMP_FMT_S | LO(4)) -#define C_UEQ_S (HI(17) | CMP_FMT_S | LO(3)) -#define C_ULE_S (HI(17) | CMP_FMT_S | LO(7)) -#define C_ULT_S (HI(17) | CMP_FMT_S | LO(5)) -#define C_UN_S (HI(17) | CMP_FMT_S | LO(1)) -#define C_FD (FD(TMP_FREG3)) -#else /* SLJIT_MIPS_REV < 6 */ -#define C_EQ_S (HI(17) | FMT_S | LO(50)) -#define C_OLE_S (HI(17) | FMT_S | LO(54)) -#define C_OLT_S (HI(17) | FMT_S | LO(52)) -#define C_UEQ_S (HI(17) | FMT_S | LO(51)) -#define C_ULE_S (HI(17) | FMT_S | LO(55)) -#define C_ULT_S (HI(17) | FMT_S | LO(53)) -#define C_UN_S (HI(17) | FMT_S | LO(49)) -#define C_FD (0) -#endif /* SLJIT_MIPS_REV >= 6 */ -#define CVT_S_S (HI(17) | FMT_S | LO(32)) -#define DADDIU (HI(25)) -#define DADDU (HI(0) | LO(45)) -#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6) -#define DDIV (HI(0) | (2 << 6) | LO(30)) -#define DDIVU (HI(0) | (2 << 6) | LO(31)) -#define DMOD (HI(0) | (3 << 6) | LO(30)) -#define DMODU (HI(0) | (3 << 6) | LO(31)) -#define DIV (HI(0) | (2 << 6) | LO(26)) -#define DIVU (HI(0) | (2 << 6) | LO(27)) -#define DMUH (HI(0) | (3 << 6) | LO(28)) -#define DMUHU (HI(0) | (3 << 6) | LO(29)) -#define DMUL (HI(0) | (2 << 6) | LO(28)) -#define DMULU (HI(0) | (2 << 6) | LO(29)) -#else /* SLJIT_MIPS_REV < 6 */ -#define DDIV (HI(0) | LO(30)) -#define DDIVU (HI(0) | LO(31)) -#define DIV (HI(0) | LO(26)) -#define DIVU (HI(0) | LO(27)) -#define DMULT (HI(0) | LO(28)) -#define DMULTU (HI(0) | LO(29)) -#endif /* SLJIT_MIPS_REV >= 6 */ -#define DIV_S (HI(17) | FMT_S | LO(3)) -#define DINSU (HI(31) | LO(6)) -#define DROTR (HI(0) | (1 << 21) | LO(58)) -#define DROTR32 (HI(0) | (1 << 21) | LO(62)) -#define DROTRV (HI(0) | (1 << 6) | LO(22)) -#define DSLL (HI(0) | LO(56)) -#define DSLL32 (HI(0) | LO(60)) -#define DSLLV (HI(0) | LO(20)) -#define DSRA (HI(0) | LO(59)) -#define DSRA32 (HI(0) | LO(63)) -#define DSRAV (HI(0) | LO(23)) -#define DSRL (HI(0) | LO(58)) -#define DSRL32 (HI(0) | LO(62)) -#define DSRLV (HI(0) | LO(22)) -#define DSUBU (HI(0) | LO(47)) -#define J (HI(2)) -#define JAL (HI(3)) -#define JALR (HI(0) | LO(9)) -#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6) -#define JR (HI(0) | LO(9)) -#else /* SLJIT_MIPS_REV < 6 */ -#define JR (HI(0) | LO(8)) -#endif /* SLJIT_MIPS_REV >= 6 */ -#define LD (HI(55)) -#define LDL (HI(26)) -#define LDR (HI(27)) -#define LDC1 (HI(53)) -#define LUI (HI(15)) -#define LW (HI(35)) -#define LWL (HI(34)) -#define LWR (HI(38)) -#define LWC1 (HI(49)) -#define MFC1 (HI(17)) -#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6) -#define MOD (HI(0) | (3 << 6) | LO(26)) -#define MODU (HI(0) | (3 << 6) | LO(27)) -#else /* SLJIT_MIPS_REV < 6 */ -#define MFHI (HI(0) | LO(16)) -#define MFLO (HI(0) | LO(18)) -#endif /* SLJIT_MIPS_REV >= 6 */ -#define MOV_S (HI(17) | FMT_S | LO(6)) -#define MTC1 (HI(17) | (4 << 21)) -#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6) -#define MUH (HI(0) | (3 << 6) | LO(24)) -#define MUHU (HI(0) | (3 << 6) | LO(25)) -#define MUL (HI(0) | (2 << 6) | LO(24)) -#define MULU (HI(0) | (2 << 6) | LO(25)) -#else /* SLJIT_MIPS_REV < 6 */ -#define MULT (HI(0) | LO(24)) -#define MULTU (HI(0) | LO(25)) -#endif /* SLJIT_MIPS_REV >= 6 */ -#define MUL_S (HI(17) | FMT_S | LO(2)) -#define NEG_S (HI(17) | FMT_S | LO(7)) -#define NOP (HI(0) | LO(0)) -#define NOR (HI(0) | LO(39)) -#define OR (HI(0) | LO(37)) -#define ORI (HI(13)) -#define ROTR (HI(0) | (1 << 21) | LO(2)) -#define ROTRV (HI(0) | (1 << 6) | LO(6)) -#define SD (HI(63)) -#define SDL (HI(44)) -#define SDR (HI(45)) -#define SDC1 (HI(61)) -#define SLT (HI(0) | LO(42)) -#define SLTI (HI(10)) -#define SLTIU (HI(11)) -#define SLTU (HI(0) | LO(43)) -#define SLL (HI(0) | LO(0)) -#define SLLV (HI(0) | LO(4)) -#define SRL (HI(0) | LO(2)) -#define SRLV (HI(0) | LO(6)) -#define SRA (HI(0) | LO(3)) -#define SRAV (HI(0) | LO(7)) -#define SUB_S (HI(17) | FMT_S | LO(1)) -#define SUBU (HI(0) | LO(35)) -#define SW (HI(43)) -#define SWL (HI(42)) -#define SWR (HI(46)) -#define SWC1 (HI(57)) -#define TRUNC_W_S (HI(17) | FMT_S | LO(13)) -#define XOR (HI(0) | LO(38)) -#define XORI (HI(14)) - -#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1) -#define CLZ (HI(28) | LO(32)) -#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6) -#define DCLZ (LO(18)) -#else /* SLJIT_MIPS_REV < 6 */ -#define DCLZ (HI(28) | LO(36)) -#define MOVF (HI(0) | (0 << 16) | LO(1)) -#define MOVN (HI(0) | LO(11)) -#define MOVT (HI(0) | (1 << 16) | LO(1)) -#define MOVZ (HI(0) | LO(10)) -#define MUL (HI(28) | LO(2)) -#endif /* SLJIT_MIPS_REV >= 6 */ -#define PREF (HI(51)) -#define PREFX (HI(19) | LO(15)) -#define SEB (HI(31) | (16 << 6) | LO(32)) -#define SEH (HI(31) | (24 << 6) | LO(32)) -#endif /* SLJIT_MIPS_REV >= 1 */ - -#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) -#define ADDU_W ADDU -#define ADDIU_W ADDIU -#define SLL_W SLL -#define SRA_W SRA -#define SUBU_W SUBU -#define STORE_W SW -#define LOAD_W LW -#else -#define ADDU_W DADDU -#define ADDIU_W DADDIU -#define SLL_W DSLL -#define SRA_W DSRA -#define SUBU_W DSUBU -#define STORE_W SD -#define LOAD_W LD -#endif - -#define SIMM_MAX (0x7fff) -#define SIMM_MIN (-0x8000) -#define UIMM_MAX (0xffff) - -/* dest_reg is the absolute name of the register - Useful for reordering instructions in the delay slot. */ -static sljit_s32 push_inst(struct sljit_compiler *compiler, sljit_ins ins, sljit_s32 delay_slot) -{ - sljit_ins *ptr = (sljit_ins*)ensure_buf(compiler, sizeof(sljit_ins)); - SLJIT_ASSERT(delay_slot == MOVABLE_INS || delay_slot >= UNMOVABLE_INS - || (sljit_ins)delay_slot == ((ins >> 11) & 0x1f) - || (sljit_ins)delay_slot == ((ins >> 16) & 0x1f)); - FAIL_IF(!ptr); - *ptr = ins; - compiler->size++; - compiler->delay_slot = delay_slot; - return SLJIT_SUCCESS; -} - -static SLJIT_INLINE sljit_ins invert_branch(sljit_uw flags) -{ - if (flags & IS_BIT26_COND) - return (1 << 26); -#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6) - if (flags & IS_BIT23_COND) - return (1 << 23); -#endif /* SLJIT_MIPS_REV >= 6 */ - return (1 << 16); -} - -static SLJIT_INLINE sljit_ins* detect_jump_type(struct sljit_jump *jump, sljit_ins *code, sljit_sw executable_offset) -{ - sljit_sw diff; - sljit_uw target_addr; - sljit_ins *inst; - sljit_ins saved_inst; - - inst = (sljit_ins *)jump->addr; - -#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) - if (jump->flags & (SLJIT_REWRITABLE_JUMP | IS_CALL)) - goto exit; -#else - if (jump->flags & SLJIT_REWRITABLE_JUMP) - goto exit; -#endif - - if (jump->flags & JUMP_ADDR) - target_addr = jump->u.target; - else { - SLJIT_ASSERT(jump->flags & JUMP_LABEL); - target_addr = (sljit_uw)(code + jump->u.label->size) + (sljit_uw)executable_offset; - } - - if (jump->flags & IS_COND) - inst--; - -#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) - if (jump->flags & IS_CALL) - goto preserve_addr; -#endif - - /* B instructions. */ - if (jump->flags & IS_MOVABLE) { - diff = ((sljit_sw)target_addr - (sljit_sw)inst - executable_offset) >> 2; - if (diff <= SIMM_MAX && diff >= SIMM_MIN) { - jump->flags |= PATCH_B; - - if (!(jump->flags & IS_COND)) { - inst[0] = inst[-1]; - inst[-1] = (jump->flags & IS_JAL) ? BAL : B; - jump->addr -= sizeof(sljit_ins); - return inst; - } - saved_inst = inst[0]; - inst[0] = inst[-1]; - inst[-1] = saved_inst ^ invert_branch(jump->flags); - jump->addr -= 2 * sizeof(sljit_ins); - return inst; - } - } else { - diff = ((sljit_sw)target_addr - (sljit_sw)(inst + 1) - executable_offset) >> 2; - if (diff <= SIMM_MAX && diff >= SIMM_MIN) { - jump->flags |= PATCH_B; - - if (!(jump->flags & IS_COND)) { - inst[0] = (jump->flags & IS_JAL) ? BAL : B; - /* Keep inst[1] */ - return inst + 1; - } - inst[0] ^= invert_branch(jump->flags); - inst[1] = NOP; - jump->addr -= sizeof(sljit_ins); - return inst + 1; - } - } - - if (jump->flags & IS_COND) { - if ((jump->flags & IS_MOVABLE) && (target_addr & ~(sljit_uw)0xfffffff) == ((jump->addr + 2 * sizeof(sljit_ins)) & ~(sljit_uw)0xfffffff)) { - jump->flags |= PATCH_J; - saved_inst = inst[0]; - inst[0] = inst[-1]; - inst[-1] = (saved_inst & 0xffff0000) | 3; - inst[1] = J; - inst[2] = NOP; - return inst + 2; - } - else if ((target_addr & ~(sljit_uw)0xfffffff) == ((jump->addr + 3 * sizeof(sljit_ins)) & ~(sljit_uw)0xfffffff)) { - jump->flags |= PATCH_J; - inst[0] = (inst[0] & 0xffff0000) | 3; - inst[1] = NOP; - inst[2] = J; - inst[3] = NOP; - jump->addr += sizeof(sljit_ins); - return inst + 3; - } - } - else { - /* J instuctions. */ - if ((jump->flags & IS_MOVABLE) && (target_addr & ~(sljit_uw)0xfffffff) == (jump->addr & ~(sljit_uw)0xfffffff)) { - jump->flags |= PATCH_J; - inst[0] = inst[-1]; - inst[-1] = (jump->flags & IS_JAL) ? JAL : J; - jump->addr -= sizeof(sljit_ins); - return inst; - } - - if ((target_addr & ~(sljit_uw)0xfffffff) == ((jump->addr + sizeof(sljit_ins)) & ~(sljit_uw)0xfffffff)) { - jump->flags |= PATCH_J; - inst[0] = (jump->flags & IS_JAL) ? JAL : J; - /* Keep inst[1] */ - return inst + 1; - } - } - - if (jump->flags & IS_COND) - inst++; - -#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) -preserve_addr: - if (target_addr <= 0x7fffffff) { - jump->flags |= PATCH_ABS32; - if (jump->flags & IS_COND) - inst[-1] -= 4; - - inst[2] = inst[0]; - inst[3] = inst[1]; - return inst + 3; - } - if (target_addr <= 0x7fffffffffffl) { - jump->flags |= PATCH_ABS48; - if (jump->flags & IS_COND) - inst[-1] -= 2; - - inst[4] = inst[0]; - inst[5] = inst[1]; - return inst + 5; - } -#endif - -exit: -#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) - inst[2] = inst[0]; - inst[3] = inst[1]; - return inst + 3; -#else - inst[6] = inst[0]; - inst[7] = inst[1]; - return inst + 7; -#endif -} - -#ifdef __GNUC__ -static __attribute__ ((noinline)) void sljit_cache_flush(void* code, void* code_ptr) -{ - SLJIT_CACHE_FLUSH(code, code_ptr); -} -#endif - -#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) -{ - if (max_label < 0x80000000l) { - put_label->flags = PATCH_ABS32; - return 1; - } - - if (max_label < 0x800000000000l) { - put_label->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) -{ - 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; - } - -#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) - inst[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); - } - 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; - } - 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; - } -#endif /* SLJIT_CONFIG_MIPS_32 */ - - inst[1] = ORI | S(reg) | T(reg) | IMM(addr & 0xffff); -} - -SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler) -{ - struct sljit_memory_fragment *buf; - sljit_ins *code; - sljit_ins *code_ptr; - sljit_ins *buf_ptr; - sljit_ins *buf_end; - sljit_uw word_count; - sljit_uw next_addr; - 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); - 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; - - 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) { - 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); - label->size = (sljit_uw)(code_ptr - code); - label = label->next; - } - if (jump && jump->addr == word_count) { -#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); - jump = jump->next; - } - if (const_ && const_->addr == word_count) { - const_->addr = (sljit_uw)code_ptr; - const_ = const_->next; - } - 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); - } - code_ptr++; - word_count++; - } while (buf_ptr < buf_end); - - buf = buf->next; - } while (buf); - - if (label && label->size == word_count) { - label->addr = (sljit_uw)code_ptr; - label->size = (sljit_uw)(code_ptr - code); - label = label->next; - } - - 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; - buf_ptr = (sljit_ins *)jump->addr; - - if (jump->flags & PATCH_B) { - addr = (sljit_uw)((sljit_sw)(addr - (sljit_uw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset) - sizeof(sljit_ins)) >> 2); - SLJIT_ASSERT((sljit_sw)addr <= SIMM_MAX && (sljit_sw)addr >= SIMM_MIN); - buf_ptr[0] = (buf_ptr[0] & 0xffff0000) | ((sljit_ins)addr & 0xffff); - break; - } - if (jump->flags & PATCH_J) { - SLJIT_ASSERT((addr & ~(sljit_uw)0xfffffff) - == (((sljit_uw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset) + sizeof(sljit_ins)) & ~(sljit_uw)0xfffffff)); - buf_ptr[0] |= (sljit_ins)(addr >> 2) & 0x03ffffff; - break; - } - - load_addr_to_reg(jump, PIC_ADDR_REG); - } 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; - } - - compiler->error = SLJIT_ERR_COMPILED; - compiler->executable_offset = executable_offset; - compiler->executable_size = (sljit_uw)(code_ptr - code) * sizeof(sljit_ins); - - code = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(code, executable_offset); - code_ptr = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset); - -#ifndef __GNUC__ - SLJIT_CACHE_FLUSH(code, code_ptr); -#else - /* GCC workaround for invalid code generation with -O2. */ - sljit_cache_flush(code, code_ptr); -#endif - SLJIT_UPDATE_WX_FLAGS(code, code_ptr, 1); - return code; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type) -{ -#if defined(__GNUC__) && !defined(SLJIT_IS_FPU_AVAILABLE) - sljit_sw fir = 0; -#endif /* __GNUC__ && !SLJIT_IS_FPU_AVAILABLE */ - - switch (feature_type) { - case SLJIT_HAS_FPU: -#ifdef SLJIT_IS_FPU_AVAILABLE - return SLJIT_IS_FPU_AVAILABLE; -#elif defined(__GNUC__) - __asm__ ("cfc1 %0, $0" : "=r"(fir)); - return (fir >> 22) & 0x1; -#else -#error "FIR check is not implemented for this architecture" -#endif - case SLJIT_HAS_ZERO_REGISTER: - return 1; -#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1) - case SLJIT_HAS_CLZ: - case SLJIT_HAS_CMOV: - case SLJIT_HAS_PREFETCH: - return 1; - - case SLJIT_HAS_CTZ: - return 2; -#endif /* SLJIT_MIPS_REV >= 1 */ -#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 2) - case SLJIT_HAS_ROT: - return 1; -#endif /* SLJIT_MIPS_REV >= 2 */ - default: - return 0; - } -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_cmp_info(sljit_s32 type) -{ - return (type >= SLJIT_ORDERED_EQUAL && type <= SLJIT_ORDERED_LESS_EQUAL); -} - -/* --------------------------------------------------------------------- */ -/* Entry, exit */ -/* --------------------------------------------------------------------- */ - -/* Creates an index in data_transfer_insts array. */ -#define LOAD_DATA 0x01 -#define WORD_DATA 0x00 -#define BYTE_DATA 0x02 -#define HALF_DATA 0x04 -#define INT_DATA 0x06 -#define SIGNED_DATA 0x08 -/* Separates integer and floating point registers */ -#define GPR_REG 0x0f -#define DOUBLE_DATA 0x10 -#define SINGLE_DATA 0x12 - -#define MEM_MASK 0x1f - -#define ARG_TEST 0x00020 -#define ALT_KEEP_CACHE 0x00040 -#define CUMULATIVE_OP 0x00080 -#define LOGICAL_OP 0x00100 -#define IMM_OP 0x00200 -#define MOVE_OP 0x00400 -#define SRC2_IMM 0x00800 - -#define UNUSED_DEST 0x01000 -#define REG_DEST 0x02000 -#define REG1_SOURCE 0x04000 -#define REG2_SOURCE 0x08000 -#define SLOW_SRC1 0x10000 -#define SLOW_SRC2 0x20000 -#define SLOW_DEST 0x40000 - -static sljit_s32 emit_op_mem(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg_ar, sljit_s32 arg, sljit_sw argw); -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) -#include "sljitNativeMIPS_32.c" -#else -#include "sljitNativeMIPS_64.c" -#endif - -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, - sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size) -{ - sljit_ins base; - sljit_s32 i, tmp, offset; - sljit_s32 arg_count, word_arg_count, float_arg_count; - sljit_s32 saved_arg_count = SLJIT_KEPT_SAVEDS_COUNT(options); - - CHECK_ERROR(); - CHECK(check_sljit_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size)); - set_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size); - - local_size += GET_SAVED_REGISTERS_SIZE(scratches, saveds - saved_arg_count, 1); -#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) - if (fsaveds > 0 || fscratches >= SLJIT_FIRST_SAVED_FLOAT_REG) { - if ((local_size & SSIZE_OF(sw)) != 0) - local_size += SSIZE_OF(sw); - local_size += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, sizeof(sljit_f64)); - } - - local_size = (local_size + SLJIT_LOCALS_OFFSET + 15) & ~0xf; -#else - local_size += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, sizeof(sljit_f64)); - local_size = (local_size + SLJIT_LOCALS_OFFSET + 31) & ~0x1f; -#endif - compiler->local_size = local_size; - - offset = 0; -#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) - if (!(options & SLJIT_ENTER_REG_ARG)) { - tmp = arg_types >> SLJIT_ARG_SHIFT; - arg_count = 0; - - while (tmp) { - offset = arg_count; - if ((tmp & SLJIT_ARG_MASK) == SLJIT_ARG_TYPE_F64) { - if ((arg_count & 0x1) != 0) - arg_count++; - arg_count++; - } - - arg_count++; - tmp >>= SLJIT_ARG_SHIFT; - } - - compiler->args_size = (sljit_uw)arg_count << 2; - offset = (offset >= 4) ? (offset << 2) : 0; - } -#endif /* SLJIT_CONFIG_MIPS_32 */ - - if (local_size + offset <= -SIMM_MIN) { - /* Frequent case. */ - FAIL_IF(push_inst(compiler, ADDIU_W | S(SLJIT_SP) | T(SLJIT_SP) | IMM(-local_size), DR(SLJIT_SP))); - base = S(SLJIT_SP); - 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, SUBU_W | S(SLJIT_SP) | TA(OTHER_FLAG) | D(SLJIT_SP), DR(SLJIT_SP))); - base = S(TMP_REG2); - offset = -SSIZE_OF(sw); -#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) - local_size = 0; -#endif - } - - FAIL_IF(push_inst(compiler, STORE_W | base | TA(RETURN_ADDR_REG) | IMM(offset), UNMOVABLE_INS)); - - tmp = SLJIT_S0 - saveds; - for (i = SLJIT_S0 - saved_arg_count; i > tmp; i--) { - offset -= SSIZE_OF(sw); - FAIL_IF(push_inst(compiler, STORE_W | base | T(i) | IMM(offset), MOVABLE_INS)); - } - - for (i = scratches; i >= SLJIT_FIRST_SAVED_REG; i--) { - offset -= SSIZE_OF(sw); - FAIL_IF(push_inst(compiler, STORE_W | base | T(i) | IMM(offset), MOVABLE_INS)); - } - -#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) - /* This alignment is valid because offset is not used after storing FPU regs. */ - if ((offset & SSIZE_OF(sw)) != 0) - offset -= SSIZE_OF(sw); -#endif - - tmp = SLJIT_FS0 - fsaveds; - for (i = SLJIT_FS0; i > tmp; i--) { - offset -= SSIZE_OF(f64); - FAIL_IF(push_inst(compiler, SDC1 | base | FT(i) | IMM(offset), MOVABLE_INS)); - } - - for (i = fscratches; i >= SLJIT_FIRST_SAVED_FLOAT_REG; i--) { - offset -= SSIZE_OF(f64); - FAIL_IF(push_inst(compiler, SDC1 | base | FT(i) | IMM(offset), MOVABLE_INS)); - } - - if (options & SLJIT_ENTER_REG_ARG) - return SLJIT_SUCCESS; - - arg_types >>= SLJIT_ARG_SHIFT; - arg_count = 0; - word_arg_count = 0; - float_arg_count = 0; - -#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) - /* The first maximum two floating point arguments are passed in floating point - registers if no integer argument precedes them. The first 16 byte data is - passed in four integer registers, the rest is placed onto the stack. - The floating point registers are also part of the first 16 byte data, so - their corresponding integer registers are not used when they are present. */ - - while (arg_types) { - switch (arg_types & SLJIT_ARG_MASK) { - case SLJIT_ARG_TYPE_F64: - float_arg_count++; - if ((arg_count & 0x1) != 0) - arg_count++; - - if (word_arg_count == 0 && float_arg_count <= 2) { - if (float_arg_count == 1) - FAIL_IF(push_inst(compiler, MOV_S | FMT_D | FS(TMP_FREG1) | FD(SLJIT_FR0), MOVABLE_INS)); - } else if (arg_count < 4) { - FAIL_IF(push_inst(compiler, MTC1 | TA(4 + arg_count) | FS(float_arg_count), MOVABLE_INS)); - FAIL_IF(push_inst(compiler, MTC1 | TA(5 + arg_count) | FS(float_arg_count) | (1 << 11), MOVABLE_INS)); - } else - FAIL_IF(push_inst(compiler, LDC1 | base | FT(float_arg_count) | IMM(local_size + (arg_count << 2)), MOVABLE_INS)); - arg_count++; - break; - case SLJIT_ARG_TYPE_F32: - float_arg_count++; - - if (word_arg_count == 0 && float_arg_count <= 2) { - if (float_arg_count == 1) - FAIL_IF(push_inst(compiler, MOV_S | FMT_S | FS(TMP_FREG1) | FD(SLJIT_FR0), MOVABLE_INS)); - } else if (arg_count < 4) - FAIL_IF(push_inst(compiler, MTC1 | TA(4 + arg_count) | FS(float_arg_count), MOVABLE_INS)); - else - FAIL_IF(push_inst(compiler, LWC1 | base | FT(float_arg_count) | IMM(local_size + (arg_count << 2)), MOVABLE_INS)); - break; - default: - word_arg_count++; - - if (!(arg_types & SLJIT_ARG_TYPE_SCRATCH_REG)) { - tmp = SLJIT_S0 - saved_arg_count; - saved_arg_count++; - } else if (word_arg_count != arg_count + 1 || arg_count == 0) - tmp = word_arg_count; - else - break; - - if (arg_count < 4) - FAIL_IF(push_inst(compiler, ADDU_W | SA(4 + arg_count) | TA(0) | D(tmp), DR(tmp))); - else - FAIL_IF(push_inst(compiler, LW | base | T(tmp) | IMM(local_size + (arg_count << 2)), DR(tmp))); - break; - } - arg_count++; - arg_types >>= SLJIT_ARG_SHIFT; - } - - SLJIT_ASSERT(compiler->args_size == (sljit_uw)arg_count << 2); -#else /* !SLJIT_CONFIG_MIPS_32 */ - while (arg_types) { - arg_count++; - switch (arg_types & SLJIT_ARG_MASK) { - case SLJIT_ARG_TYPE_F64: - float_arg_count++; - if (arg_count != float_arg_count) - FAIL_IF(push_inst(compiler, MOV_S | FMT_D | FS(arg_count) | FD(float_arg_count), MOVABLE_INS)); - else if (arg_count == 1) - FAIL_IF(push_inst(compiler, MOV_S | FMT_D | FS(TMP_FREG1) | FD(SLJIT_FR0), MOVABLE_INS)); - break; - case SLJIT_ARG_TYPE_F32: - float_arg_count++; - if (arg_count != float_arg_count) - FAIL_IF(push_inst(compiler, MOV_S | FMT_S | FS(arg_count) | FD(float_arg_count), MOVABLE_INS)); - else if (arg_count == 1) - FAIL_IF(push_inst(compiler, MOV_S | FMT_S | FS(TMP_FREG1) | FD(SLJIT_FR0), MOVABLE_INS)); - break; - default: - word_arg_count++; - - if (!(arg_types & SLJIT_ARG_TYPE_SCRATCH_REG)) { - tmp = SLJIT_S0 - saved_arg_count; - saved_arg_count++; - } else if (word_arg_count != arg_count || word_arg_count <= 1) - tmp = word_arg_count; - else - break; - - FAIL_IF(push_inst(compiler, ADDU_W | SA(3 + arg_count) | TA(0) | D(tmp), DR(tmp))); - break; - } - arg_types >>= SLJIT_ARG_SHIFT; - } -#endif /* SLJIT_CONFIG_MIPS_32 */ - - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(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) -{ - CHECK_ERROR(); - CHECK(check_sljit_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size)); - set_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size); - - local_size += GET_SAVED_REGISTERS_SIZE(scratches, saveds - SLJIT_KEPT_SAVEDS_COUNT(options), 1); -#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) - if (fsaveds > 0 || fscratches >= SLJIT_FIRST_SAVED_FLOAT_REG) { - if ((local_size & SSIZE_OF(sw)) != 0) - local_size += SSIZE_OF(sw); - local_size += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, sizeof(sljit_f64)); - } - - compiler->local_size = (local_size + SLJIT_LOCALS_OFFSET + 15) & ~0xf; -#else - local_size += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, sizeof(sljit_f64)); - compiler->local_size = (local_size + SLJIT_LOCALS_OFFSET + 31) & ~0x1f; -#endif - return SLJIT_SUCCESS; -} - -static sljit_s32 emit_stack_frame_release(struct sljit_compiler *compiler, sljit_s32 frame_size, sljit_ins *ins_ptr) -{ - sljit_s32 local_size, i, tmp, offset; - sljit_s32 load_return_addr = (frame_size == 0); - sljit_s32 scratches = compiler->scratches; - sljit_s32 saveds = compiler->saveds; - sljit_s32 fsaveds = compiler->fsaveds; - sljit_s32 fscratches = compiler->fscratches; - sljit_s32 kept_saveds_count = SLJIT_KEPT_SAVEDS_COUNT(compiler->options); - - SLJIT_ASSERT(frame_size == 1 || (frame_size & 0xf) == 0); - frame_size &= ~0xf; - - local_size = compiler->local_size; - - tmp = GET_SAVED_REGISTERS_SIZE(scratches, saveds - kept_saveds_count, 1); -#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) - if (fsaveds > 0 || fscratches >= SLJIT_FIRST_SAVED_FLOAT_REG) { - if ((tmp & SSIZE_OF(sw)) != 0) - tmp += SSIZE_OF(sw); - tmp += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, sizeof(sljit_f64)); - } -#else - tmp += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, sizeof(sljit_f64)); -#endif - - if (local_size <= SIMM_MAX) { - if (local_size < frame_size) { - FAIL_IF(push_inst(compiler, ADDIU_W | S(SLJIT_SP) | T(SLJIT_SP) | IMM(local_size - frame_size), DR(SLJIT_SP))); - local_size = frame_size; - } - } else { - 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))); - local_size = tmp; - } - - SLJIT_ASSERT(local_size >= frame_size); - - offset = local_size - SSIZE_OF(sw); - if (load_return_addr) - FAIL_IF(push_inst(compiler, LOAD_W | S(SLJIT_SP) | TA(RETURN_ADDR_REG) | IMM(offset), RETURN_ADDR_REG)); - - tmp = SLJIT_S0 - saveds; - for (i = SLJIT_S0 - kept_saveds_count; i > tmp; i--) { - offset -= SSIZE_OF(sw); - FAIL_IF(push_inst(compiler, LOAD_W | S(SLJIT_SP) | T(i) | IMM(offset), MOVABLE_INS)); - } - - for (i = scratches; i >= SLJIT_FIRST_SAVED_REG; i--) { - offset -= SSIZE_OF(sw); - FAIL_IF(push_inst(compiler, LOAD_W | S(SLJIT_SP) | T(i) | IMM(offset), MOVABLE_INS)); - } - -#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) - /* This alignment is valid because offset is not used after storing FPU regs. */ - if ((offset & SSIZE_OF(sw)) != 0) - offset -= SSIZE_OF(sw); -#endif - - tmp = SLJIT_FS0 - fsaveds; - for (i = SLJIT_FS0; i > tmp; i--) { - offset -= SSIZE_OF(f64); - FAIL_IF(push_inst(compiler, LDC1 | S(SLJIT_SP) | FT(i) | IMM(offset), MOVABLE_INS)); - } - - for (i = fscratches; i >= SLJIT_FIRST_SAVED_FLOAT_REG; i--) { - offset -= SSIZE_OF(f64); - FAIL_IF(push_inst(compiler, LDC1 | S(SLJIT_SP) | FT(i) | IMM(offset), MOVABLE_INS)); - } - - if (local_size > frame_size) - *ins_ptr = ADDIU_W | S(SLJIT_SP) | T(SLJIT_SP) | IMM(local_size - frame_size); - else - *ins_ptr = NOP; - - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_void(struct sljit_compiler *compiler) -{ - sljit_ins ins; - - CHECK_ERROR(); - CHECK(check_sljit_emit_return_void(compiler)); - - emit_stack_frame_release(compiler, 0, &ins); - - FAIL_IF(push_inst(compiler, JR | SA(RETURN_ADDR_REG), UNMOVABLE_INS)); - return push_inst(compiler, ins, UNMOVABLE_INS); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_to(struct sljit_compiler *compiler, - sljit_s32 src, sljit_sw srcw) -{ - sljit_ins ins; - - CHECK_ERROR(); - CHECK(check_sljit_emit_return_to(compiler, src, srcw)); - - if (src & SLJIT_MEM) { - ADJUST_LOCAL_OFFSET(src, srcw); - FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, DR(PIC_ADDR_REG), src, srcw)); - src = PIC_ADDR_REG; - srcw = 0; - } else if (src >= SLJIT_FIRST_SAVED_REG && src <= (SLJIT_S0 - SLJIT_KEPT_SAVEDS_COUNT(compiler->options))) { - FAIL_IF(push_inst(compiler, ADDU_W | S(src) | TA(0) | D(PIC_ADDR_REG), DR(PIC_ADDR_REG))); - src = PIC_ADDR_REG; - srcw = 0; - } - - FAIL_IF(emit_stack_frame_release(compiler, 1, &ins)); - - if (!(src & SLJIT_IMM)) { - FAIL_IF(push_inst(compiler, JR | S(src), UNMOVABLE_INS)); - return push_inst(compiler, ins, UNMOVABLE_INS); - } - - if (ins != NOP) - FAIL_IF(push_inst(compiler, ins, MOVABLE_INS)); - - SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_ijump(compiler, SLJIT_JUMP, src, srcw); -} - -/* --------------------------------------------------------------------- */ -/* Operators */ -/* --------------------------------------------------------------------- */ - -#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) -#define ARCH_32_64(a, b) a -#else -#define ARCH_32_64(a, b) b -#endif - -static const sljit_ins data_transfer_insts[16 + 4] = { -/* u w s */ ARCH_32_64(HI(43) /* sw */, HI(63) /* sd */), -/* u w l */ ARCH_32_64(HI(35) /* lw */, HI(55) /* ld */), -/* u b s */ HI(40) /* sb */, -/* u b l */ HI(36) /* lbu */, -/* u h s */ HI(41) /* sh */, -/* u h l */ HI(37) /* lhu */, -/* u i s */ HI(43) /* sw */, -/* u i l */ ARCH_32_64(HI(35) /* lw */, HI(39) /* lwu */), - -/* s w s */ ARCH_32_64(HI(43) /* sw */, HI(63) /* sd */), -/* s w l */ ARCH_32_64(HI(35) /* lw */, HI(55) /* ld */), -/* s b s */ HI(40) /* sb */, -/* s b l */ HI(32) /* lb */, -/* s h s */ HI(41) /* sh */, -/* s h l */ HI(33) /* lh */, -/* s i s */ HI(43) /* sw */, -/* s i l */ HI(35) /* lw */, - -/* d s */ HI(61) /* sdc1 */, -/* d l */ HI(53) /* ldc1 */, -/* s s */ HI(57) /* swc1 */, -/* s l */ HI(49) /* lwc1 */, -}; - -#undef ARCH_32_64 - -/* reg_ar is an absoulute register! */ - -/* Can perform an operation using at most 1 instruction. */ -static sljit_s32 getput_arg_fast(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg_ar, sljit_s32 arg, sljit_sw argw) -{ - SLJIT_ASSERT(arg & SLJIT_MEM); - - if (!(arg & OFFS_REG_MASK) && argw <= SIMM_MAX && argw >= SIMM_MIN) { - /* Works for both absoulte and relative addresses. */ - if (SLJIT_UNLIKELY(flags & ARG_TEST)) - return 1; - FAIL_IF(push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | S(arg & REG_MASK) - | TA(reg_ar) | IMM(argw), ((flags & MEM_MASK) <= GPR_REG && (flags & LOAD_DATA)) ? reg_ar : MOVABLE_INS)); - return -1; - } - return 0; -} - -#define TO_ARGW_HI(argw) (((argw) & ~0xffff) + (((argw) & 0x8000) ? 0x10000 : 0)) - -/* See getput_arg below. - Note: can_cache is called only for binary operators. */ -static sljit_s32 can_cache(sljit_s32 arg, sljit_sw argw, sljit_s32 next_arg, sljit_sw next_argw) -{ - SLJIT_ASSERT((arg & SLJIT_MEM) && (next_arg & SLJIT_MEM)); - - /* Simple operation except for updates. */ - if (arg & OFFS_REG_MASK) { - argw &= 0x3; - next_argw &= 0x3; - if (argw && argw == next_argw && (arg == next_arg || (arg & OFFS_REG_MASK) == (next_arg & OFFS_REG_MASK))) - return 1; - return 0; - } - - if (arg == next_arg) { - if (((next_argw - argw) <= SIMM_MAX && (next_argw - argw) >= SIMM_MIN) - || TO_ARGW_HI(argw) == TO_ARGW_HI(next_argw)) - return 1; - return 0; - } - - return 0; -} - -/* Emit the necessary instructions. See can_cache above. */ -static sljit_s32 getput_arg(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg_ar, sljit_s32 arg, sljit_sw argw, sljit_s32 next_arg, sljit_sw next_argw) -{ - sljit_s32 tmp_ar, base, delay_slot; - sljit_sw offset, argw_hi; - - SLJIT_ASSERT(arg & SLJIT_MEM); - if (!(next_arg & SLJIT_MEM)) { - next_arg = 0; - 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_ar = reg_ar; - delay_slot = reg_ar; - } - else { - tmp_ar = DR(TMP_REG1); - delay_slot = MOVABLE_INS; - } - base = arg & REG_MASK; - - if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) { - argw &= 0x3; - - /* Using the cache. */ - if (argw == compiler->cache_argw) { - if (arg == compiler->cache_arg) - return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | S(TMP_REG3) | TA(reg_ar), delay_slot); - - if ((SLJIT_MEM | (arg & OFFS_REG_MASK)) == compiler->cache_arg) { - if (arg == next_arg && argw == (next_argw & 0x3)) { - compiler->cache_arg = arg; - compiler->cache_argw = argw; - FAIL_IF(push_inst(compiler, ADDU_W | S(base) | T(TMP_REG3) | D(TMP_REG3), DR(TMP_REG3))); - return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | S(TMP_REG3) | TA(reg_ar), delay_slot); - } - FAIL_IF(push_inst(compiler, ADDU_W | S(base) | T(TMP_REG3) | DA(tmp_ar), tmp_ar)); - return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | SA(tmp_ar) | TA(reg_ar), delay_slot); - } - } - - if (SLJIT_UNLIKELY(argw)) { - compiler->cache_arg = SLJIT_MEM | (arg & OFFS_REG_MASK); - compiler->cache_argw = argw; - FAIL_IF(push_inst(compiler, SLL_W | T(OFFS_REG(arg)) | D(TMP_REG3) | SH_IMM(argw), DR(TMP_REG3))); - } - - if (arg == next_arg && argw == (next_argw & 0x3)) { - compiler->cache_arg = arg; - compiler->cache_argw = argw; - FAIL_IF(push_inst(compiler, ADDU_W | S(base) | T(!argw ? OFFS_REG(arg) : TMP_REG3) | D(TMP_REG3), DR(TMP_REG3))); - tmp_ar = DR(TMP_REG3); - } - else - FAIL_IF(push_inst(compiler, ADDU_W | S(base) | T(!argw ? OFFS_REG(arg) : TMP_REG3) | DA(tmp_ar), tmp_ar)); - return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | SA(tmp_ar) | TA(reg_ar), delay_slot); - } - - if (compiler->cache_arg == arg && argw - compiler->cache_argw <= SIMM_MAX && argw - compiler->cache_argw >= SIMM_MIN) - return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | S(TMP_REG3) | TA(reg_ar) | IMM(argw - compiler->cache_argw), delay_slot); - - if (compiler->cache_arg == SLJIT_MEM && (argw - compiler->cache_argw) <= SIMM_MAX && (argw - compiler->cache_argw) >= SIMM_MIN) { - offset = argw - compiler->cache_argw; - } else { - compiler->cache_arg = SLJIT_MEM; - - argw_hi = TO_ARGW_HI(argw); - - if (next_arg && next_argw - argw <= SIMM_MAX && next_argw - argw >= SIMM_MIN && argw_hi != TO_ARGW_HI(next_argw)) { - FAIL_IF(load_immediate(compiler, DR(TMP_REG3), argw)); - compiler->cache_argw = argw; - offset = 0; - } else { - FAIL_IF(load_immediate(compiler, DR(TMP_REG3), argw_hi)); - compiler->cache_argw = argw_hi; - offset = argw & 0xffff; - argw = argw_hi; - } - } - - if (!base) - return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | S(TMP_REG3) | TA(reg_ar) | IMM(offset), delay_slot); - - if (arg == next_arg && next_argw - argw <= SIMM_MAX && next_argw - argw >= SIMM_MIN) { - compiler->cache_arg = arg; - FAIL_IF(push_inst(compiler, ADDU_W | S(TMP_REG3) | T(base) | D(TMP_REG3), DR(TMP_REG3))); - return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | S(TMP_REG3) | TA(reg_ar) | IMM(offset), delay_slot); - } - - FAIL_IF(push_inst(compiler, ADDU_W | S(TMP_REG3) | T(base) | DA(tmp_ar), tmp_ar)); - return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | SA(tmp_ar) | TA(reg_ar) | IMM(offset), delay_slot); -} - -static sljit_s32 emit_op_mem(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg_ar, sljit_s32 arg, sljit_sw argw) -{ - sljit_s32 tmp_ar, base, delay_slot; - - if (getput_arg_fast(compiler, flags, reg_ar, arg, argw)) - return compiler->error; - - if ((flags & MEM_MASK) <= GPR_REG && (flags & LOAD_DATA)) { - tmp_ar = reg_ar; - delay_slot = reg_ar; - } - else { - tmp_ar = DR(TMP_REG1); - delay_slot = MOVABLE_INS; - } - base = arg & REG_MASK; - - if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) { - argw &= 0x3; - - if (SLJIT_UNLIKELY(argw)) { - FAIL_IF(push_inst(compiler, SLL_W | T(OFFS_REG(arg)) | DA(tmp_ar) | SH_IMM(argw), tmp_ar)); - FAIL_IF(push_inst(compiler, ADDU_W | SA(tmp_ar) | T(base) | DA(tmp_ar), tmp_ar)); - } - else - FAIL_IF(push_inst(compiler, ADDU_W | S(base) | T(OFFS_REG(arg)) | DA(tmp_ar), tmp_ar)); - return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | SA(tmp_ar) | TA(reg_ar), delay_slot); - } - - FAIL_IF(load_immediate(compiler, tmp_ar, TO_ARGW_HI(argw))); - - if (base != 0) - FAIL_IF(push_inst(compiler, ADDU_W | SA(tmp_ar) | T(base) | DA(tmp_ar), tmp_ar)); - - return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | SA(tmp_ar) | TA(reg_ar) | IMM(argw), delay_slot); -} - -static SLJIT_INLINE sljit_s32 emit_op_mem2(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg1, sljit_sw arg1w, sljit_s32 arg2, sljit_sw arg2w) -{ - if (getput_arg_fast(compiler, flags, reg, arg1, arg1w)) - return compiler->error; - return getput_arg(compiler, flags, reg, arg1, arg1w, arg2, arg2w); -} - -#define EMIT_LOGICAL(op_imm, op_reg) \ - if (flags & SRC2_IMM) { \ - if (op & SLJIT_SET_Z) \ - FAIL_IF(push_inst(compiler, op_imm | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG)); \ - if (!(flags & UNUSED_DEST)) \ - FAIL_IF(push_inst(compiler, op_imm | S(src1) | T(dst) | IMM(src2), DR(dst))); \ - } \ - else { \ - if (op & SLJIT_SET_Z) \ - FAIL_IF(push_inst(compiler, op_reg | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG)); \ - if (!(flags & UNUSED_DEST)) \ - FAIL_IF(push_inst(compiler, op_reg | S(src1) | T(src2) | D(dst), DR(dst))); \ - } - -#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) - -#define SELECT_OP(a, b) (b) - -#define EMIT_SHIFT(dimm, dimm32, imm, dv, v) \ - op_imm = (imm); \ - op_v = (v); - -#else /* !SLJIT_CONFIG_MIPS_32 */ - -#define SELECT_OP(a, b) \ - (!(op & SLJIT_32) ? a : b) - -#define EMIT_SHIFT(dimm, dimm32, imm, dv, v) \ - op_dimm = (dimm); \ - op_dimm32 = (dimm32); \ - op_imm = (imm); \ - op_dv = (dv); \ - op_v = (v); - -#endif /* SLJIT_CONFIG_MIPS_32 */ - -#if (!defined SLJIT_MIPS_REV || SLJIT_MIPS_REV < 1) - -static sljit_s32 emit_clz_ctz(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 dst, sljit_sw src) -{ - sljit_s32 is_clz = (GET_OPCODE(op) == SLJIT_CLZ); -#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) - sljit_ins max = (op & SLJIT_32) ? 32 : 64; -#else /* !SLJIT_CONFIG_RISCV_64 */ - sljit_ins max = 32; -#endif /* SLJIT_CONFIG_RISCV_64 */ - - /* The TMP_REG2 is the next value. */ - if (src != TMP_REG2) - FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(src) | TA(0) | D(TMP_REG2), DR(TMP_REG2))); - - FAIL_IF(push_inst(compiler, BEQ | S(TMP_REG2) | TA(0) | IMM(is_clz ? 13 : 14), UNMOVABLE_INS)); - /* The OTHER_FLAG is the counter. Delay slot. */ - FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | SA(0) | TA(OTHER_FLAG) | IMM(max), OTHER_FLAG)); - - if (!is_clz) { - FAIL_IF(push_inst(compiler, ANDI | S(TMP_REG2) | T(TMP_REG1) | IMM(1), DR(TMP_REG1))); - FAIL_IF(push_inst(compiler, BNE | S(TMP_REG1) | TA(0) | IMM(11), UNMOVABLE_INS)); - } else - FAIL_IF(push_inst(compiler, BLTZ | S(TMP_REG2) | TA(0) | IMM(11), UNMOVABLE_INS)); - - /* Delay slot. */ - FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | SA(0) | TA(OTHER_FLAG) | IMM(0), OTHER_FLAG)); - - /* The TMP_REG1 is the next shift. */ - FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | SA(0) | T(TMP_REG1) | IMM(max), DR(TMP_REG1))); - - FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(TMP_REG2) | TA(0) | DA(EQUAL_FLAG), EQUAL_FLAG)); - FAIL_IF(push_inst(compiler, SELECT_OP(DSRL, SRL) | T(TMP_REG1) | D(TMP_REG1) | SH_IMM(1), DR(TMP_REG1))); - - FAIL_IF(push_inst(compiler, (is_clz ? SELECT_OP(DSRLV, SRLV) : SELECT_OP(DSLLV, SLLV)) | S(TMP_REG1) | TA(EQUAL_FLAG) | D(TMP_REG2), DR(TMP_REG2))); - FAIL_IF(push_inst(compiler, BNE | S(TMP_REG2) | TA(0) | IMM(-4), UNMOVABLE_INS)); - /* Delay slot. */ - FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS)); - - FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(TMP_REG1) | T(TMP_REG2) | IMM(-1), DR(TMP_REG2))); - FAIL_IF(push_inst(compiler, (is_clz ? SELECT_OP(DSRLV, SRLV) : SELECT_OP(DSLLV, SLLV)) | S(TMP_REG2) | TA(EQUAL_FLAG) | D(TMP_REG2), DR(TMP_REG2))); - - FAIL_IF(push_inst(compiler, BEQ | S(TMP_REG2) | TA(0) | IMM(-7), UNMOVABLE_INS)); - /* Delay slot. */ - FAIL_IF(push_inst(compiler, OR | SA(OTHER_FLAG) | T(TMP_REG1) | DA(OTHER_FLAG), OTHER_FLAG)); - - return push_inst(compiler, SELECT_OP(DADDU, ADDU) | SA(OTHER_FLAG) | TA(0) | D(dst), DR(dst)); -} - -#endif /* SLJIT_MIPS_REV < 1 */ - -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_ins op_imm, op_v; -#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) - sljit_ins ins, op_dimm, op_dimm32, op_dv; -#endif - - switch (GET_OPCODE(op)) { - case SLJIT_MOV: - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM)); - if (dst != src2) - return push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(src2) | TA(0) | D(dst), DR(dst)); - return SLJIT_SUCCESS; - - case SLJIT_MOV_U8: - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM)); - if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) - return push_inst(compiler, ANDI | S(src2) | T(dst) | IMM(0xff), DR(dst)); - SLJIT_ASSERT(dst == src2); - return SLJIT_SUCCESS; - - case SLJIT_MOV_S8: - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM)); - if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) { -#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) -#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1) - return push_inst(compiler, SEB | T(src2) | D(dst), DR(dst)); -#else /* SLJIT_MIPS_REV < 1 */ - FAIL_IF(push_inst(compiler, SLL | T(src2) | D(dst) | SH_IMM(24), DR(dst))); - return push_inst(compiler, SRA | T(dst) | D(dst) | SH_IMM(24), DR(dst)); -#endif /* SLJIT_MIPS_REV >= 1 */ -#else /* !SLJIT_CONFIG_MIPS_32 */ -#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1) - if (op & SLJIT_32) - return push_inst(compiler, SEB | T(src2) | D(dst), DR(dst)); -#endif /* SLJIT_MIPS_REV >= 1 */ - FAIL_IF(push_inst(compiler, DSLL32 | T(src2) | D(dst) | SH_IMM(24), DR(dst))); - return push_inst(compiler, DSRA32 | T(dst) | D(dst) | SH_IMM(24), DR(dst)); -#endif /* SLJIT_CONFIG_MIPS_32 */ - } - SLJIT_ASSERT(dst == src2); - return SLJIT_SUCCESS; - - case SLJIT_MOV_U16: - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM)); - if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) - return push_inst(compiler, ANDI | S(src2) | T(dst) | IMM(0xffff), DR(dst)); - SLJIT_ASSERT(dst == src2); - return SLJIT_SUCCESS; - - case SLJIT_MOV_S16: - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM)); - if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) { -#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) -#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1) - return push_inst(compiler, SEH | T(src2) | D(dst), DR(dst)); -#else /* SLJIT_MIPS_REV < 1 */ - FAIL_IF(push_inst(compiler, SLL | T(src2) | D(dst) | SH_IMM(16), DR(dst))); - return push_inst(compiler, SRA | T(dst) | D(dst) | SH_IMM(16), DR(dst)); -#endif /* SLJIT_MIPS_REV >= 1 */ -#else /* !SLJIT_CONFIG_MIPS_32 */ -#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1) - if (op & SLJIT_32) - return push_inst(compiler, SEH | T(src2) | D(dst), DR(dst)); -#endif /* SLJIT_MIPS_REV >= 1 */ - FAIL_IF(push_inst(compiler, DSLL32 | T(src2) | D(dst) | SH_IMM(16), DR(dst))); - return push_inst(compiler, DSRA32 | T(dst) | D(dst) | SH_IMM(16), DR(dst)); -#endif /* SLJIT_CONFIG_MIPS_32 */ - } - SLJIT_ASSERT(dst == src2); - return SLJIT_SUCCESS; - -#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) - case SLJIT_MOV_U32: - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM) && !(op & SLJIT_32)); - if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) { -#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 2) - if (dst == src2) - return push_inst(compiler, DINSU | T(src2) | SA(0) | (31 << 11) | (0 << 11), DR(dst)); -#endif /* SLJIT_MIPS_REV >= 2 */ - FAIL_IF(push_inst(compiler, DSLL32 | T(src2) | D(dst) | SH_IMM(0), DR(dst))); - return push_inst(compiler, DSRL32 | T(dst) | D(dst) | SH_IMM(0), DR(dst)); - } - SLJIT_ASSERT(dst == src2); - return SLJIT_SUCCESS; - - case SLJIT_MOV_S32: - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM) && !(op & SLJIT_32)); - if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) { - return push_inst(compiler, SLL | T(src2) | D(dst) | SH_IMM(0), DR(dst)); - } - SLJIT_ASSERT(dst == src2); - return SLJIT_SUCCESS; -#endif /* SLJIT_CONFIG_MIPS_64 */ - - case SLJIT_NOT: - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM)); - if (op & SLJIT_SET_Z) - FAIL_IF(push_inst(compiler, NOR | S(src2) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG)); - if (!(flags & UNUSED_DEST)) - FAIL_IF(push_inst(compiler, NOR | S(src2) | T(src2) | D(dst), DR(dst))); - return SLJIT_SUCCESS; - -#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1) - case SLJIT_CLZ: - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM)); -#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6) - return push_inst(compiler, SELECT_OP(DCLZ, CLZ) | S(src2) | D(dst), DR(dst)); -#else /* SLJIT_MIPS_REV < 6 */ - return push_inst(compiler, SELECT_OP(DCLZ, CLZ) | S(src2) | T(dst) | D(dst), DR(dst)); -#endif /* SLJIT_MIPS_REV >= 6 */ - case SLJIT_CTZ: - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM)); - FAIL_IF(push_inst(compiler, SELECT_OP(DSUBU, SUBU) | SA(0) | T(src2) | D(TMP_REG1), DR(TMP_REG1))); - FAIL_IF(push_inst(compiler, AND | S(src2) | T(TMP_REG1) | D(dst), DR(dst))); -#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6) - FAIL_IF(push_inst(compiler, SELECT_OP(DCLZ, CLZ) | S(dst) | D(dst), DR(dst))); -#else /* SLJIT_MIPS_REV < 6 */ - FAIL_IF(push_inst(compiler, SELECT_OP(DCLZ, CLZ) | S(dst) | T(dst) | D(dst), DR(dst))); -#endif /* SLJIT_MIPS_REV >= 6 */ - FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(dst) | T(TMP_REG1) | IMM(SELECT_OP(-64, -32)), DR(TMP_REG1))); - FAIL_IF(push_inst(compiler, SELECT_OP(DSRL32, SRL) | T(TMP_REG1) | D(TMP_REG1) | SH_IMM(SELECT_OP(26, 27)), DR(TMP_REG1))); - return push_inst(compiler, XOR | S(dst) | T(TMP_REG1) | D(dst), DR(dst)); -#else /* SLJIT_MIPS_REV < 1 */ - case SLJIT_CLZ: - case SLJIT_CTZ: - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM)); - return emit_clz_ctz(compiler, op, dst, src2); -#endif /* SLJIT_MIPS_REV >= 1 */ - - case SLJIT_ADD: - /* Overflow computation (both add and sub): overflow = src1_sign ^ src2_sign ^ result_sign ^ carry_flag */ - is_overflow = GET_FLAG_TYPE(op) == SLJIT_OVERFLOW; - carry_src_ar = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY); - - if (flags & SRC2_IMM) { - if (is_overflow) { - if (src2 >= 0) - FAIL_IF(push_inst(compiler, OR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG)); - else - FAIL_IF(push_inst(compiler, NOR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG)); - } - else if (op & SLJIT_SET_Z) - FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG)); - - /* Only the zero flag is needed. */ - if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK)) - FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | T(dst) | IMM(src2), DR(dst))); - } - else { - if (is_overflow) - FAIL_IF(push_inst(compiler, XOR | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG)); - else if (op & SLJIT_SET_Z) - FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG)); - - if (is_overflow || carry_src_ar != 0) { - if (src1 != dst) - carry_src_ar = DR(src1); - else if (src2 != dst) - carry_src_ar = DR(src2); - else { - FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(src1) | TA(0) | DA(OTHER_FLAG), OTHER_FLAG)); - carry_src_ar = OTHER_FLAG; - } - } - - /* Only the zero flag is needed. */ - if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK)) - FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(src1) | T(src2) | D(dst), DR(dst))); - } - - /* Carry is zero if a + b >= a or a + b >= b, otherwise it is 1. */ - if (is_overflow || carry_src_ar != 0) { - if (flags & SRC2_IMM) - FAIL_IF(push_inst(compiler, SLTIU | S(dst) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG)); - else - FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(carry_src_ar) | DA(OTHER_FLAG), OTHER_FLAG)); - } - - if (!is_overflow) - return SLJIT_SUCCESS; - - FAIL_IF(push_inst(compiler, XOR | S(dst) | TA(EQUAL_FLAG) | D(TMP_REG1), DR(TMP_REG1))); - if (op & SLJIT_SET_Z) - FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(dst) | TA(0) | DA(EQUAL_FLAG), EQUAL_FLAG)); - FAIL_IF(push_inst(compiler, SELECT_OP(DSRL32, SRL) | T(TMP_REG1) | D(TMP_REG1) | SH_IMM(31), DR(TMP_REG1))); - return push_inst(compiler, XOR | S(TMP_REG1) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG); - - case SLJIT_ADDC: - carry_src_ar = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY); - - if (flags & SRC2_IMM) { - FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | T(dst) | IMM(src2), DR(dst))); - } else { - if (carry_src_ar != 0) { - if (src1 != dst) - carry_src_ar = DR(src1); - else if (src2 != dst) - carry_src_ar = DR(src2); - else { - FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(src1) | TA(0) | DA(EQUAL_FLAG), EQUAL_FLAG)); - carry_src_ar = EQUAL_FLAG; - } - } - - FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(src1) | T(src2) | D(dst), DR(dst))); - } - - /* Carry is zero if a + b >= a or a + b >= b, otherwise it is 1. */ - if (carry_src_ar != 0) { - if (flags & SRC2_IMM) - FAIL_IF(push_inst(compiler, SLTIU | S(dst) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG)); - else - FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(carry_src_ar) | DA(EQUAL_FLAG), EQUAL_FLAG)); - } - - FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(dst) | TA(OTHER_FLAG) | D(dst), DR(dst))); - - if (carry_src_ar == 0) - return SLJIT_SUCCESS; - - /* Set ULESS_FLAG (dst == 0) && (OTHER_FLAG == 1). */ - FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG)); - /* Set carry flag. */ - return push_inst(compiler, OR | SA(OTHER_FLAG) | TA(EQUAL_FLAG) | DA(OTHER_FLAG), OTHER_FLAG); - - case SLJIT_SUB: - if ((flags & SRC2_IMM) && src2 == SIMM_MIN) { - FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(TMP_REG2) | IMM(src2), DR(TMP_REG2))); - src2 = TMP_REG2; - flags &= ~SRC2_IMM; - } - - is_handled = 0; - - if (flags & SRC2_IMM) { - if (GET_FLAG_TYPE(op) == SLJIT_LESS || GET_FLAG_TYPE(op) == SLJIT_GREATER_EQUAL) { - FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG)); - is_handled = 1; - } - else if (GET_FLAG_TYPE(op) == SLJIT_SIG_LESS || GET_FLAG_TYPE(op) == SLJIT_SIG_GREATER_EQUAL) { - FAIL_IF(push_inst(compiler, SLTI | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG)); - is_handled = 1; - } - } - - if (!is_handled && GET_FLAG_TYPE(op) >= SLJIT_LESS && GET_FLAG_TYPE(op) <= SLJIT_SIG_LESS_EQUAL) { - 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; - flags &= ~SRC2_IMM; - } - - switch (GET_FLAG_TYPE(op)) { - case SLJIT_LESS: - case SLJIT_GREATER_EQUAL: - FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG)); - break; - case SLJIT_GREATER: - case SLJIT_LESS_EQUAL: - FAIL_IF(push_inst(compiler, SLTU | S(src2) | T(src1) | DA(OTHER_FLAG), OTHER_FLAG)); - break; - case SLJIT_SIG_LESS: - case SLJIT_SIG_GREATER_EQUAL: - FAIL_IF(push_inst(compiler, SLT | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG)); - break; - case SLJIT_SIG_GREATER: - case SLJIT_SIG_LESS_EQUAL: - FAIL_IF(push_inst(compiler, SLT | S(src2) | T(src1) | DA(OTHER_FLAG), OTHER_FLAG)); - break; - } - } - - if (is_handled) { - if (flags & SRC2_IMM) { - if (op & SLJIT_SET_Z) - FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | TA(EQUAL_FLAG) | IMM(-src2), EQUAL_FLAG)); - if (!(flags & UNUSED_DEST)) - return push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | T(dst) | IMM(-src2), DR(dst)); - } - else { - if (op & SLJIT_SET_Z) - FAIL_IF(push_inst(compiler, SELECT_OP(DSUBU, SUBU) | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG)); - if (!(flags & UNUSED_DEST)) - return push_inst(compiler, SELECT_OP(DSUBU, SUBU) | S(src1) | T(src2) | D(dst), DR(dst)); - } - return SLJIT_SUCCESS; - } - - is_overflow = GET_FLAG_TYPE(op) == SLJIT_OVERFLOW; - is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY); - - if (flags & SRC2_IMM) { - if (is_overflow) { - if (src2 >= 0) - FAIL_IF(push_inst(compiler, OR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG)); - else - FAIL_IF(push_inst(compiler, NOR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG)); - } - else if (op & SLJIT_SET_Z) - FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | TA(EQUAL_FLAG) | IMM(-src2), EQUAL_FLAG)); - - if (is_overflow || is_carry) - FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG)); - - /* Only the zero flag is needed. */ - if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK)) - FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | T(dst) | IMM(-src2), DR(dst))); - } - else { - if (is_overflow) - FAIL_IF(push_inst(compiler, XOR | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG)); - else if (op & SLJIT_SET_Z) - FAIL_IF(push_inst(compiler, SELECT_OP(DSUBU, SUBU) | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG)); - - if (is_overflow || is_carry) - FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG)); - - /* Only the zero flag is needed. */ - if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK)) - FAIL_IF(push_inst(compiler, SELECT_OP(DSUBU, SUBU) | S(src1) | T(src2) | D(dst), DR(dst))); - } - - if (!is_overflow) - return SLJIT_SUCCESS; - - FAIL_IF(push_inst(compiler, XOR | S(dst) | TA(EQUAL_FLAG) | D(TMP_REG1), DR(TMP_REG1))); - if (op & SLJIT_SET_Z) - FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(dst) | TA(0) | DA(EQUAL_FLAG), EQUAL_FLAG)); - FAIL_IF(push_inst(compiler, SELECT_OP(DSRL32, SRL) | T(TMP_REG1) | D(TMP_REG1) | SH_IMM(31), DR(TMP_REG1))); - return push_inst(compiler, XOR | S(TMP_REG1) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG); - - case SLJIT_SUBC: - if ((flags & SRC2_IMM) && src2 == SIMM_MIN) { - FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(TMP_REG2) | IMM(src2), DR(TMP_REG2))); - src2 = TMP_REG2; - flags &= ~SRC2_IMM; - } - - is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY); - - if (flags & SRC2_IMM) { - if (is_carry) - FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG)); - - FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | T(dst) | IMM(-src2), DR(dst))); - } - else { - if (is_carry) - FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG)); - - FAIL_IF(push_inst(compiler, SELECT_OP(DSUBU, SUBU) | S(src1) | T(src2) | D(dst), DR(dst))); - } - - if (is_carry) - FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(OTHER_FLAG) | D(TMP_REG1), DR(TMP_REG1))); - - FAIL_IF(push_inst(compiler, SELECT_OP(DSUBU, SUBU) | S(dst) | TA(OTHER_FLAG) | D(dst), DR(dst))); - - if (!is_carry) - return SLJIT_SUCCESS; - - return push_inst(compiler, OR | SA(EQUAL_FLAG) | T(TMP_REG1) | DA(OTHER_FLAG), OTHER_FLAG); - - case SLJIT_MUL: - SLJIT_ASSERT(!(flags & SRC2_IMM)); - - if (GET_FLAG_TYPE(op) != SLJIT_OVERFLOW) { -#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6) - return push_inst(compiler, SELECT_OP(DMUL, MUL) | S(src1) | T(src2) | D(dst), DR(dst)); -#elif (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1) -#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) - return push_inst(compiler, MUL | S(src1) | T(src2) | D(dst), DR(dst)); -#else /* !SLJIT_CONFIG_MIPS_32 */ - if (op & SLJIT_32) - return push_inst(compiler, MUL | S(src1) | T(src2) | D(dst), DR(dst)); - FAIL_IF(push_inst(compiler, DMULT | S(src1) | T(src2), MOVABLE_INS)); - return push_inst(compiler, MFLO | D(dst), DR(dst)); -#endif /* SLJIT_CONFIG_MIPS_32 */ -#else /* SLJIT_MIPS_REV < 1 */ - FAIL_IF(push_inst(compiler, SELECT_OP(DMULT, MULT) | S(src1) | T(src2), MOVABLE_INS)); - return push_inst(compiler, MFLO | D(dst), DR(dst)); -#endif /* SLJIT_MIPS_REV >= 6 */ - } - -#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6) - FAIL_IF(push_inst(compiler, SELECT_OP(DMUL, MUL) | S(src1) | T(src2) | D(dst), DR(dst))); - FAIL_IF(push_inst(compiler, SELECT_OP(DMUH, MUH) | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG)); -#else /* SLJIT_MIPS_REV < 6 */ - FAIL_IF(push_inst(compiler, SELECT_OP(DMULT, MULT) | S(src1) | T(src2), MOVABLE_INS)); - FAIL_IF(push_inst(compiler, MFHI | DA(EQUAL_FLAG), EQUAL_FLAG)); - FAIL_IF(push_inst(compiler, MFLO | D(dst), DR(dst))); -#endif /* SLJIT_MIPS_REV >= 6 */ - FAIL_IF(push_inst(compiler, SELECT_OP(DSRA32, SRA) | T(dst) | DA(OTHER_FLAG) | SH_IMM(31), OTHER_FLAG)); - return push_inst(compiler, SELECT_OP(DSUBU, SUBU) | SA(EQUAL_FLAG) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG); - - case SLJIT_AND: - EMIT_LOGICAL(ANDI, AND); - return SLJIT_SUCCESS; - - case SLJIT_OR: - EMIT_LOGICAL(ORI, OR); - return SLJIT_SUCCESS; - - case SLJIT_XOR: - EMIT_LOGICAL(XORI, XOR); - return SLJIT_SUCCESS; - - case SLJIT_SHL: - case SLJIT_MSHL: - EMIT_SHIFT(DSLL, DSLL32, SLL, DSLLV, SLLV); - break; - - case SLJIT_LSHR: - case SLJIT_MLSHR: - EMIT_SHIFT(DSRL, DSRL32, SRL, DSRLV, SRLV); - break; - - case SLJIT_ASHR: - case SLJIT_MASHR: - EMIT_SHIFT(DSRA, DSRA32, SRA, DSRAV, SRAV); - break; - -#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 2) - case SLJIT_ROTL: - if ((flags & SRC2_IMM) || src2 == 0) { -#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) - src2 = -src2 & 0x1f; -#else /* !SLJIT_CONFIG_MIPS_32 */ - src2 = -src2 & ((op & SLJIT_32) ? 0x1f : 0x3f); -#endif /* SLJIT_CONFIG_MIPS_32 */ - } else { - FAIL_IF(push_inst(compiler, SELECT_OP(DSUBU, SUBU) | SA(0) | T(src2) | D(TMP_REG2), DR(TMP_REG2))); - src2 = TMP_REG2; - } - /* fallthrough */ - - case SLJIT_ROTR: - EMIT_SHIFT(DROTR, DROTR32, ROTR, DROTRV, ROTRV); - break; -#else /* SLJIT_MIPS_REV < 1 */ - case SLJIT_ROTL: - case SLJIT_ROTR: - if (flags & SRC2_IMM) { - SLJIT_ASSERT(src2 != 0); -#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) - if (!(op & SLJIT_32)) { - if (GET_OPCODE(op) == SLJIT_ROTL) - op_imm = ((src2 < 32) ? DSLL : DSLL32); - else - op_imm = ((src2 < 32) ? DSRL : DSRL32); - - FAIL_IF(push_inst(compiler, op_imm | T(src1) | DA(OTHER_FLAG) | (((sljit_ins)src2 & 0x1f) << 6), OTHER_FLAG)); - - src2 = 64 - src2; - if (GET_OPCODE(op) == SLJIT_ROTL) - op_imm = ((src2 < 32) ? DSRL : DSRL32); - else - op_imm = ((src2 < 32) ? DSLL : DSLL32); - - FAIL_IF(push_inst(compiler, op_imm | T(src1) | D(dst) | (((sljit_ins)src2 & 0x1f) << 6), DR(dst))); - return push_inst(compiler, OR | S(dst) | TA(OTHER_FLAG) | D(dst), DR(dst)); - } -#endif /* SLJIT_CONFIG_MIPS_64 */ - - op_imm = (GET_OPCODE(op) == SLJIT_ROTL) ? SLL : SRL; - FAIL_IF(push_inst(compiler, op_imm | T(src1) | DA(OTHER_FLAG) | ((sljit_ins)src2 << 6), OTHER_FLAG)); - - src2 = 32 - src2; - op_imm = (GET_OPCODE(op) == SLJIT_ROTL) ? SRL : SLL; - FAIL_IF(push_inst(compiler, op_imm | T(src1) | D(dst) | (((sljit_ins)src2 & 0x1f) << 6), DR(dst))); - return push_inst(compiler, OR | S(dst) | TA(OTHER_FLAG) | D(dst), DR(dst)); - } - - if (src2 == 0) { - if (dst != src1) - return push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(src1) | TA(0) | D(dst), DR(dst)); - return SLJIT_SUCCESS; - } - - FAIL_IF(push_inst(compiler, SELECT_OP(DSUBU, SUBU) | SA(0) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG)); - -#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) - if (!(op & SLJIT_32)) { - op_v = (GET_OPCODE(op) == SLJIT_ROTL) ? DSLLV : DSRLV; - FAIL_IF(push_inst(compiler, op_v | S(src2) | T(src1) | DA(OTHER_FLAG), OTHER_FLAG)); - op_v = (GET_OPCODE(op) == SLJIT_ROTL) ? DSRLV : DSLLV; - FAIL_IF(push_inst(compiler, op_v | SA(EQUAL_FLAG) | T(src1) | D(dst), DR(dst))); - return push_inst(compiler, OR | S(dst) | TA(OTHER_FLAG) | D(dst), DR(dst)); - } -#endif /* SLJIT_CONFIG_MIPS_64 */ - - op_v = (GET_OPCODE(op) == SLJIT_ROTL) ? SLLV : SRLV; - FAIL_IF(push_inst(compiler, op_v | S(src2) | T(src1) | DA(OTHER_FLAG), OTHER_FLAG)); - op_v = (GET_OPCODE(op) == SLJIT_ROTL) ? SRLV : SLLV; - FAIL_IF(push_inst(compiler, op_v | SA(EQUAL_FLAG) | T(src1) | D(dst), DR(dst))); - return push_inst(compiler, OR | S(dst) | TA(OTHER_FLAG) | D(dst), DR(dst)); -#endif /* SLJIT_MIPS_REV >= 2 */ - - default: - SLJIT_UNREACHABLE(); - return SLJIT_SUCCESS; - } - -#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) - if ((flags & SRC2_IMM) || src2 == 0) { - if (op & SLJIT_SET_Z) - FAIL_IF(push_inst(compiler, op_imm | T(src1) | DA(EQUAL_FLAG) | SH_IMM(src2), EQUAL_FLAG)); - - if (flags & UNUSED_DEST) - return SLJIT_SUCCESS; - return push_inst(compiler, op_imm | T(src1) | D(dst) | SH_IMM(src2), DR(dst)); - } - - if (op & SLJIT_SET_Z) - FAIL_IF(push_inst(compiler, op_v | S(src2) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG)); - - if (flags & UNUSED_DEST) - return SLJIT_SUCCESS; - return push_inst(compiler, op_v | S(src2) | T(src1) | D(dst), DR(dst)); -#else /* !SLJIT_CONFIG_MIPS_32 */ - if ((flags & SRC2_IMM) || src2 == 0) { - if (src2 >= 32) { - SLJIT_ASSERT(!(op & SLJIT_32)); - ins = op_dimm32; - src2 -= 32; - } - else - ins = (op & SLJIT_32) ? op_imm : op_dimm; - - if (op & SLJIT_SET_Z) - FAIL_IF(push_inst(compiler, ins | T(src1) | DA(EQUAL_FLAG) | SH_IMM(src2), EQUAL_FLAG)); - - if (flags & UNUSED_DEST) - return SLJIT_SUCCESS; - return push_inst(compiler, ins | T(src1) | D(dst) | SH_IMM(src2), DR(dst)); - } - - ins = (op & SLJIT_32) ? op_v : op_dv; - if (op & SLJIT_SET_Z) - FAIL_IF(push_inst(compiler, ins | S(src2) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG)); - - if (flags & UNUSED_DEST) - return SLJIT_SUCCESS; - return push_inst(compiler, ins | S(src2) | T(src1) | D(dst), DR(dst)); -#endif /* SLJIT_CONFIG_MIPS_32 */ -} - -#define CHECK_IMM(flags, srcw) \ - ((!((flags) & LOGICAL_OP) && ((srcw) <= SIMM_MAX && (srcw) >= SIMM_MIN)) \ - || (((flags) & LOGICAL_OP) && !((srcw) & ~UIMM_MAX))) - -static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 flags, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - /* arg1 goes to TMP_REG1 or src reg - arg2 goes to TMP_REG2, imm or src reg - TMP_REG3 can be used for caching - result goes to TMP_REG2, so put result can use TMP_REG1 and TMP_REG3. */ - sljit_s32 dst_r = TMP_REG2; - sljit_s32 src1_r; - sljit_sw src2_r = 0; - sljit_s32 sugg_src2_r = TMP_REG2; - - if (!(flags & ALT_KEEP_CACHE)) { - compiler->cache_arg = 0; - compiler->cache_argw = 0; - } - - if (dst == TMP_REG2) { - SLJIT_ASSERT(HAS_FLAGS(op)); - flags |= UNUSED_DEST; - } - 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, DR(TMP_REG1), dst, dstw)) - flags |= SLOW_DEST; - - if (flags & IMM_OP) { - if ((src2 & SLJIT_IMM) && src2w != 0 && CHECK_IMM(flags, src2w)) { - flags |= SRC2_IMM; - src2_r = src2w; - } else if ((flags & CUMULATIVE_OP) && (src1 & SLJIT_IMM) && src1w != 0 && CHECK_IMM(flags, src1w)) { - flags |= SRC2_IMM; - src2_r = src1w; - - /* And swap arguments. */ - src1 = src2; - src1w = src2w; - src2 = SLJIT_IMM; - /* src2w = src2_r unneeded. */ - } - } - - /* Source 1. */ - if (FAST_IS_REG(src1)) { - src1_r = src1; - flags |= REG1_SOURCE; - } - else if (src1 & SLJIT_IMM) { - if (src1w) { - FAIL_IF(load_immediate(compiler, DR(TMP_REG1), src1w)); - src1_r = TMP_REG1; - } - else - src1_r = 0; - } - else { - if (getput_arg_fast(compiler, flags | LOAD_DATA, DR(TMP_REG1), src1, src1w)) - FAIL_IF(compiler->error); - else - flags |= SLOW_SRC1; - src1_r = TMP_REG1; - } - - /* Source 2. */ - if (FAST_IS_REG(src2)) { - src2_r = src2; - flags |= REG2_SOURCE; - if ((flags & (REG_DEST | MOVE_OP)) == MOVE_OP) - dst_r = (sljit_s32)src2_r; - } - 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; - } - else { - src2_r = 0; - if (flags & MOVE_OP) { - if (dst & SLJIT_MEM) - dst_r = 0; - else - op = SLJIT_MOV; - } - } - } - } - else { - if (getput_arg_fast(compiler, flags | LOAD_DATA, DR(sugg_src2_r), src2, src2w)) - FAIL_IF(compiler->error); - else - flags |= SLOW_SRC2; - src2_r = sugg_src2_r; - } - - 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)) { - 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)); - } - else { - FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, DR(TMP_REG1), src1, src1w, src2, src2w)); - FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, DR(TMP_REG2), src2, src2w, dst, dstw)); - } - } - 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(emit_single_op(compiler, op, flags, dst_r, src1_r, src2_r)); - - if (dst & SLJIT_MEM) { - if (!(flags & SLOW_DEST)) { - getput_arg_fast(compiler, flags, DR(dst_r), dst, dstw); - return compiler->error; - } - return getput_arg(compiler, flags, DR(dst_r), dst, dstw, 0, 0); - } - - return SLJIT_SUCCESS; -} - -#undef CHECK_IMM - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compiler, sljit_s32 op) -{ -#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) - sljit_s32 int_op = op & SLJIT_32; -#endif - - CHECK_ERROR(); - CHECK(check_sljit_emit_op0(compiler, op)); - - op = GET_OPCODE(op); - switch (op) { - case SLJIT_BREAKPOINT: - return push_inst(compiler, BREAK, UNMOVABLE_INS); - case SLJIT_NOP: - return push_inst(compiler, NOP, UNMOVABLE_INS); - case SLJIT_LMUL_UW: - case SLJIT_LMUL_SW: -#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6) -#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) - FAIL_IF(push_inst(compiler, (op == SLJIT_LMUL_UW ? DMULU : DMUL) | S(SLJIT_R0) | T(SLJIT_R1) | D(TMP_REG3), DR(TMP_REG3))); - FAIL_IF(push_inst(compiler, (op == SLJIT_LMUL_UW ? DMUHU : DMUH) | S(SLJIT_R0) | T(SLJIT_R1) | D(TMP_REG1), DR(TMP_REG1))); -#else /* !SLJIT_CONFIG_MIPS_64 */ - FAIL_IF(push_inst(compiler, (op == SLJIT_LMUL_UW ? MULU : MUL) | S(SLJIT_R0) | T(SLJIT_R1) | D(TMP_REG3), DR(TMP_REG3))); - FAIL_IF(push_inst(compiler, (op == SLJIT_LMUL_UW ? MUHU : MUH) | S(SLJIT_R0) | T(SLJIT_R1) | D(TMP_REG1), DR(TMP_REG1))); -#endif /* SLJIT_CONFIG_MIPS_64 */ - FAIL_IF(push_inst(compiler, ADDU_W | S(TMP_REG3) | TA(0) | D(SLJIT_R0), DR(SLJIT_R0))); - return push_inst(compiler, ADDU_W | S(TMP_REG1) | TA(0) | D(SLJIT_R1), DR(SLJIT_R1)); -#else /* SLJIT_MIPS_REV < 6 */ -#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) - FAIL_IF(push_inst(compiler, (op == SLJIT_LMUL_UW ? DMULTU : DMULT) | S(SLJIT_R0) | T(SLJIT_R1), MOVABLE_INS)); -#else /* !SLJIT_CONFIG_MIPS_64 */ - FAIL_IF(push_inst(compiler, (op == SLJIT_LMUL_UW ? MULTU : MULT) | S(SLJIT_R0) | T(SLJIT_R1), MOVABLE_INS)); -#endif /* SLJIT_CONFIG_MIPS_64 */ - FAIL_IF(push_inst(compiler, MFLO | D(SLJIT_R0), DR(SLJIT_R0))); - return push_inst(compiler, MFHI | D(SLJIT_R1), DR(SLJIT_R1)); -#endif /* SLJIT_MIPS_REV >= 6 */ - case SLJIT_DIVMOD_UW: - case SLJIT_DIVMOD_SW: - case SLJIT_DIV_UW: - case SLJIT_DIV_SW: - SLJIT_COMPILE_ASSERT((SLJIT_DIVMOD_UW & 0x2) == 0 && SLJIT_DIV_UW - 0x2 == SLJIT_DIVMOD_UW, bad_div_opcode_assignments); -#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6) -#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) - if (int_op) { - FAIL_IF(push_inst(compiler, ((op | 0x2) == SLJIT_DIV_UW ? DIVU : DIV) | S(SLJIT_R0) | T(SLJIT_R1) | D(TMP_REG3), DR(TMP_REG3))); - FAIL_IF(push_inst(compiler, ((op | 0x2) == SLJIT_DIV_UW ? MODU : MOD) | S(SLJIT_R0) | T(SLJIT_R1) | D(TMP_REG1), DR(TMP_REG1))); - } - else { - FAIL_IF(push_inst(compiler, ((op | 0x2) == SLJIT_DIV_UW ? DDIVU : DDIV) | S(SLJIT_R0) | T(SLJIT_R1) | D(TMP_REG3), DR(TMP_REG3))); - FAIL_IF(push_inst(compiler, ((op | 0x2) == SLJIT_DIV_UW ? DMODU : DMOD) | S(SLJIT_R0) | T(SLJIT_R1) | D(TMP_REG1), DR(TMP_REG1))); - } -#else /* !SLJIT_CONFIG_MIPS_64 */ - FAIL_IF(push_inst(compiler, ((op | 0x2) == SLJIT_DIV_UW ? DIVU : DIV) | S(SLJIT_R0) | T(SLJIT_R1) | D(TMP_REG3), DR(TMP_REG3))); - FAIL_IF(push_inst(compiler, ((op | 0x2) == SLJIT_DIV_UW ? MODU : MOD) | S(SLJIT_R0) | T(SLJIT_R1) | D(TMP_REG1), DR(TMP_REG1))); -#endif /* SLJIT_CONFIG_MIPS_64 */ - FAIL_IF(push_inst(compiler, ADDU_W | S(TMP_REG3) | TA(0) | D(SLJIT_R0), DR(SLJIT_R0))); - return (op >= SLJIT_DIV_UW) ? SLJIT_SUCCESS : push_inst(compiler, ADDU_W | S(TMP_REG1) | TA(0) | D(SLJIT_R1), DR(SLJIT_R1)); -#else /* SLJIT_MIPS_REV < 6 */ -#if !(defined SLJIT_MIPS_REV) - FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS)); - FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS)); -#endif /* !SLJIT_MIPS_REV */ -#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) - if (int_op) - FAIL_IF(push_inst(compiler, ((op | 0x2) == SLJIT_DIV_UW ? DIVU : DIV) | S(SLJIT_R0) | T(SLJIT_R1), MOVABLE_INS)); - else - FAIL_IF(push_inst(compiler, ((op | 0x2) == SLJIT_DIV_UW ? DDIVU : DDIV) | S(SLJIT_R0) | T(SLJIT_R1), MOVABLE_INS)); -#else /* !SLJIT_CONFIG_MIPS_64 */ - FAIL_IF(push_inst(compiler, ((op | 0x2) == SLJIT_DIV_UW ? DIVU : DIV) | S(SLJIT_R0) | T(SLJIT_R1), MOVABLE_INS)); -#endif /* SLJIT_CONFIG_MIPS_64 */ - FAIL_IF(push_inst(compiler, MFLO | D(SLJIT_R0), DR(SLJIT_R0))); - return (op >= SLJIT_DIV_UW) ? SLJIT_SUCCESS : push_inst(compiler, MFHI | D(SLJIT_R1), DR(SLJIT_R1)); -#endif /* SLJIT_MIPS_REV >= 6 */ - case SLJIT_ENDBR: - case SLJIT_SKIP_FRAMES_BEFORE_RETURN: - return SLJIT_SUCCESS; - } - - return SLJIT_SUCCESS; -} - -#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1) -static sljit_s32 emit_prefetch(struct sljit_compiler *compiler, - sljit_s32 src, sljit_sw srcw) -{ - if (!(src & OFFS_REG_MASK)) { - if (srcw <= SIMM_MAX && srcw >= SIMM_MIN) - return push_inst(compiler, PREF | S(src & REG_MASK) | IMM(srcw), MOVABLE_INS); - - FAIL_IF(load_immediate(compiler, DR(TMP_REG1), srcw)); - return push_inst(compiler, PREFX | S(src & REG_MASK) | T(TMP_REG1), MOVABLE_INS); - } - - srcw &= 0x3; - - if (SLJIT_UNLIKELY(srcw != 0)) { - FAIL_IF(push_inst(compiler, SLL_W | T(OFFS_REG(src)) | D(TMP_REG1) | SH_IMM(srcw), DR(TMP_REG1))); - return push_inst(compiler, PREFX | S(src & REG_MASK) | T(TMP_REG1), MOVABLE_INS); - } - - return push_inst(compiler, PREFX | S(src & REG_MASK) | T(OFFS_REG(src)), MOVABLE_INS); -} -#endif /* SLJIT_MIPS_REV >= 1 */ - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src, sljit_sw srcw) -{ - sljit_s32 flags = 0; - - CHECK_ERROR(); - CHECK(check_sljit_emit_op1(compiler, op, dst, dstw, src, srcw)); - ADJUST_LOCAL_OFFSET(dst, dstw); - ADJUST_LOCAL_OFFSET(src, srcw); - -#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) - if (op & SLJIT_32) - flags = INT_DATA | SIGNED_DATA; -#endif - - switch (GET_OPCODE(op)) { - case SLJIT_MOV: -#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) - case SLJIT_MOV_U32: - case SLJIT_MOV_S32: - 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); - -#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_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); - - case SLJIT_MOV_S32: - 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); -#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); - - 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); - - 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); - - 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); - - case SLJIT_NOT: - return emit_op(compiler, op, flags, dst, dstw, TMP_REG1, 0, src, srcw); - - case SLJIT_CLZ: - case SLJIT_CTZ: - return emit_op(compiler, op, flags, dst, dstw, TMP_REG1, 0, src, srcw); - } - - SLJIT_UNREACHABLE(); - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - sljit_s32 flags = 0; - - CHECK_ERROR(); - CHECK(check_sljit_emit_op2(compiler, op, 0, dst, dstw, src1, src1w, src2, src2w)); - ADJUST_LOCAL_OFFSET(dst, dstw); - ADJUST_LOCAL_OFFSET(src1, src1w); - ADJUST_LOCAL_OFFSET(src2, src2w); - -#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) - if (op & SLJIT_32) { - flags |= INT_DATA | SIGNED_DATA; - if (src1 & SLJIT_IMM) - src1w = (sljit_s32)src1w; - if (src2 & SLJIT_IMM) - src2w = (sljit_s32)src2w; - } -#endif - - switch (GET_OPCODE(op)) { - case SLJIT_ADD: - case SLJIT_ADDC: - compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD; - return emit_op(compiler, op, flags | CUMULATIVE_OP | IMM_OP, dst, dstw, src1, src1w, src2, src2w); - - case SLJIT_SUB: - case SLJIT_SUBC: - compiler->status_flags_state = SLJIT_CURRENT_FLAGS_SUB; - return emit_op(compiler, op, flags | IMM_OP, dst, dstw, src1, src1w, src2, src2w); - - case SLJIT_MUL: - compiler->status_flags_state = 0; - return emit_op(compiler, op, flags | CUMULATIVE_OP, dst, dstw, src1, src1w, src2, src2w); - - case SLJIT_AND: - case SLJIT_OR: - case SLJIT_XOR: - return emit_op(compiler, op, flags | CUMULATIVE_OP | LOGICAL_OP | IMM_OP, dst, dstw, src1, src1w, src2, src2w); - - case SLJIT_SHL: - case SLJIT_MSHL: - case SLJIT_LSHR: - case SLJIT_MLSHR: - case SLJIT_ASHR: - case SLJIT_MASHR: - case SLJIT_ROTL: - case SLJIT_ROTR: -#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) - if (src2 & SLJIT_IMM) - src2w &= 0x1f; -#else - if (src2 & SLJIT_IMM) { - if (op & SLJIT_32) - src2w &= 0x1f; - else - src2w &= 0x3f; - } -#endif - return emit_op(compiler, op, flags | IMM_OP, dst, dstw, src1, src1w, src2, src2w); - } - - SLJIT_UNREACHABLE(); - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - 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, TMP_REG2, 0, src1, src1w, src2, src2w); -} - -#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_shift_into(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 src_dst, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - sljit_s32 is_left; - sljit_ins ins1, ins2, ins3; -#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) - sljit_s32 inp_flags = ((op & SLJIT_32) ? INT_DATA : WORD_DATA) | LOAD_DATA; - sljit_sw bit_length = (op & SLJIT_32) ? 32 : 64; -#else /* !SLJIT_CONFIG_MIPS_64 */ - sljit_s32 inp_flags = WORD_DATA | LOAD_DATA; - sljit_sw bit_length = 32; -#endif /* SLJIT_CONFIG_MIPS_64 */ - - CHECK_ERROR(); - CHECK(check_sljit_emit_shift_into(compiler, op, src_dst, src1, src1w, src2, src2w)); - - is_left = (GET_OPCODE(op) == SLJIT_SHL || GET_OPCODE(op) == SLJIT_MSHL); - - if (src_dst == src1) { - SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_op2(compiler, (is_left ? SLJIT_ROTL : SLJIT_ROTR) | (op & SLJIT_32), src_dst, 0, src_dst, 0, src2, src2w); - } - - ADJUST_LOCAL_OFFSET(src1, src1w); - ADJUST_LOCAL_OFFSET(src2, src2w); - - if (src2 & SLJIT_IMM) { - src2w &= bit_length - 1; - - if (src2w == 0) - return SLJIT_SUCCESS; - } else if (src2 & SLJIT_MEM) { - FAIL_IF(emit_op_mem(compiler, inp_flags, DR(TMP_REG2), src2, src2w)); - src2 = TMP_REG2; - } - - if (src1 & SLJIT_MEM) { - FAIL_IF(emit_op_mem(compiler, inp_flags, DR(TMP_REG1), src1, src1w)); - src1 = TMP_REG1; - } else if (src1 & SLJIT_IMM) { - FAIL_IF(load_immediate(compiler, DR(TMP_REG1), src1w)); - src1 = TMP_REG1; - } - - if (src2 & SLJIT_IMM) { - if (is_left) { - ins1 = SELECT_OP3(op, src2w, DSLL, DSLL32, SLL); - src2w = bit_length - src2w; - ins2 = SELECT_OP3(op, src2w, DSRL, DSRL32, SRL); - } else { - ins1 = SELECT_OP3(op, src2w, DSRL, DSRL32, SRL); - src2w = bit_length - src2w; - ins2 = SELECT_OP3(op, src2w, DSLL, DSLL32, SLL); - } - - FAIL_IF(push_inst(compiler, ins1 | T(src_dst) | D(src_dst), DR(src_dst))); - FAIL_IF(push_inst(compiler, ins2 | T(src1) | D(TMP_REG1), DR(TMP_REG1))); - return push_inst(compiler, OR | S(src_dst) | T(TMP_REG1) | D(src_dst), DR(src_dst)); - } - - if (is_left) { - ins1 = SELECT_OP2(op, DSRL, SRL); - ins2 = SELECT_OP2(op, DSLLV, SLLV); - ins3 = SELECT_OP2(op, DSRLV, SRLV); - } else { - ins1 = SELECT_OP2(op, DSLL, SLL); - ins2 = SELECT_OP2(op, DSRLV, SRLV); - ins3 = SELECT_OP2(op, DSLLV, SLLV); - } - - FAIL_IF(push_inst(compiler, ins2 | S(src2) | T(src_dst) | D(src_dst), DR(src_dst))); - - if (!(op & SLJIT_SHIFT_INTO_NON_ZERO)) { - FAIL_IF(push_inst(compiler, ins1 | T(src1) | D(TMP_REG1) | (1 << 6), DR(TMP_REG1))); - FAIL_IF(push_inst(compiler, XORI | S(src2) | T(TMP_REG2) | ((sljit_ins)bit_length - 1), DR(TMP_REG2))); - src1 = TMP_REG1; - } else - FAIL_IF(push_inst(compiler, SELECT_OP2(op, DSUBU, SUBU) | SA(0) | T(src2) | D(TMP_REG2), DR(TMP_REG2))); - - FAIL_IF(push_inst(compiler, ins3 | S(TMP_REG2) | T(src1) | D(TMP_REG1), DR(TMP_REG1))); - return push_inst(compiler, OR | S(src_dst) | T(TMP_REG1) | D(src_dst), DR(src_dst)); -} - -#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) -{ - CHECK_ERROR(); - CHECK(check_sljit_emit_op_src(compiler, op, src, srcw)); - ADJUST_LOCAL_OFFSET(src, srcw); - - switch (op) { - case SLJIT_FAST_RETURN: - if (FAST_IS_REG(src)) - FAIL_IF(push_inst(compiler, ADDU_W | S(src) | TA(0) | DA(RETURN_ADDR_REG), RETURN_ADDR_REG)); - else - FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, RETURN_ADDR_REG, src, srcw)); - - FAIL_IF(push_inst(compiler, JR | SA(RETURN_ADDR_REG), UNMOVABLE_INS)); - return push_inst(compiler, NOP, UNMOVABLE_INS); - case SLJIT_SKIP_FRAMES_BEFORE_FAST_RETURN: - return SLJIT_SUCCESS; - case SLJIT_PREFETCH_L1: - case SLJIT_PREFETCH_L2: - case SLJIT_PREFETCH_L3: - case SLJIT_PREFETCH_ONCE: -#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1) - return emit_prefetch(compiler, src, srcw); -#else /* SLJIT_MIPS_REV < 1 */ - return SLJIT_SUCCESS; -#endif /* SLJIT_MIPS_REV >= 1 */ - } - - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 reg) -{ - CHECK_REG_INDEX(check_sljit_get_register_index(reg)); - return reg_map[reg]; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_float_register_index(sljit_s32 reg) -{ - CHECK_REG_INDEX(check_sljit_get_float_register_index(reg)); - return FR(reg); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler, - void *instruction, sljit_u32 size) -{ - CHECK_ERROR(); - CHECK(check_sljit_emit_op_custom(compiler, instruction, size)); - - return push_inst(compiler, *(sljit_ins*)instruction, UNMOVABLE_INS); -} - -/* --------------------------------------------------------------------- */ -/* Floating point operators */ -/* --------------------------------------------------------------------- */ - -#define FLOAT_DATA(op) (DOUBLE_DATA | ((op & SLJIT_32) >> 7)) -#define FMT(op) ((((sljit_ins)op & SLJIT_32) ^ SLJIT_32) << (21 - 8)) - -static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src, sljit_sw srcw) -{ -#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) -# define flags (sljit_u32)0 -#else - sljit_u32 flags = ((sljit_u32)(GET_OPCODE(op) == SLJIT_CONV_SW_FROM_F64)) << 21; -#endif - - if (src & SLJIT_MEM) { - FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, FR(TMP_FREG1), src, srcw, dst, dstw)); - src = TMP_FREG1; - } - - FAIL_IF(push_inst(compiler, (TRUNC_W_S ^ (flags >> 19)) | FMT(op) | FS(src) | FD(TMP_FREG1), MOVABLE_INS)); - - if (FAST_IS_REG(dst)) { - FAIL_IF(push_inst(compiler, MFC1 | flags | T(dst) | FS(TMP_FREG1), MOVABLE_INS)); -#if (!defined SLJIT_MIPS_REV || SLJIT_MIPS_REV <= 3) - FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS)); -#endif - return SLJIT_SUCCESS; - } - - /* Store the integer value from a VFP register. */ - return emit_op_mem2(compiler, flags ? DOUBLE_DATA : SINGLE_DATA, FR(TMP_FREG1), dst, dstw, 0, 0); - -#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) -# undef flags -#endif -} - -static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src, sljit_sw srcw) -{ -#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) -# define flags (sljit_u32)0 -#else - sljit_u32 flags = ((sljit_u32)(GET_OPCODE(op) == SLJIT_CONV_F64_FROM_SW)) << 21; -#endif - - sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1; - - if (FAST_IS_REG(src)) { - FAIL_IF(push_inst(compiler, MTC1 | flags | T(src) | FS(TMP_FREG1), MOVABLE_INS)); -#if (!defined SLJIT_MIPS_REV || SLJIT_MIPS_REV <= 3) - FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS)); -#endif - } else if (src & SLJIT_MEM) { - /* Load the integer value into a VFP register. */ - FAIL_IF(emit_op_mem2(compiler, (flags ? DOUBLE_DATA : SINGLE_DATA) | LOAD_DATA, FR(TMP_FREG1), src, srcw, dst, dstw)); - } - else { -#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) - if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32) - srcw = (sljit_s32)srcw; -#endif - FAIL_IF(load_immediate(compiler, DR(TMP_REG1), srcw)); - FAIL_IF(push_inst(compiler, MTC1 | flags | T(TMP_REG1) | FS(TMP_FREG1), MOVABLE_INS)); -#if (!defined SLJIT_MIPS_REV || SLJIT_MIPS_REV <= 3) - FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS)); -#endif - } - - FAIL_IF(push_inst(compiler, CVT_S_S | flags | (4 << 21) | ((((sljit_ins)op & SLJIT_32) ^ SLJIT_32) >> 8) | FS(TMP_FREG1) | FD(dst_r), MOVABLE_INS)); - - if (dst & SLJIT_MEM) - return emit_op_mem2(compiler, FLOAT_DATA(op), FR(TMP_FREG1), dst, dstw, 0, 0); - return SLJIT_SUCCESS; - -#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) -# undef flags -#endif -} - -static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - sljit_ins inst; - - if (src1 & SLJIT_MEM) { - FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, FR(TMP_FREG1), src1, src1w, src2, src2w)); - src1 = TMP_FREG1; - } - - if (src2 & SLJIT_MEM) { - FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, FR(TMP_FREG2), src2, src2w, 0, 0)); - src2 = TMP_FREG2; - } - - switch (GET_FLAG_TYPE(op)) { - case SLJIT_F_EQUAL: - case SLJIT_ORDERED_EQUAL: - case SLJIT_UNORDERED_OR_NOT_EQUAL: - inst = C_EQ_S; - break; - case SLJIT_F_NOT_EQUAL: - case SLJIT_UNORDERED_OR_EQUAL: - case SLJIT_ORDERED_NOT_EQUAL: - inst = C_UEQ_S; - break; - case SLJIT_F_LESS: - case SLJIT_ORDERED_LESS: - case SLJIT_UNORDERED_OR_GREATER_EQUAL: - inst = C_OLT_S; - break; - case SLJIT_F_GREATER_EQUAL: - case SLJIT_UNORDERED_OR_LESS: - case SLJIT_ORDERED_GREATER_EQUAL: - inst = C_ULT_S; - break; - case SLJIT_F_GREATER: - case SLJIT_ORDERED_GREATER: - case SLJIT_UNORDERED_OR_LESS_EQUAL: - inst = C_ULE_S; - break; - case SLJIT_F_LESS_EQUAL: - case SLJIT_UNORDERED_OR_GREATER: - case SLJIT_ORDERED_LESS_EQUAL: - inst = C_OLE_S; - break; - default: - SLJIT_ASSERT(GET_FLAG_TYPE(op) == SLJIT_UNORDERED || GET_FLAG_TYPE(op) == SLJIT_ORDERED); - inst = C_UN_S; - break; - } - return push_inst(compiler, inst | FMT(op) | FT(src2) | FS(src1) | C_FD, UNMOVABLE_INS); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src, sljit_sw srcw) -{ - sljit_s32 dst_r; - - CHECK_ERROR(); - compiler->cache_arg = 0; - compiler->cache_argw = 0; - - SLJIT_COMPILE_ASSERT((SLJIT_32 == 0x100) && !(DOUBLE_DATA & 0x2), float_transfer_bit_error); - SELECT_FOP1_OPERATION_WITH_CHECKS(compiler, op, dst, dstw, src, srcw); - - if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_F32) - op ^= SLJIT_32; - - dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1; - - if (src & SLJIT_MEM) { - FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, FR(dst_r), src, srcw, dst, dstw)); - src = dst_r; - } - - switch (GET_OPCODE(op)) { - case SLJIT_MOV_F64: - if (src != dst_r) { - if (dst_r != TMP_FREG1) - FAIL_IF(push_inst(compiler, MOV_S | FMT(op) | FS(src) | FD(dst_r), MOVABLE_INS)); - else - dst_r = src; - } - break; - case SLJIT_NEG_F64: - FAIL_IF(push_inst(compiler, NEG_S | FMT(op) | FS(src) | FD(dst_r), MOVABLE_INS)); - break; - case SLJIT_ABS_F64: - FAIL_IF(push_inst(compiler, ABS_S | FMT(op) | FS(src) | FD(dst_r), MOVABLE_INS)); - break; - case SLJIT_CONV_F64_FROM_F32: - /* The SLJIT_32 bit is inverted because sljit_f32 needs to be loaded from the memory. */ - FAIL_IF(push_inst(compiler, CVT_S_S | (sljit_ins)((op & SLJIT_32) ? 1 : (1 << 21)) | FS(src) | FD(dst_r), MOVABLE_INS)); - op ^= SLJIT_32; - break; - } - - if (dst & SLJIT_MEM) - return emit_op_mem2(compiler, FLOAT_DATA(op), FR(dst_r), dst, dstw, 0, 0); - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - sljit_s32 dst_r, flags = 0; - - CHECK_ERROR(); - CHECK(check_sljit_emit_fop2(compiler, op, dst, dstw, src1, src1w, src2, src2w)); - ADJUST_LOCAL_OFFSET(dst, dstw); - ADJUST_LOCAL_OFFSET(src1, src1w); - ADJUST_LOCAL_OFFSET(src2, src2w); - - compiler->cache_arg = 0; - compiler->cache_argw = 0; - - dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG2; - - if (src1 & SLJIT_MEM) { - if (getput_arg_fast(compiler, FLOAT_DATA(op) | LOAD_DATA, FR(TMP_FREG1), src1, src1w)) { - FAIL_IF(compiler->error); - src1 = TMP_FREG1; - } else - flags |= SLOW_SRC1; - } - - if (src2 & SLJIT_MEM) { - if (getput_arg_fast(compiler, FLOAT_DATA(op) | LOAD_DATA, FR(TMP_FREG2), src2, src2w)) { - FAIL_IF(compiler->error); - src2 = TMP_FREG2; - } else - flags |= SLOW_SRC2; - } - - if ((flags & (SLOW_SRC1 | SLOW_SRC2)) == (SLOW_SRC1 | SLOW_SRC2)) { - if (!can_cache(src1, src1w, src2, src2w) && can_cache(src1, src1w, dst, dstw)) { - FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, 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 { - 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)); - } - } - else if (flags & SLOW_SRC1) - FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, FR(TMP_FREG1), src1, src1w, dst, dstw)); - else if (flags & SLOW_SRC2) - FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, FR(TMP_FREG2), src2, src2w, dst, dstw)); - - if (flags & SLOW_SRC1) - src1 = TMP_FREG1; - if (flags & SLOW_SRC2) - src2 = TMP_FREG2; - - switch (GET_OPCODE(op)) { - case SLJIT_ADD_F64: - FAIL_IF(push_inst(compiler, ADD_S | FMT(op) | FT(src2) | FS(src1) | FD(dst_r), MOVABLE_INS)); - break; - - case SLJIT_SUB_F64: - FAIL_IF(push_inst(compiler, SUB_S | FMT(op) | FT(src2) | FS(src1) | FD(dst_r), MOVABLE_INS)); - break; - - case SLJIT_MUL_F64: - FAIL_IF(push_inst(compiler, MUL_S | FMT(op) | FT(src2) | FS(src1) | FD(dst_r), MOVABLE_INS)); - break; - - case SLJIT_DIV_F64: - FAIL_IF(push_inst(compiler, DIV_S | FMT(op) | FT(src2) | FS(src1) | FD(dst_r), MOVABLE_INS)); - break; - } - - if (dst_r == TMP_FREG2) - FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op), FR(TMP_FREG2), dst, dstw, 0, 0)); - - return SLJIT_SUCCESS; -} - -#undef FLOAT_DATA -#undef FMT - -/* --------------------------------------------------------------------- */ -/* Other instructions */ -/* --------------------------------------------------------------------- */ - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw) -{ - CHECK_ERROR(); - CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw)); - ADJUST_LOCAL_OFFSET(dst, dstw); - - if (FAST_IS_REG(dst)) - return push_inst(compiler, ADDU_W | SA(RETURN_ADDR_REG) | TA(0) | D(dst), UNMOVABLE_INS); - - /* Memory. */ - FAIL_IF(emit_op_mem(compiler, WORD_DATA, RETURN_ADDR_REG, dst, dstw)); - compiler->delay_slot = UNMOVABLE_INS; - return SLJIT_SUCCESS; -} - -/* --------------------------------------------------------------------- */ -/* Conditional instructions */ -/* --------------------------------------------------------------------- */ - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compiler *compiler) -{ - struct sljit_label *label; - - CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_label(compiler)); - - if (compiler->last_label && compiler->last_label->size == compiler->size) - return compiler->last_label; - - label = (struct sljit_label*)ensure_abuf(compiler, sizeof(struct sljit_label)); - PTR_FAIL_IF(!label); - set_label(label, compiler); - compiler->delay_slot = UNMOVABLE_INS; - return label; -} - -#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) -#define BRANCH_LENGTH 4 -#else -#define BRANCH_LENGTH 8 -#endif - -#define BR_Z(src) \ - inst = BEQ | SA(src) | TA(0) | BRANCH_LENGTH; \ - flags = IS_BIT26_COND; \ - delay_check = src; - -#define BR_NZ(src) \ - inst = BNE | SA(src) | TA(0) | BRANCH_LENGTH; \ - flags = IS_BIT26_COND; \ - delay_check = src; - -#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6) - -#define BR_T() \ - inst = BC1NEZ; \ - flags = IS_BIT23_COND; \ - delay_check = FCSR_FCC; -#define BR_F() \ - inst = BC1EQZ; \ - flags = IS_BIT23_COND; \ - delay_check = FCSR_FCC; - -#else /* SLJIT_MIPS_REV < 6 */ - -#define BR_T() \ - inst = BC1T | BRANCH_LENGTH; \ - flags = IS_BIT16_COND; \ - delay_check = FCSR_FCC; -#define BR_F() \ - inst = BC1F | BRANCH_LENGTH; \ - flags = IS_BIT16_COND; \ - delay_check = FCSR_FCC; - -#endif /* SLJIT_MIPS_REV >= 6 */ - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type) -{ - struct sljit_jump *jump; - sljit_ins inst; - sljit_u32 flags = 0; - sljit_s32 delay_check = UNMOVABLE_INS; - - CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_jump(compiler, type)); - - jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump)); - PTR_FAIL_IF(!jump); - set_jump(jump, compiler, type & SLJIT_REWRITABLE_JUMP); - type &= 0xff; - - switch (type) { - case SLJIT_EQUAL: - BR_NZ(EQUAL_FLAG); - break; - case SLJIT_NOT_EQUAL: - BR_Z(EQUAL_FLAG); - break; - case SLJIT_LESS: - case SLJIT_GREATER: - case SLJIT_SIG_LESS: - case SLJIT_SIG_GREATER: - case SLJIT_OVERFLOW: - case SLJIT_CARRY: - BR_Z(OTHER_FLAG); - break; - case SLJIT_GREATER_EQUAL: - case SLJIT_LESS_EQUAL: - case SLJIT_SIG_GREATER_EQUAL: - case SLJIT_SIG_LESS_EQUAL: - case SLJIT_NOT_OVERFLOW: - case SLJIT_NOT_CARRY: - BR_NZ(OTHER_FLAG); - break; - case SLJIT_F_NOT_EQUAL: - case SLJIT_F_GREATER_EQUAL: - case SLJIT_F_GREATER: - case SLJIT_UNORDERED_OR_NOT_EQUAL: - case SLJIT_ORDERED_NOT_EQUAL: - case SLJIT_UNORDERED_OR_GREATER_EQUAL: - case SLJIT_ORDERED_GREATER_EQUAL: - case SLJIT_ORDERED_GREATER: - case SLJIT_UNORDERED_OR_GREATER: - case SLJIT_ORDERED: - BR_T(); - break; - case SLJIT_F_EQUAL: - case SLJIT_F_LESS: - case SLJIT_F_LESS_EQUAL: - case SLJIT_ORDERED_EQUAL: - case SLJIT_UNORDERED_OR_EQUAL: - case SLJIT_ORDERED_LESS: - case SLJIT_UNORDERED_OR_LESS: - case SLJIT_UNORDERED_OR_LESS_EQUAL: - case SLJIT_ORDERED_LESS_EQUAL: - case SLJIT_UNORDERED: - BR_F(); - break; - default: - /* Not conditional branch. */ - inst = 0; - break; - } - - jump->flags |= flags; - if (compiler->delay_slot == MOVABLE_INS || (compiler->delay_slot != UNMOVABLE_INS && compiler->delay_slot != delay_check)) - jump->flags |= IS_MOVABLE; - - if (inst) - 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)); - else { - jump->flags |= IS_JAL; - PTR_FAIL_IF(push_inst(compiler, JALR | S(TMP_REG2) | DA(RETURN_ADDR_REG), UNMOVABLE_INS)); - } - - jump->addr = compiler->size; - PTR_FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS)); - - /* Maximum number of instructions required for generating a constant. */ -#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) - compiler->size += 2; -#else - compiler->size += 6; -#endif - return jump; -} - -#define RESOLVE_IMM1() \ - if (src1 & SLJIT_IMM) { \ - if (src1w) { \ - PTR_FAIL_IF(load_immediate(compiler, DR(TMP_REG1), src1w)); \ - src1 = TMP_REG1; \ - } \ - else \ - src1 = 0; \ - } - -#define RESOLVE_IMM2() \ - if (src2 & SLJIT_IMM) { \ - if (src2w) { \ - PTR_FAIL_IF(load_immediate(compiler, DR(TMP_REG2), src2w)); \ - src2 = TMP_REG2; \ - } \ - else \ - src2 = 0; \ - } - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - struct sljit_jump *jump; - sljit_s32 flags; - sljit_ins inst; - - CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_cmp(compiler, type, src1, src1w, src2, src2w)); - ADJUST_LOCAL_OFFSET(src1, src1w); - ADJUST_LOCAL_OFFSET(src2, src2w); - - compiler->cache_arg = 0; - compiler->cache_argw = 0; -#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) - flags = WORD_DATA | LOAD_DATA; -#else /* !SLJIT_CONFIG_MIPS_32 */ - flags = ((type & SLJIT_32) ? INT_DATA : WORD_DATA) | LOAD_DATA; -#endif /* SLJIT_CONFIG_MIPS_32 */ - - if (src1 & SLJIT_MEM) { - PTR_FAIL_IF(emit_op_mem2(compiler, flags, DR(TMP_REG1), src1, src1w, src2, src2w)); - src1 = TMP_REG1; - } - - if (src2 & SLJIT_MEM) { - PTR_FAIL_IF(emit_op_mem2(compiler, flags, DR(TMP_REG2), src2, src2w, 0, 0)); - src2 = TMP_REG2; - } - - jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump)); - PTR_FAIL_IF(!jump); - set_jump(jump, compiler, type & SLJIT_REWRITABLE_JUMP); - type &= 0xff; - - if (type <= SLJIT_NOT_EQUAL) { - RESOLVE_IMM1(); - RESOLVE_IMM2(); - jump->flags |= IS_BIT26_COND; - if (compiler->delay_slot == MOVABLE_INS || (compiler->delay_slot != UNMOVABLE_INS && compiler->delay_slot != DR(src1) && compiler->delay_slot != DR(src2))) - jump->flags |= IS_MOVABLE; - PTR_FAIL_IF(push_inst(compiler, (type == SLJIT_EQUAL ? BNE : BEQ) | S(src1) | T(src2) | BRANCH_LENGTH, UNMOVABLE_INS)); - } - else if (type >= SLJIT_SIG_LESS && (((src1 & SLJIT_IMM) && (src1w == 0)) || ((src2 & SLJIT_IMM) && (src2w == 0)))) { - inst = NOP; - if ((src1 & SLJIT_IMM) && (src1w == 0)) { - RESOLVE_IMM2(); - switch (type) { - case SLJIT_SIG_LESS: - inst = BLEZ; - jump->flags |= IS_BIT26_COND; - break; - case SLJIT_SIG_GREATER_EQUAL: - inst = BGTZ; - jump->flags |= IS_BIT26_COND; - break; - case SLJIT_SIG_GREATER: - inst = BGEZ; - jump->flags |= IS_BIT16_COND; - break; - case SLJIT_SIG_LESS_EQUAL: - inst = BLTZ; - jump->flags |= IS_BIT16_COND; - break; - } - src1 = src2; - } - else { - RESOLVE_IMM1(); - switch (type) { - case SLJIT_SIG_LESS: - inst = BGEZ; - jump->flags |= IS_BIT16_COND; - break; - case SLJIT_SIG_GREATER_EQUAL: - inst = BLTZ; - jump->flags |= IS_BIT16_COND; - break; - case SLJIT_SIG_GREATER: - inst = BLEZ; - jump->flags |= IS_BIT26_COND; - break; - case SLJIT_SIG_LESS_EQUAL: - inst = BGTZ; - jump->flags |= IS_BIT26_COND; - break; - } - } - PTR_FAIL_IF(push_inst(compiler, inst | S(src1) | BRANCH_LENGTH, UNMOVABLE_INS)); - } - else { - if (type == SLJIT_LESS || type == SLJIT_GREATER_EQUAL || type == SLJIT_SIG_LESS || type == SLJIT_SIG_GREATER_EQUAL) { - RESOLVE_IMM1(); - if ((src2 & SLJIT_IMM) && src2w <= SIMM_MAX && src2w >= SIMM_MIN) - PTR_FAIL_IF(push_inst(compiler, (type <= SLJIT_LESS_EQUAL ? SLTIU : SLTI) | S(src1) | T(TMP_REG1) | IMM(src2w), DR(TMP_REG1))); - else { - RESOLVE_IMM2(); - PTR_FAIL_IF(push_inst(compiler, (type <= SLJIT_LESS_EQUAL ? SLTU : SLT) | S(src1) | T(src2) | D(TMP_REG1), DR(TMP_REG1))); - } - type = (type == SLJIT_LESS || type == SLJIT_SIG_LESS) ? SLJIT_NOT_EQUAL : SLJIT_EQUAL; - } - else { - RESOLVE_IMM2(); - if ((src1 & SLJIT_IMM) && src1w <= SIMM_MAX && src1w >= SIMM_MIN) - PTR_FAIL_IF(push_inst(compiler, (type <= SLJIT_LESS_EQUAL ? SLTIU : SLTI) | S(src2) | T(TMP_REG1) | IMM(src1w), DR(TMP_REG1))); - else { - RESOLVE_IMM1(); - PTR_FAIL_IF(push_inst(compiler, (type <= SLJIT_LESS_EQUAL ? SLTU : SLT) | S(src2) | T(src1) | D(TMP_REG1), DR(TMP_REG1))); - } - type = (type == SLJIT_GREATER || type == SLJIT_SIG_GREATER) ? SLJIT_NOT_EQUAL : SLJIT_EQUAL; - } - - jump->flags |= IS_BIT26_COND; - 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)); - jump->addr = compiler->size; - PTR_FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS)); - - /* Maximum number of instructions required for generating a constant. */ -#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) - compiler->size += 2; -#else - compiler->size += 6; -#endif - return jump; -} - -#undef RESOLVE_IMM1 -#undef RESOLVE_IMM2 - -#undef BRANCH_LENGTH -#undef BR_Z -#undef BR_NZ -#undef BR_T -#undef BR_F - -#undef FLOAT_DATA -#undef FMT - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 src, sljit_sw srcw) -{ - struct sljit_jump *jump = NULL; - - CHECK_ERROR(); - CHECK(check_sljit_emit_ijump(compiler, type, src, srcw)); - - if (src & SLJIT_IMM) { - jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump)); - FAIL_IF(!jump); - set_jump(jump, compiler, JUMP_ADDR | ((type >= SLJIT_FAST_CALL) ? IS_JAL : 0)); - jump->u.target = (sljit_uw)srcw; - - if (compiler->delay_slot != UNMOVABLE_INS) - jump->flags |= IS_MOVABLE; - - src = TMP_REG2; - } 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; - } - - if (type <= SLJIT_JUMP) - FAIL_IF(push_inst(compiler, JR | S(src), UNMOVABLE_INS)); - else - FAIL_IF(push_inst(compiler, JALR | S(src) | DA(RETURN_ADDR_REG), UNMOVABLE_INS)); - - if (jump != NULL) { - jump->addr = compiler->size; - - /* Maximum number of instructions required for generating a constant. */ -#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) - compiler->size += 2; -#else - compiler->size += 6; -#endif - } - - FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS)); - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 type) -{ - sljit_s32 src_ar, dst_ar, invert; - sljit_s32 saved_op = op; -#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) - sljit_s32 mem_type = WORD_DATA; -#else - sljit_s32 mem_type = ((op & SLJIT_32) || op == SLJIT_MOV32) ? (INT_DATA | SIGNED_DATA) : WORD_DATA; -#endif - - CHECK_ERROR(); - CHECK(check_sljit_emit_op_flags(compiler, op, dst, dstw, type)); - ADJUST_LOCAL_OFFSET(dst, dstw); - - op = GET_OPCODE(op); - dst_ar = DR((op < SLJIT_ADD && FAST_IS_REG(dst)) ? dst : TMP_REG2); - - compiler->cache_arg = 0; - compiler->cache_argw = 0; - - if (op >= SLJIT_ADD && (dst & SLJIT_MEM)) - FAIL_IF(emit_op_mem2(compiler, mem_type | LOAD_DATA, DR(TMP_REG1), dst, dstw, dst, dstw)); - - if (type < SLJIT_F_EQUAL) { - src_ar = OTHER_FLAG; - invert = type & 0x1; - - switch (type) { - case SLJIT_EQUAL: - case SLJIT_NOT_EQUAL: - FAIL_IF(push_inst(compiler, SLTIU | SA(EQUAL_FLAG) | TA(dst_ar) | IMM(1), dst_ar)); - src_ar = dst_ar; - break; - case SLJIT_OVERFLOW: - case SLJIT_NOT_OVERFLOW: - if (compiler->status_flags_state & (SLJIT_CURRENT_FLAGS_ADD | SLJIT_CURRENT_FLAGS_SUB)) { - src_ar = OTHER_FLAG; - break; - } - FAIL_IF(push_inst(compiler, SLTIU | SA(OTHER_FLAG) | TA(dst_ar) | IMM(1), dst_ar)); - src_ar = dst_ar; - invert ^= 0x1; - break; - } - } else { - invert = 0; - - switch (type) { - case SLJIT_F_NOT_EQUAL: - case SLJIT_F_GREATER_EQUAL: - case SLJIT_F_GREATER: - case SLJIT_UNORDERED_OR_NOT_EQUAL: - case SLJIT_ORDERED_NOT_EQUAL: - case SLJIT_UNORDERED_OR_GREATER_EQUAL: - case SLJIT_ORDERED_GREATER_EQUAL: - case SLJIT_ORDERED_GREATER: - case SLJIT_UNORDERED_OR_GREATER: - case SLJIT_ORDERED: - invert = 1; - break; - } - -#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6) - FAIL_IF(push_inst(compiler, MFC1 | TA(dst_ar) | FS(TMP_FREG3), dst_ar)); -#else /* SLJIT_MIPS_REV < 6 */ - FAIL_IF(push_inst(compiler, CFC1 | TA(dst_ar) | DA(FCSR_REG), dst_ar)); -#endif /* SLJIT_MIPS_REV >= 6 */ - FAIL_IF(push_inst(compiler, SRL | TA(dst_ar) | DA(dst_ar) | SH_IMM(23), dst_ar)); - FAIL_IF(push_inst(compiler, ANDI | SA(dst_ar) | TA(dst_ar) | IMM(1), dst_ar)); - src_ar = dst_ar; - } - - if (invert) { - FAIL_IF(push_inst(compiler, XORI | SA(src_ar) | TA(dst_ar) | IMM(1), dst_ar)); - src_ar = dst_ar; - } - - if (op < SLJIT_ADD) { - if (dst & SLJIT_MEM) - return emit_op_mem(compiler, mem_type, src_ar, dst, dstw); - - if (src_ar != dst_ar) - return push_inst(compiler, ADDU_W | SA(src_ar) | TA(0) | DA(dst_ar), dst_ar); - return SLJIT_SUCCESS; - } - - /* OTHER_FLAG cannot be specified as src2 argument at the moment. */ - if (DR(TMP_REG2) != src_ar) - FAIL_IF(push_inst(compiler, ADDU_W | SA(src_ar) | TA(0) | D(TMP_REG2), DR(TMP_REG2))); - - mem_type |= CUMULATIVE_OP | LOGICAL_OP | IMM_OP | ALT_KEEP_CACHE; - - if (dst & SLJIT_MEM) - return emit_op(compiler, saved_op, mem_type, dst, dstw, TMP_REG1, 0, TMP_REG2, 0); - return emit_op(compiler, saved_op, mem_type, dst, dstw, dst, dstw, TMP_REG2, 0); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 dst_reg, - sljit_s32 src, sljit_sw srcw) -{ -#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1 && SLJIT_MIPS_REV < 6) - sljit_ins ins; -#endif /* SLJIT_MIPS_REV >= 1 && SLJIT_MIPS_REV < 6 */ - - CHECK_ERROR(); - CHECK(check_sljit_emit_cmov(compiler, type, dst_reg, src, srcw)); - -#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1 && SLJIT_MIPS_REV < 6) - - if (SLJIT_UNLIKELY(src & SLJIT_IMM)) { -#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) - if (type & SLJIT_32) - srcw = (sljit_s32)srcw; -#endif - FAIL_IF(load_immediate(compiler, DR(TMP_REG1), srcw)); - src = TMP_REG1; - srcw = 0; - } - - switch (type & ~SLJIT_32) { - case SLJIT_EQUAL: - ins = MOVZ | TA(EQUAL_FLAG); - break; - case SLJIT_NOT_EQUAL: - ins = MOVN | TA(EQUAL_FLAG); - break; - case SLJIT_LESS: - case SLJIT_GREATER: - case SLJIT_SIG_LESS: - case SLJIT_SIG_GREATER: - case SLJIT_OVERFLOW: - ins = MOVN | TA(OTHER_FLAG); - break; - case SLJIT_GREATER_EQUAL: - case SLJIT_LESS_EQUAL: - case SLJIT_SIG_GREATER_EQUAL: - case SLJIT_SIG_LESS_EQUAL: - case SLJIT_NOT_OVERFLOW: - ins = MOVZ | TA(OTHER_FLAG); - break; - case SLJIT_F_EQUAL: - case SLJIT_F_LESS: - case SLJIT_F_LESS_EQUAL: - case SLJIT_ORDERED_EQUAL: - case SLJIT_UNORDERED_OR_EQUAL: - case SLJIT_ORDERED_LESS: - case SLJIT_UNORDERED_OR_LESS: - case SLJIT_UNORDERED_OR_LESS_EQUAL: - case SLJIT_ORDERED_LESS_EQUAL: - case SLJIT_UNORDERED: - ins = MOVT; - break; - case SLJIT_F_NOT_EQUAL: - case SLJIT_F_GREATER_EQUAL: - case SLJIT_F_GREATER: - case SLJIT_UNORDERED_OR_NOT_EQUAL: - case SLJIT_ORDERED_NOT_EQUAL: - case SLJIT_UNORDERED_OR_GREATER_EQUAL: - case SLJIT_ORDERED_GREATER_EQUAL: - case SLJIT_ORDERED_GREATER: - case SLJIT_UNORDERED_OR_GREATER: - case SLJIT_ORDERED: - ins = MOVF; - break; - default: - ins = MOVZ | TA(OTHER_FLAG); - SLJIT_UNREACHABLE(); - break; - } - - return push_inst(compiler, ins | S(src) | D(dst_reg), DR(dst_reg)); - -#else /* SLJIT_MIPS_REV < 1 || SLJIT_MIPS_REV >= 6 */ - return sljit_emit_cmov_generic(compiler, type, dst_reg, src, srcw); -#endif /* SLJIT_MIPS_REV >= 1 */ -} - -static sljit_s32 update_mem_addr(struct sljit_compiler *compiler, sljit_s32 *mem, sljit_sw *memw, sljit_s16 max_offset) -{ - sljit_s32 arg = *mem; - sljit_sw argw = *memw; - - if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) { - argw &= 0x3; - - if (SLJIT_UNLIKELY(argw)) { - FAIL_IF(push_inst(compiler, SLL_W | T(OFFS_REG(arg)) | D(TMP_REG1) | SH_IMM(argw), DR(TMP_REG1))); - FAIL_IF(push_inst(compiler, ADDU_W | S(TMP_REG1) | T(arg & REG_MASK) | D(TMP_REG1), DR(TMP_REG1))); - } else - FAIL_IF(push_inst(compiler, ADDU_W | S(arg & REG_MASK) | T(OFFS_REG(arg)) | D(TMP_REG1), DR(TMP_REG1))); - - *mem = TMP_REG1; - *memw = 0; - - return SLJIT_SUCCESS; - } - - if (argw <= max_offset && argw >= SIMM_MIN) { - *mem = arg & REG_MASK; - return SLJIT_SUCCESS; - } - - *mem = TMP_REG1; - - if ((sljit_s16)argw > max_offset) { - FAIL_IF(load_immediate(compiler, DR(TMP_REG1), argw)); - *memw = 0; - } else { - FAIL_IF(load_immediate(compiler, DR(TMP_REG1), TO_ARGW_HI(argw))); - *memw = (sljit_s16)argw; - } - - if ((arg & REG_MASK) == 0) - return SLJIT_SUCCESS; - - return push_inst(compiler, ADDU_W | S(TMP_REG1) | T(arg & REG_MASK) | D(TMP_REG1), DR(TMP_REG1)); -} - -#if (defined SLJIT_LITTLE_ENDIAN && SLJIT_LITTLE_ENDIAN) -#define MEM16_IMM_FIRST(memw) IMM((memw) + 1) -#define MEM16_IMM_SECOND(memw) IMM(memw) -#define MEMF64_FS_FIRST(freg) FS(freg) -#define MEMF64_FS_SECOND(freg) (FS(freg) | ((sljit_ins)1 << 11)) -#else /* !SLJIT_LITTLE_ENDIAN */ -#define MEM16_IMM_FIRST(memw) IMM(memw) -#define MEM16_IMM_SECOND(memw) IMM((memw) + 1) -#define MEMF64_FS_FIRST(freg) (FS(freg) | ((sljit_ins)1 << 11)) -#define MEMF64_FS_SECOND(freg) FS(freg) -#endif /* SLJIT_LITTLE_ENDIAN */ - -#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) -#define MEM_CHECK_UNALIGNED(type) ((type) & (SLJIT_MEM_UNALIGNED | SLJIT_MEM_UNALIGNED_16)) -#else /* !SLJIT_CONFIG_MIPS_32 */ -#define MEM_CHECK_UNALIGNED(type) ((type) & (SLJIT_MEM_UNALIGNED | SLJIT_MEM_UNALIGNED_16 | SLJIT_MEM_UNALIGNED_32)) -#endif /* SLJIT_CONFIG_MIPS_32 */ - -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) -{ - sljit_s32 op = type & 0xff; - sljit_s32 flags = 0; - sljit_ins ins; -#if !(defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6) - sljit_ins ins_right; -#endif /* !(SLJIT_MIPS_REV >= 6) */ - - CHECK_ERROR(); - CHECK(check_sljit_emit_mem(compiler, type, reg, mem, memw)); - - if (reg & REG_PAIR_MASK) { - ADJUST_LOCAL_OFFSET(mem, memw); - -#if !(defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6) - if (MEM_CHECK_UNALIGNED(type)) { - FAIL_IF(update_mem_addr(compiler, &mem, &memw, SIMM_MAX - (2 * SSIZE_OF(sw) - 1))); - - if (!(type & SLJIT_MEM_STORE) && (mem == REG_PAIR_FIRST(reg) || mem == REG_PAIR_SECOND(reg))) { - FAIL_IF(push_inst(compiler, ADDU_W | S(mem) | TA(0) | D(TMP_REG1), DR(TMP_REG1))); - mem = TMP_REG1; - } - -#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) - ins = ((type & SLJIT_MEM_STORE) ? SWL : LWL) | S(mem); - ins_right = ((type & SLJIT_MEM_STORE) ? SWR : LWR) | S(mem); -#else /* !SLJIT_CONFIG_MIPS_32 */ - ins = ((type & SLJIT_MEM_STORE) ? SDL : LDL) | S(mem); - ins_right = ((type & SLJIT_MEM_STORE) ? SDR : LDR) | S(mem); -#endif /* SLJIT_CONFIG_MIPS_32 */ - - FAIL_IF(push_inst(compiler, ins | T(REG_PAIR_FIRST(reg)) | IMM(memw), DR(REG_PAIR_FIRST(reg)))); - FAIL_IF(push_inst(compiler, ins_right | T(REG_PAIR_FIRST(reg)) | IMM(memw + (SSIZE_OF(sw) - 1)), DR(REG_PAIR_FIRST(reg)))); - FAIL_IF(push_inst(compiler, ins | T(REG_PAIR_SECOND(reg)) | IMM(memw + SSIZE_OF(sw)), DR(REG_PAIR_SECOND(reg)))); - return push_inst(compiler, ins_right | T(REG_PAIR_SECOND(reg)) | IMM((memw + 2 * SSIZE_OF(sw) - 1)), DR(REG_PAIR_SECOND(reg))); - } -#endif /* !(SLJIT_MIPS_REV >= 6) */ - - FAIL_IF(update_mem_addr(compiler, &mem, &memw, SIMM_MAX - SSIZE_OF(sw))); - - ins = ((type & SLJIT_MEM_STORE) ? STORE_W : LOAD_W) | S(mem); - - if (!(type & SLJIT_MEM_STORE) && mem == REG_PAIR_FIRST(reg)) { - FAIL_IF(push_inst(compiler, ins | T(REG_PAIR_SECOND(reg)) | IMM(memw + SSIZE_OF(sw)), DR(REG_PAIR_SECOND(reg)))); - return push_inst(compiler, ins | T(REG_PAIR_FIRST(reg)) | IMM(memw), DR(REG_PAIR_FIRST(reg))); - } - - FAIL_IF(push_inst(compiler, ins | T(REG_PAIR_FIRST(reg)) | IMM(memw), DR(REG_PAIR_FIRST(reg)))); - return push_inst(compiler, ins | T(REG_PAIR_SECOND(reg)) | IMM(memw + SSIZE_OF(sw)), DR(REG_PAIR_SECOND(reg))); - } - -#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6) - return sljit_emit_mem_unaligned(compiler, type, reg, mem, memw); -#else /* !(SLJIT_MIPS_REV >= 6) */ - ADJUST_LOCAL_OFFSET(mem, memw); - - switch (op) { - case SLJIT_MOV_U8: - case SLJIT_MOV_S8: - flags = BYTE_DATA; - if (!(type & SLJIT_MEM_STORE)) - flags |= LOAD_DATA; - - if (op == SLJIT_MOV_S8) - flags |= SIGNED_DATA; - - return emit_op_mem(compiler, flags, DR(reg), mem, memw); - - case SLJIT_MOV_U16: - case SLJIT_MOV_S16: - FAIL_IF(update_mem_addr(compiler, &mem, &memw, SIMM_MAX - 1)); - SLJIT_ASSERT(FAST_IS_REG(mem) && mem != TMP_REG2); - - if (type & SLJIT_MEM_STORE) { - FAIL_IF(push_inst(compiler, SRA_W | T(reg) | D(TMP_REG2) | SH_IMM(8), DR(TMP_REG2))); - FAIL_IF(push_inst(compiler, data_transfer_insts[BYTE_DATA] | S(mem) | T(TMP_REG2) | MEM16_IMM_FIRST(memw), MOVABLE_INS)); - return push_inst(compiler, data_transfer_insts[BYTE_DATA] | S(mem) | T(reg) | MEM16_IMM_SECOND(memw), MOVABLE_INS); - } - - flags = BYTE_DATA | LOAD_DATA; - - if (op == SLJIT_MOV_S16) - flags |= SIGNED_DATA; - - FAIL_IF(push_inst(compiler, data_transfer_insts[flags] | S(mem) | T(TMP_REG2) | MEM16_IMM_FIRST(memw), DR(TMP_REG2))); - FAIL_IF(push_inst(compiler, data_transfer_insts[BYTE_DATA | LOAD_DATA] | S(mem) | T(reg) | MEM16_IMM_SECOND(memw), DR(reg))); - FAIL_IF(push_inst(compiler, SLL_W | T(TMP_REG2) | D(TMP_REG2) | SH_IMM(8), DR(TMP_REG2))); - return push_inst(compiler, OR | S(reg) | T(TMP_REG2) | D(reg), DR(reg)); - - case SLJIT_MOV: - case SLJIT_MOV_P: -#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) - if (type & SLJIT_MEM_UNALIGNED_32) { - flags = WORD_DATA; - if (!(type & SLJIT_MEM_STORE)) - flags |= LOAD_DATA; - - return emit_op_mem(compiler, flags, DR(reg), mem, memw); - } -#else /* !SLJIT_CONFIG_MIPS_32 */ - FAIL_IF(update_mem_addr(compiler, &mem, &memw, SIMM_MAX - 7)); - SLJIT_ASSERT(FAST_IS_REG(mem) && mem != TMP_REG2); - - if (type & SLJIT_MEM_STORE) { - FAIL_IF(push_inst(compiler, SDL | S(mem) | T(reg) | IMM(memw), MOVABLE_INS)); - return push_inst(compiler, SDR | S(mem) | T(reg) | IMM(memw + 7), MOVABLE_INS); - } - - if (mem == reg) { - FAIL_IF(push_inst(compiler, ADDU_W | S(mem) | TA(0) | D(TMP_REG1), DR(TMP_REG1))); - mem = TMP_REG1; - } - - FAIL_IF(push_inst(compiler, LDL | S(mem) | T(reg) | IMM(memw), DR(reg))); - return push_inst(compiler, LDR | S(mem) | T(reg) | IMM(memw + 7), DR(reg)); -#endif /* SLJIT_CONFIG_MIPS_32 */ - } - - FAIL_IF(update_mem_addr(compiler, &mem, &memw, SIMM_MAX - 3)); - SLJIT_ASSERT(FAST_IS_REG(mem) && mem != TMP_REG2); - - if (type & SLJIT_MEM_STORE) { - FAIL_IF(push_inst(compiler, SWL | S(mem) | T(reg) | IMM(memw), MOVABLE_INS)); - return push_inst(compiler, SWR | S(mem) | T(reg) | IMM(memw + 3), MOVABLE_INS); - } - - if (mem == reg) { - FAIL_IF(push_inst(compiler, ADDU_W | S(mem) | TA(0) | D(TMP_REG1), DR(TMP_REG1))); - mem = TMP_REG1; - } - - FAIL_IF(push_inst(compiler, LWL | S(mem) | T(reg) | IMM(memw), DR(reg))); -#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) - return push_inst(compiler, LWR | S(mem) | T(reg) | IMM(memw + 3), DR(reg)); -#else /* !SLJIT_CONFIG_MIPS_32 */ - FAIL_IF(push_inst(compiler, LWR | S(mem) | T(reg) | IMM(memw + 3), DR(reg))); - - if (op != SLJIT_MOV_U32) - return SLJIT_SUCCESS; - -#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 2) - return push_inst(compiler, DINSU | T(reg) | SA(0) | (31 << 11) | (0 << 11), DR(reg)); -#else /* SLJIT_MIPS_REV < 1 */ - FAIL_IF(push_inst(compiler, DSLL32 | T(reg) | D(reg) | SH_IMM(0), DR(reg))); - return push_inst(compiler, DSRL32 | T(reg) | D(reg) | SH_IMM(0), DR(reg)); -#endif /* SLJIT_MIPS_REV >= 2 */ -#endif /* SLJIT_CONFIG_MIPS_32 */ -#endif /* SLJIT_MIPS_REV >= 6 */ -} - -#if !(defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6) - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fmem(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 freg, - sljit_s32 mem, sljit_sw memw) -{ - CHECK_ERROR(); - CHECK(check_sljit_emit_fmem(compiler, type, freg, mem, memw)); - - FAIL_IF(update_mem_addr(compiler, &mem, &memw, SIMM_MAX - (type & SLJIT_32) ? 3 : 7)); - SLJIT_ASSERT(FAST_IS_REG(mem) && mem != TMP_REG2); - - if (type & SLJIT_MEM_STORE) { - if (type & SLJIT_32) { - FAIL_IF(push_inst(compiler, MFC1 | T(TMP_REG2) | FS(freg), DR(TMP_REG2))); -#if (!defined SLJIT_MIPS_REV || SLJIT_MIPS_REV <= 3) - FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS)); -#endif - FAIL_IF(push_inst(compiler, SWL | S(mem) | T(TMP_REG2) | IMM(memw), MOVABLE_INS)); - return push_inst(compiler, SWR | S(mem) | T(TMP_REG2) | IMM(memw + 3), MOVABLE_INS); - } - -#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) - FAIL_IF(push_inst(compiler, MFC1 | T(TMP_REG2) | MEMF64_FS_FIRST(freg), DR(TMP_REG2))); -#if (!defined SLJIT_MIPS_REV || SLJIT_MIPS_REV <= 3) - FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS)); -#endif - FAIL_IF(push_inst(compiler, SWL | S(mem) | T(TMP_REG2) | IMM(memw), MOVABLE_INS)); - FAIL_IF(push_inst(compiler, SWR | S(mem) | T(TMP_REG2) | IMM(memw + 3), MOVABLE_INS)); - - FAIL_IF(push_inst(compiler, MFC1 | T(TMP_REG2) | MEMF64_FS_SECOND(freg), DR(TMP_REG2))); -#if (!defined SLJIT_MIPS_REV || SLJIT_MIPS_REV <= 3) - FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS)); -#endif - FAIL_IF(push_inst(compiler, SWL | S(mem) | T(TMP_REG2) | IMM(memw + 4), MOVABLE_INS)); - return push_inst(compiler, SWR | S(mem) | T(TMP_REG2) | IMM(memw + 7), MOVABLE_INS); -#else /* !SLJIT_CONFIG_MIPS_32 */ - FAIL_IF(push_inst(compiler, MFC1 | (1 << 21) | T(TMP_REG2) | FS(freg), DR(TMP_REG2))); -#if (!defined SLJIT_MIPS_REV || SLJIT_MIPS_REV <= 3) - FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS)); -#endif - FAIL_IF(push_inst(compiler, SDL | S(mem) | T(TMP_REG2) | IMM(memw), MOVABLE_INS)); - return push_inst(compiler, SDR | S(mem) | T(TMP_REG2) | IMM(memw + 7), MOVABLE_INS); -#endif /* SLJIT_CONFIG_MIPS_32 */ - } - - if (type & SLJIT_32) { - FAIL_IF(push_inst(compiler, LWL | S(mem) | T(TMP_REG2) | IMM(memw), DR(TMP_REG2))); - FAIL_IF(push_inst(compiler, LWR | S(mem) | T(TMP_REG2) | IMM(memw + 3), DR(TMP_REG2))); - - FAIL_IF(push_inst(compiler, MTC1 | T(TMP_REG2) | FS(freg), MOVABLE_INS)); -#if (!defined SLJIT_MIPS_REV || SLJIT_MIPS_REV <= 3) - FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS)); -#endif - return SLJIT_SUCCESS; - } - -#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) - FAIL_IF(push_inst(compiler, LWL | S(mem) | T(TMP_REG2) | IMM(memw), DR(TMP_REG2))); - FAIL_IF(push_inst(compiler, LWR | S(mem) | T(TMP_REG2) | IMM(memw + 3), DR(TMP_REG2))); - FAIL_IF(push_inst(compiler, MTC1 | T(TMP_REG2) | MEMF64_FS_FIRST(freg), MOVABLE_INS)); - - FAIL_IF(push_inst(compiler, LWL | S(mem) | T(TMP_REG2) | IMM(memw + 4), DR(TMP_REG2))); - FAIL_IF(push_inst(compiler, LWR | S(mem) | T(TMP_REG2) | IMM(memw + 7), DR(TMP_REG2))); - FAIL_IF(push_inst(compiler, MTC1 | T(TMP_REG2) | MEMF64_FS_SECOND(freg), MOVABLE_INS)); -#if (!defined SLJIT_MIPS_REV || SLJIT_MIPS_REV <= 3) - FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS)); -#endif -#else /* !SLJIT_CONFIG_MIPS_32 */ - FAIL_IF(push_inst(compiler, LDL | S(mem) | T(TMP_REG2) | IMM(memw), DR(TMP_REG2))); - FAIL_IF(push_inst(compiler, LDR | S(mem) | T(TMP_REG2) | IMM(memw + 7), DR(TMP_REG2))); - - FAIL_IF(push_inst(compiler, MTC1 | (1 << 21) | T(TMP_REG2) | FS(freg), MOVABLE_INS)); -#if (!defined SLJIT_MIPS_REV || SLJIT_MIPS_REV <= 3) - FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS)); -#endif -#endif /* SLJIT_CONFIG_MIPS_32 */ - return SLJIT_SUCCESS; -} - -#endif /* !SLJIT_MIPS_REV || SLJIT_MIPS_REV < 6 */ - -#undef MEM16_IMM_FIRST -#undef MEM16_IMM_SECOND -#undef MEMF64_FS_FIRST -#undef MEMF64_FS_SECOND -#undef MEM_CHECK_UNALIGNED - -#undef TO_ARGW_HI - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value) -{ - struct sljit_const *const_; - sljit_s32 dst_r; - - CHECK_ERROR_PTR(); - 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; - PTR_FAIL_IF(emit_const(compiler, dst_r, init_value)); - - if (dst & SLJIT_MEM) - PTR_FAIL_IF(emit_op_mem(compiler, WORD_DATA, DR(TMP_REG2), dst, dstw)); - - return const_; -} - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label* sljit_emit_put_label(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw) -{ - struct sljit_put_label *put_label; - sljit_s32 dst_r; - - CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_put_label(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); - - dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2; - PTR_FAIL_IF(push_inst(compiler, (sljit_ins)dst_r, UNMOVABLE_INS)); -#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) - compiler->size += 1; -#else - compiler->size += 5; -#endif - - if (dst & SLJIT_MEM) - PTR_FAIL_IF(emit_op_mem(compiler, WORD_DATA, DR(TMP_REG2), dst, dstw)); - - return put_label; -} diff --git a/modules/regex/pcre2/src/sljit/sljitNativePPC_32.c b/modules/regex/pcre2/src/sljit/sljitNativePPC_32.c deleted file mode 100644 index 9449e4b..0000000 --- a/modules/regex/pcre2/src/sljit/sljitNativePPC_32.c +++ /dev/null @@ -1,340 +0,0 @@ -/* - * 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. - */ - -/* ppc 32-bit arch dependent functions. */ - -static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 reg, sljit_sw imm) -{ - if (imm <= SIMM_MAX && imm >= SIMM_MIN) - return push_inst(compiler, ADDI | D(reg) | A(0) | IMM(imm)); - - if (!(imm & ~0xffff)) - return push_inst(compiler, ORI | S(TMP_ZERO) | A(reg) | IMM(imm)); - - FAIL_IF(push_inst(compiler, ADDIS | D(reg) | A(0) | IMM(imm >> 16))); - return (imm & 0xffff) ? push_inst(compiler, ORI | S(reg) | A(reg) | IMM(imm)) : SLJIT_SUCCESS; -} - -/* Simplified mnemonics: clrlwi. */ -#define INS_CLEAR_LEFT(dst, src, from) \ - (RLWINM | S(src) | A(dst) | RLWI_MBE(from, 31)) - -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_s32 src2) -{ - sljit_u32 imm; - - switch (op) { - case SLJIT_MOV: - case SLJIT_MOV_U32: - case SLJIT_MOV_S32: - case SLJIT_MOV_P: - SLJIT_ASSERT(src1 == TMP_REG1); - if (dst != src2) - return push_inst(compiler, OR | S(src2) | A(dst) | B(src2)); - return SLJIT_SUCCESS; - - case SLJIT_MOV_U8: - case SLJIT_MOV_S8: - SLJIT_ASSERT(src1 == TMP_REG1); - if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) { - if (op == SLJIT_MOV_S8) - return push_inst(compiler, EXTSB | S(src2) | A(dst)); - return push_inst(compiler, INS_CLEAR_LEFT(dst, src2, 24)); - } - else if ((flags & REG_DEST) && op == SLJIT_MOV_S8) - return push_inst(compiler, EXTSB | S(src2) | A(dst)); - else { - SLJIT_ASSERT(dst == src2); - } - return SLJIT_SUCCESS; - - case SLJIT_MOV_U16: - case SLJIT_MOV_S16: - SLJIT_ASSERT(src1 == TMP_REG1); - if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) { - if (op == SLJIT_MOV_S16) - return push_inst(compiler, EXTSH | S(src2) | A(dst)); - return push_inst(compiler, INS_CLEAR_LEFT(dst, src2, 16)); - } - else { - SLJIT_ASSERT(dst == src2); - } - return SLJIT_SUCCESS; - - case SLJIT_NOT: - SLJIT_ASSERT(src1 == TMP_REG1); - return push_inst(compiler, NOR | RC(flags) | S(src2) | A(dst) | B(src2)); - - case SLJIT_CLZ: - SLJIT_ASSERT(src1 == TMP_REG1); - return push_inst(compiler, CNTLZW | S(src2) | A(dst)); - - case SLJIT_CTZ: - SLJIT_ASSERT(src1 == TMP_REG1); - FAIL_IF(push_inst(compiler, NEG | D(TMP_REG1) | A(src2))); - FAIL_IF(push_inst(compiler, AND | S(src2) | A(dst) | B(TMP_REG1))); - FAIL_IF(push_inst(compiler, CNTLZW | S(dst) | A(dst))); - FAIL_IF(push_inst(compiler, ADDI | D(TMP_REG1) | A(dst) | IMM(-32))); - /* The highest bits are set, if dst < 32, zero otherwise. */ - FAIL_IF(push_inst(compiler, SRWI(27) | S(TMP_REG1) | A(TMP_REG1))); - return push_inst(compiler, XOR | S(dst) | A(dst) | B(TMP_REG1)); - - case SLJIT_ADD: - if (flags & ALT_FORM1) { - /* Setting XER SO is not enough, CR SO is also needed. */ - return push_inst(compiler, ADD | OE(ALT_SET_FLAGS) | RC(ALT_SET_FLAGS) | D(dst) | A(src1) | B(src2)); - } - - if (flags & ALT_FORM2) { - /* Flags does not set: BIN_IMM_EXTS unnecessary. */ - SLJIT_ASSERT(src2 == TMP_REG2); - - if (flags & ALT_FORM3) - return push_inst(compiler, ADDIS | D(dst) | A(src1) | compiler->imm); - - imm = compiler->imm; - - if (flags & ALT_FORM4) { - FAIL_IF(push_inst(compiler, ADDIS | D(dst) | A(src1) | (((imm >> 16) & 0xffff) + ((imm >> 15) & 0x1)))); - src1 = dst; - } - - return push_inst(compiler, ADDI | D(dst) | A(src1) | (imm & 0xffff)); - } - if (flags & ALT_FORM3) { - SLJIT_ASSERT(src2 == TMP_REG2); - return push_inst(compiler, ADDIC | D(dst) | A(src1) | compiler->imm); - } - SLJIT_ASSERT(!(flags & ALT_FORM4)); - if (!(flags & ALT_SET_FLAGS)) - return push_inst(compiler, ADD | D(dst) | A(src1) | B(src2)); - if (flags & ALT_FORM5) - return push_inst(compiler, ADDC | RC(ALT_SET_FLAGS) | D(dst) | A(src1) | B(src2)); - return push_inst(compiler, ADD | RC(flags) | D(dst) | A(src1) | B(src2)); - - case SLJIT_ADDC: - return push_inst(compiler, ADDE | D(dst) | A(src1) | B(src2)); - - case SLJIT_SUB: - if (flags & ALT_FORM1) { - if (flags & ALT_FORM2) { - FAIL_IF(push_inst(compiler, CMPLI | CRD(0) | A(src1) | compiler->imm)); - if (!(flags & ALT_FORM3)) - return SLJIT_SUCCESS; - return push_inst(compiler, ADDI | D(dst) | A(src1) | (-compiler->imm & 0xffff)); - } - FAIL_IF(push_inst(compiler, CMPL | CRD(0) | A(src1) | B(src2))); - if (!(flags & ALT_FORM3)) - return SLJIT_SUCCESS; - return push_inst(compiler, SUBF | D(dst) | A(src2) | B(src1)); - } - - if (flags & ALT_FORM2) { - if (flags & ALT_FORM3) { - FAIL_IF(push_inst(compiler, CMPI | CRD(0) | A(src1) | compiler->imm)); - if (!(flags & ALT_FORM4)) - return SLJIT_SUCCESS; - return push_inst(compiler, ADDI | D(dst) | A(src1) | (-compiler->imm & 0xffff)); - } - FAIL_IF(push_inst(compiler, CMP | CRD(0) | A(src1) | B(src2))); - if (!(flags & ALT_FORM4)) - return SLJIT_SUCCESS; - return push_inst(compiler, SUBF | D(dst) | A(src2) | B(src1)); - } - - if (flags & ALT_FORM3) { - /* Setting XER SO is not enough, CR SO is also needed. */ - if (src1 != TMP_ZERO) - return push_inst(compiler, SUBF | OE(ALT_SET_FLAGS) | RC(ALT_SET_FLAGS) | D(dst) | A(src2) | B(src1)); - return push_inst(compiler, NEG | OE(ALT_SET_FLAGS) | RC(ALT_SET_FLAGS) | D(dst) | A(src2)); - } - - if (flags & ALT_FORM4) { - /* Flags does not set: BIN_IMM_EXTS unnecessary. */ - SLJIT_ASSERT(src2 == TMP_REG2); - return push_inst(compiler, SUBFIC | D(dst) | A(src1) | compiler->imm); - } - - if (!(flags & ALT_SET_FLAGS)) { - SLJIT_ASSERT(src1 != TMP_ZERO); - return push_inst(compiler, SUBF | D(dst) | A(src2) | B(src1)); - } - - if (flags & ALT_FORM5) - return push_inst(compiler, SUBFC | RC(ALT_SET_FLAGS) | D(dst) | A(src2) | B(src1)); - - if (src1 != TMP_ZERO) - return push_inst(compiler, SUBF | RC(ALT_SET_FLAGS) | D(dst) | A(src2) | B(src1)); - return push_inst(compiler, NEG | RC(ALT_SET_FLAGS) | D(dst) | A(src2)); - - case SLJIT_SUBC: - return push_inst(compiler, SUBFE | D(dst) | A(src2) | B(src1)); - - case SLJIT_MUL: - if (flags & ALT_FORM1) { - SLJIT_ASSERT(src2 == TMP_REG2); - return push_inst(compiler, MULLI | D(dst) | A(src1) | compiler->imm); - } - return push_inst(compiler, MULLW | OE(flags) | RC(flags) | D(dst) | A(src2) | B(src1)); - - case SLJIT_AND: - if (flags & ALT_FORM1) { - SLJIT_ASSERT(src2 == TMP_REG2); - return push_inst(compiler, ANDI | S(src1) | A(dst) | compiler->imm); - } - if (flags & ALT_FORM2) { - SLJIT_ASSERT(src2 == TMP_REG2); - return push_inst(compiler, ANDIS | S(src1) | A(dst) | compiler->imm); - } - return push_inst(compiler, AND | RC(flags) | S(src1) | A(dst) | B(src2)); - - case SLJIT_OR: - if (flags & ALT_FORM1) { - SLJIT_ASSERT(src2 == TMP_REG2); - return push_inst(compiler, ORI | S(src1) | A(dst) | compiler->imm); - } - if (flags & ALT_FORM2) { - SLJIT_ASSERT(src2 == TMP_REG2); - return push_inst(compiler, ORIS | S(src1) | A(dst) | compiler->imm); - } - if (flags & ALT_FORM3) { - SLJIT_ASSERT(src2 == TMP_REG2); - imm = compiler->imm; - - FAIL_IF(push_inst(compiler, ORI | S(src1) | A(dst) | IMM(imm))); - return push_inst(compiler, ORIS | S(dst) | A(dst) | IMM(imm >> 16)); - } - return push_inst(compiler, OR | RC(flags) | S(src1) | A(dst) | B(src2)); - - case SLJIT_XOR: - if (flags & ALT_FORM1) { - SLJIT_ASSERT(src2 == TMP_REG2); - return push_inst(compiler, XORI | S(src1) | A(dst) | compiler->imm); - } - if (flags & ALT_FORM2) { - SLJIT_ASSERT(src2 == TMP_REG2); - return push_inst(compiler, XORIS | S(src1) | A(dst) | compiler->imm); - } - if (flags & ALT_FORM3) { - SLJIT_ASSERT(src2 == TMP_REG2); - imm = compiler->imm; - - FAIL_IF(push_inst(compiler, XORI | S(src1) | A(dst) | IMM(imm))); - return push_inst(compiler, XORIS | S(dst) | A(dst) | IMM(imm >> 16)); - } - return push_inst(compiler, XOR | RC(flags) | S(src1) | A(dst) | B(src2)); - - case SLJIT_SHL: - case SLJIT_MSHL: - if (flags & ALT_FORM1) { - SLJIT_ASSERT(src2 == TMP_REG2); - imm = compiler->imm & 0x1f; - return push_inst(compiler, SLWI(imm) | RC(flags) | S(src1) | A(dst)); - } - - if (op == SLJIT_MSHL) { - FAIL_IF(push_inst(compiler, ANDI | S(src2) | A(TMP_REG2) | 0x1f)); - src2 = TMP_REG2; - } - - return push_inst(compiler, SLW | RC(flags) | S(src1) | A(dst) | B(src2)); - - case SLJIT_LSHR: - case SLJIT_MLSHR: - if (flags & ALT_FORM1) { - SLJIT_ASSERT(src2 == TMP_REG2); - imm = compiler->imm & 0x1f; - /* Since imm can be 0, SRWI() cannot be used. */ - return push_inst(compiler, RLWINM | RC(flags) | S(src1) | A(dst) | RLWI_SH((32 - imm) & 0x1f) | RLWI_MBE(imm, 31)); - } - - if (op == SLJIT_MLSHR) { - FAIL_IF(push_inst(compiler, ANDI | S(src2) | A(TMP_REG2) | 0x1f)); - src2 = TMP_REG2; - } - - return push_inst(compiler, SRW | RC(flags) | S(src1) | A(dst) | B(src2)); - - case SLJIT_ASHR: - case SLJIT_MASHR: - if (flags & ALT_FORM1) { - SLJIT_ASSERT(src2 == TMP_REG2); - imm = compiler->imm & 0x1f; - return push_inst(compiler, SRAWI | RC(flags) | S(src1) | A(dst) | (imm << 11)); - } - - if (op == SLJIT_MASHR) { - FAIL_IF(push_inst(compiler, ANDI | S(src2) | A(TMP_REG2) | 0x1f)); - src2 = TMP_REG2; - } - - return push_inst(compiler, SRAW | RC(flags) | S(src1) | A(dst) | B(src2)); - - case SLJIT_ROTL: - case SLJIT_ROTR: - if (flags & ALT_FORM1) { - SLJIT_ASSERT(src2 == TMP_REG2); - imm = compiler->imm; - - if (op == SLJIT_ROTR) - imm = (sljit_u32)(-(sljit_s32)imm); - - imm &= 0x1f; - return push_inst(compiler, RLWINM | S(src1) | A(dst) | RLWI_SH(imm) | RLWI_MBE(0, 31)); - } - - if (op == SLJIT_ROTR) { - FAIL_IF(push_inst(compiler, SUBFIC | D(TMP_REG2) | A(src2) | 0)); - src2 = TMP_REG2; - } - - return push_inst(compiler, RLWNM | S(src1) | A(dst) | B(src2) | RLWI_MBE(0, 31)); - } - - SLJIT_UNREACHABLE(); - return SLJIT_SUCCESS; -} - -static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 reg, sljit_sw init_value) -{ - FAIL_IF(push_inst(compiler, ADDIS | D(reg) | A(0) | IMM(init_value >> 16))); - return push_inst(compiler, ORI | S(reg) | A(reg) | IMM(init_value)); -} - -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset) -{ - sljit_ins *inst = (sljit_ins *)addr; - SLJIT_UNUSED_ARG(executable_offset); - - SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 0); - SLJIT_ASSERT((inst[0] & 0xfc1f0000) == ADDIS && (inst[1] & 0xfc000000) == ORI); - inst[0] = (inst[0] & 0xffff0000) | ((new_target >> 16) & 0xffff); - inst[1] = (inst[1] & 0xffff0000) | (new_target & 0xffff); - SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 1); - inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset); - SLJIT_CACHE_FLUSH(inst, inst + 2); -} diff --git a/modules/regex/pcre2/src/sljit/sljitNativePPC_64.c b/modules/regex/pcre2/src/sljit/sljitNativePPC_64.c deleted file mode 100644 index 8054910..0000000 --- a/modules/regex/pcre2/src/sljit/sljitNativePPC_64.c +++ /dev/null @@ -1,579 +0,0 @@ -/* - * 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. - */ - -/* ppc 64-bit arch dependent functions. */ - -#if defined(__GNUC__) || (defined(__IBM_GCC_ASM) && __IBM_GCC_ASM) -#define ASM_SLJIT_CLZ(src, dst) \ - __asm__ volatile ( "cntlzd %0, %1" : "=r"(dst) : "r"(src) ) -#elif defined(__xlc__) -#error "Please enable GCC syntax for inline assembly statements" -#else -#error "Must implement count leading zeroes" -#endif - -/* Computes SLDI(63 - shift). */ -#define PUSH_SLDI_NEG(reg, shift) \ - push_inst(compiler, RLDICR | S(reg) | A(reg) | RLDI_SH(63 - shift) | RLDI_ME(shift)) - -static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 reg, sljit_sw imm) -{ - sljit_uw tmp; - sljit_uw shift; - sljit_uw tmp2; - sljit_uw shift2; - - if (imm <= SIMM_MAX && imm >= SIMM_MIN) - return push_inst(compiler, ADDI | D(reg) | A(0) | IMM(imm)); - - if (!(imm & ~0xffff)) - return push_inst(compiler, ORI | S(TMP_ZERO) | A(reg) | IMM(imm)); - - if (imm <= 0x7fffffffl && imm >= -0x80000000l) { - FAIL_IF(push_inst(compiler, ADDIS | D(reg) | A(0) | IMM(imm >> 16))); - return (imm & 0xffff) ? push_inst(compiler, ORI | S(reg) | A(reg) | IMM(imm)) : SLJIT_SUCCESS; - } - - /* Count leading zeroes. */ - tmp = (sljit_uw)((imm >= 0) ? imm : ~imm); - ASM_SLJIT_CLZ(tmp, shift); - SLJIT_ASSERT(shift > 0); - shift--; - tmp = ((sljit_uw)imm << shift); - - if ((tmp & ~0xffff000000000000ul) == 0) { - FAIL_IF(push_inst(compiler, ADDI | D(reg) | A(0) | (sljit_ins)(tmp >> 48))); - shift += 15; - return PUSH_SLDI_NEG(reg, shift); - } - - if ((tmp & ~0xffffffff00000000ul) == 0) { - FAIL_IF(push_inst(compiler, ADDIS | D(reg) | A(0) | (sljit_ins)(tmp >> 48))); - FAIL_IF(push_inst(compiler, ORI | S(reg) | A(reg) | IMM(tmp >> 32))); - shift += 31; - return PUSH_SLDI_NEG(reg, shift); - } - - /* Cut out the 16 bit from immediate. */ - shift += 15; - tmp2 = (sljit_uw)imm & (((sljit_uw)1 << (63 - shift)) - 1); - - if (tmp2 <= 0xffff) { - FAIL_IF(push_inst(compiler, ADDI | D(reg) | A(0) | (sljit_ins)(tmp >> 48))); - FAIL_IF(PUSH_SLDI_NEG(reg, shift)); - return push_inst(compiler, ORI | S(reg) | A(reg) | (sljit_ins)tmp2); - } - - if (tmp2 <= 0xffffffff) { - FAIL_IF(push_inst(compiler, ADDI | D(reg) | A(0) | IMM(tmp >> 48))); - FAIL_IF(PUSH_SLDI_NEG(reg, shift)); - FAIL_IF(push_inst(compiler, ORIS | S(reg) | A(reg) | (sljit_ins)(tmp2 >> 16))); - return (imm & 0xffff) ? push_inst(compiler, ORI | S(reg) | A(reg) | IMM(tmp2)) : SLJIT_SUCCESS; - } - - ASM_SLJIT_CLZ(tmp2, shift2); - tmp2 <<= shift2; - - if ((tmp2 & ~0xffff000000000000ul) == 0) { - FAIL_IF(push_inst(compiler, ADDI | D(reg) | A(0) | (sljit_ins)(tmp >> 48))); - shift2 += 15; - shift += (63 - shift2); - FAIL_IF(PUSH_SLDI_NEG(reg, shift)); - FAIL_IF(push_inst(compiler, ORI | S(reg) | A(reg) | (sljit_ins)(tmp2 >> 48))); - return PUSH_SLDI_NEG(reg, shift2); - } - - /* The general version. */ - FAIL_IF(push_inst(compiler, ADDIS | D(reg) | A(0) | (sljit_ins)((sljit_uw)imm >> 48))); - FAIL_IF(push_inst(compiler, ORI | S(reg) | A(reg) | IMM(imm >> 32))); - FAIL_IF(PUSH_SLDI_NEG(reg, 31)); - FAIL_IF(push_inst(compiler, ORIS | S(reg) | A(reg) | IMM(imm >> 16))); - return push_inst(compiler, ORI | S(reg) | A(reg) | IMM(imm)); -} - -#undef PUSH_SLDI_NEG - -#define CLRLDI(dst, src, n) \ - (RLDICL | S(src) | A(dst) | RLDI_SH(0) | RLDI_MB(n)) - -/* Sign extension for integer operations. */ -#define UN_EXTS() \ - if ((flags & (ALT_SIGN_EXT | REG2_SOURCE)) == (ALT_SIGN_EXT | REG2_SOURCE)) { \ - FAIL_IF(push_inst(compiler, EXTSW | S(src2) | A(TMP_REG2))); \ - src2 = TMP_REG2; \ - } - -#define BIN_EXTS() \ - if (flags & ALT_SIGN_EXT) { \ - if (flags & REG1_SOURCE) { \ - FAIL_IF(push_inst(compiler, EXTSW | S(src1) | A(TMP_REG1))); \ - src1 = TMP_REG1; \ - } \ - if (flags & REG2_SOURCE) { \ - FAIL_IF(push_inst(compiler, EXTSW | S(src2) | A(TMP_REG2))); \ - src2 = TMP_REG2; \ - } \ - } - -#define BIN_IMM_EXTS() \ - if ((flags & (ALT_SIGN_EXT | REG1_SOURCE)) == (ALT_SIGN_EXT | REG1_SOURCE)) { \ - FAIL_IF(push_inst(compiler, EXTSW | S(src1) | A(TMP_REG1))); \ - src1 = TMP_REG1; \ - } - -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_s32 src2) -{ - sljit_u32 imm; - - switch (op) { - case SLJIT_MOV: - case SLJIT_MOV_P: - SLJIT_ASSERT(src1 == TMP_REG1); - if (dst != src2) - return push_inst(compiler, OR | S(src2) | A(dst) | B(src2)); - return SLJIT_SUCCESS; - - case SLJIT_MOV_U32: - case SLJIT_MOV_S32: - SLJIT_ASSERT(src1 == TMP_REG1); - if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) { - if (op == SLJIT_MOV_S32) - return push_inst(compiler, EXTSW | S(src2) | A(dst)); - return push_inst(compiler, CLRLDI(dst, src2, 32)); - } - else { - SLJIT_ASSERT(dst == src2); - } - return SLJIT_SUCCESS; - - case SLJIT_MOV_U8: - case SLJIT_MOV_S8: - SLJIT_ASSERT(src1 == TMP_REG1); - if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) { - if (op == SLJIT_MOV_S8) - return push_inst(compiler, EXTSB | S(src2) | A(dst)); - return push_inst(compiler, CLRLDI(dst, src2, 56)); - } - else if ((flags & REG_DEST) && op == SLJIT_MOV_S8) - return push_inst(compiler, EXTSB | S(src2) | A(dst)); - else { - SLJIT_ASSERT(dst == src2); - } - return SLJIT_SUCCESS; - - case SLJIT_MOV_U16: - case SLJIT_MOV_S16: - SLJIT_ASSERT(src1 == TMP_REG1); - if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) { - if (op == SLJIT_MOV_S16) - return push_inst(compiler, EXTSH | S(src2) | A(dst)); - return push_inst(compiler, CLRLDI(dst, src2, 48)); - } - else { - SLJIT_ASSERT(dst == src2); - } - return SLJIT_SUCCESS; - - case SLJIT_NOT: - SLJIT_ASSERT(src1 == TMP_REG1); - UN_EXTS(); - return push_inst(compiler, NOR | RC(flags) | S(src2) | A(dst) | B(src2)); - - case SLJIT_CLZ: - SLJIT_ASSERT(src1 == TMP_REG1); - return push_inst(compiler, ((flags & ALT_FORM1) ? CNTLZW : CNTLZD) | S(src2) | A(dst)); - - case SLJIT_CTZ: - SLJIT_ASSERT(src1 == TMP_REG1); - FAIL_IF(push_inst(compiler, NEG | D(TMP_REG1) | A(src2))); - FAIL_IF(push_inst(compiler, AND | S(src2) | A(dst) | B(TMP_REG1))); - FAIL_IF(push_inst(compiler, ((flags & ALT_FORM1) ? CNTLZW : CNTLZD) | S(dst) | A(dst))); - FAIL_IF(push_inst(compiler, ADDI | D(TMP_REG1) | A(dst) | IMM((flags & ALT_FORM1) ? -32 : -64))); - /* The highest bits are set, if dst < bit width, zero otherwise. */ - FAIL_IF(push_inst(compiler, ((flags & ALT_FORM1) ? SRWI(27) : SRDI(58)) | S(TMP_REG1) | A(TMP_REG1))); - return push_inst(compiler, XOR | S(dst) | A(dst) | B(TMP_REG1)); - - case SLJIT_ADD: - if (flags & ALT_FORM1) { - if (flags & ALT_SIGN_EXT) { - FAIL_IF(push_inst(compiler, SLDI(32) | S(src1) | A(TMP_REG1))); - src1 = TMP_REG1; - FAIL_IF(push_inst(compiler, SLDI(32) | S(src2) | A(TMP_REG2))); - src2 = TMP_REG2; - } - /* Setting XER SO is not enough, CR SO is also needed. */ - FAIL_IF(push_inst(compiler, ADD | OE(ALT_SET_FLAGS) | RC(ALT_SET_FLAGS) | D(dst) | A(src1) | B(src2))); - if (flags & ALT_SIGN_EXT) - return push_inst(compiler, SRDI(32) | S(dst) | A(dst)); - return SLJIT_SUCCESS; - } - - if (flags & ALT_FORM2) { - /* Flags does not set: BIN_IMM_EXTS unnecessary. */ - SLJIT_ASSERT(src2 == TMP_REG2); - - if (flags & ALT_FORM3) - return push_inst(compiler, ADDIS | D(dst) | A(src1) | compiler->imm); - - imm = compiler->imm; - - if (flags & ALT_FORM4) { - FAIL_IF(push_inst(compiler, ADDIS | D(dst) | A(src1) | (((imm >> 16) & 0xffff) + ((imm >> 15) & 0x1)))); - src1 = dst; - } - - return push_inst(compiler, ADDI | D(dst) | A(src1) | (imm & 0xffff)); - } - if (flags & ALT_FORM3) { - SLJIT_ASSERT(src2 == TMP_REG2); - BIN_IMM_EXTS(); - return push_inst(compiler, ADDIC | D(dst) | A(src1) | compiler->imm); - } - if (flags & ALT_FORM4) { - if (flags & ALT_FORM5) - FAIL_IF(push_inst(compiler, ADDI | D(dst) | A(src1) | compiler->imm)); - else - FAIL_IF(push_inst(compiler, ADD | D(dst) | A(src1) | B(src2))); - return push_inst(compiler, CMPI | A(dst) | 0); - } - if (!(flags & ALT_SET_FLAGS)) - return push_inst(compiler, ADD | D(dst) | A(src1) | B(src2)); - BIN_EXTS(); - if (flags & ALT_FORM5) - return push_inst(compiler, ADDC | RC(ALT_SET_FLAGS) | D(dst) | A(src1) | B(src2)); - return push_inst(compiler, ADD | RC(flags) | D(dst) | A(src1) | B(src2)); - - case SLJIT_ADDC: - BIN_EXTS(); - return push_inst(compiler, ADDE | D(dst) | A(src1) | B(src2)); - - case SLJIT_SUB: - if (flags & ALT_FORM1) { - if (flags & ALT_FORM2) { - FAIL_IF(push_inst(compiler, CMPLI | CRD(0 | ((flags & ALT_SIGN_EXT) ? 0 : 1)) | A(src1) | compiler->imm)); - if (!(flags & ALT_FORM3)) - return SLJIT_SUCCESS; - return push_inst(compiler, ADDI | D(dst) | A(src1) | (-compiler->imm & 0xffff)); - } - FAIL_IF(push_inst(compiler, CMPL | CRD(0 | ((flags & ALT_SIGN_EXT) ? 0 : 1)) | A(src1) | B(src2))); - if (!(flags & ALT_FORM3)) - return SLJIT_SUCCESS; - return push_inst(compiler, SUBF | D(dst) | A(src2) | B(src1)); - } - - if (flags & ALT_FORM2) { - if (flags & ALT_FORM3) { - FAIL_IF(push_inst(compiler, CMPI | CRD(0 | ((flags & ALT_SIGN_EXT) ? 0 : 1)) | A(src1) | compiler->imm)); - if (!(flags & ALT_FORM4)) - return SLJIT_SUCCESS; - return push_inst(compiler, ADDI | D(dst) | A(src1) | (-compiler->imm & 0xffff)); - } - FAIL_IF(push_inst(compiler, CMP | CRD(0 | ((flags & ALT_SIGN_EXT) ? 0 : 1)) | A(src1) | B(src2))); - if (!(flags & ALT_FORM4)) - return SLJIT_SUCCESS; - return push_inst(compiler, SUBF | D(dst) | A(src2) | B(src1)); - } - - if (flags & ALT_FORM3) { - if (flags & ALT_SIGN_EXT) { - if (src1 != TMP_ZERO) { - FAIL_IF(push_inst(compiler, SLDI(32) | S(src1) | A(TMP_REG1))); - src1 = TMP_REG1; - } - if (src2 != TMP_ZERO) { - FAIL_IF(push_inst(compiler, SLDI(32) | S(src2) | A(TMP_REG2))); - src2 = TMP_REG2; - } - } - - /* Setting XER SO is not enough, CR SO is also needed. */ - if (src1 != TMP_ZERO) - FAIL_IF(push_inst(compiler, SUBF | OE(ALT_SET_FLAGS) | RC(ALT_SET_FLAGS) | D(dst) | A(src2) | B(src1))); - else - FAIL_IF(push_inst(compiler, NEG | OE(ALT_SET_FLAGS) | RC(ALT_SET_FLAGS) | D(dst) | A(src2))); - - if (flags & ALT_SIGN_EXT) - return push_inst(compiler, SRDI(32) | S(dst) | A(dst)); - return SLJIT_SUCCESS; - } - - if (flags & ALT_FORM4) { - /* Flags does not set: BIN_IMM_EXTS unnecessary. */ - SLJIT_ASSERT(src2 == TMP_REG2); - return push_inst(compiler, SUBFIC | D(dst) | A(src1) | compiler->imm); - } - - if (!(flags & ALT_SET_FLAGS)) { - SLJIT_ASSERT(src1 != TMP_ZERO); - return push_inst(compiler, SUBF | D(dst) | A(src2) | B(src1)); - } - - BIN_EXTS(); - if (flags & ALT_FORM5) - return push_inst(compiler, SUBFC | RC(ALT_SET_FLAGS) | D(dst) | A(src2) | B(src1)); - - if (src1 != TMP_ZERO) - return push_inst(compiler, SUBF | RC(ALT_SET_FLAGS) | D(dst) | A(src2) | B(src1)); - return push_inst(compiler, NEG | RC(ALT_SET_FLAGS) | D(dst) | A(src2)); - - case SLJIT_SUBC: - BIN_EXTS(); - return push_inst(compiler, SUBFE | D(dst) | A(src2) | B(src1)); - - case SLJIT_MUL: - if (flags & ALT_FORM1) { - SLJIT_ASSERT(src2 == TMP_REG2); - return push_inst(compiler, MULLI | D(dst) | A(src1) | compiler->imm); - } - BIN_EXTS(); - if (flags & ALT_FORM2) - return push_inst(compiler, MULLW | OE(flags) | RC(flags) | D(dst) | A(src2) | B(src1)); - return push_inst(compiler, MULLD | OE(flags) | RC(flags) | D(dst) | A(src2) | B(src1)); - - case SLJIT_AND: - if (flags & ALT_FORM1) { - SLJIT_ASSERT(src2 == TMP_REG2); - return push_inst(compiler, ANDI | S(src1) | A(dst) | compiler->imm); - } - if (flags & ALT_FORM2) { - SLJIT_ASSERT(src2 == TMP_REG2); - return push_inst(compiler, ANDIS | S(src1) | A(dst) | compiler->imm); - } - return push_inst(compiler, AND | RC(flags) | S(src1) | A(dst) | B(src2)); - - case SLJIT_OR: - if (flags & ALT_FORM1) { - SLJIT_ASSERT(src2 == TMP_REG2); - return push_inst(compiler, ORI | S(src1) | A(dst) | compiler->imm); - } - if (flags & ALT_FORM2) { - SLJIT_ASSERT(src2 == TMP_REG2); - return push_inst(compiler, ORIS | S(src1) | A(dst) | compiler->imm); - } - if (flags & ALT_FORM3) { - SLJIT_ASSERT(src2 == TMP_REG2); - imm = compiler->imm; - - FAIL_IF(push_inst(compiler, ORI | S(src1) | A(dst) | IMM(imm))); - return push_inst(compiler, ORIS | S(dst) | A(dst) | IMM(imm >> 16)); - } - return push_inst(compiler, OR | RC(flags) | S(src1) | A(dst) | B(src2)); - - case SLJIT_XOR: - if (flags & ALT_FORM1) { - SLJIT_ASSERT(src2 == TMP_REG2); - return push_inst(compiler, XORI | S(src1) | A(dst) | compiler->imm); - } - if (flags & ALT_FORM2) { - SLJIT_ASSERT(src2 == TMP_REG2); - return push_inst(compiler, XORIS | S(src1) | A(dst) | compiler->imm); - } - if (flags & ALT_FORM3) { - SLJIT_ASSERT(src2 == TMP_REG2); - imm = compiler->imm; - - FAIL_IF(push_inst(compiler, XORI | S(src1) | A(dst) | IMM(imm))); - return push_inst(compiler, XORIS | S(dst) | A(dst) | IMM(imm >> 16)); - } - return push_inst(compiler, XOR | RC(flags) | S(src1) | A(dst) | B(src2)); - - case SLJIT_SHL: - case SLJIT_MSHL: - if (flags & ALT_FORM1) { - SLJIT_ASSERT(src2 == TMP_REG2); - imm = compiler->imm; - - if (flags & ALT_FORM2) { - imm &= 0x1f; - return push_inst(compiler, SLWI(imm) | RC(flags) | S(src1) | A(dst)); - } - - imm &= 0x3f; - return push_inst(compiler, SLDI(imm) | RC(flags) | S(src1) | A(dst)); - } - - if (op == SLJIT_MSHL) { - FAIL_IF(push_inst(compiler, ANDI | S(src2) | A(TMP_REG2) | ((flags & ALT_FORM2) ? 0x1f : 0x3f))); - src2 = TMP_REG2; - } - - return push_inst(compiler, ((flags & ALT_FORM2) ? SLW : SLD) | RC(flags) | S(src1) | A(dst) | B(src2)); - - case SLJIT_LSHR: - case SLJIT_MLSHR: - if (flags & ALT_FORM1) { - SLJIT_ASSERT(src2 == TMP_REG2); - imm = compiler->imm; - - if (flags & ALT_FORM2) { - imm &= 0x1f; - /* Since imm can be 0, SRWI() cannot be used. */ - return push_inst(compiler, RLWINM | RC(flags) | S(src1) | A(dst) | RLWI_SH((32 - imm) & 0x1f) | RLWI_MBE(imm, 31)); - } - - imm &= 0x3f; - /* Since imm can be 0, SRDI() cannot be used. */ - return push_inst(compiler, RLDICL | RC(flags) | S(src1) | A(dst) | RLDI_SH((64 - imm) & 0x3f) | RLDI_MB(imm)); - } - - if (op == SLJIT_MLSHR) { - FAIL_IF(push_inst(compiler, ANDI | S(src2) | A(TMP_REG2) | ((flags & ALT_FORM2) ? 0x1f : 0x3f))); - src2 = TMP_REG2; - } - - return push_inst(compiler, ((flags & ALT_FORM2) ? SRW : SRD) | RC(flags) | S(src1) | A(dst) | B(src2)); - - case SLJIT_ASHR: - case SLJIT_MASHR: - if (flags & ALT_FORM1) { - SLJIT_ASSERT(src2 == TMP_REG2); - imm = compiler->imm; - - if (flags & ALT_FORM2) { - imm &= 0x1f; - return push_inst(compiler, SRAWI | RC(flags) | S(src1) | A(dst) | (imm << 11)); - } - - imm &= 0x3f; - return push_inst(compiler, SRADI | RC(flags) | S(src1) | A(dst) | RLDI_SH(imm)); - } - - if (op == SLJIT_MASHR) { - FAIL_IF(push_inst(compiler, ANDI | S(src2) | A(TMP_REG2) | ((flags & ALT_FORM2) ? 0x1f : 0x3f))); - src2 = TMP_REG2; - } - - return push_inst(compiler, ((flags & ALT_FORM2) ? SRAW : SRAD) | RC(flags) | S(src1) | A(dst) | B(src2)); - - case SLJIT_ROTL: - case SLJIT_ROTR: - if (flags & ALT_FORM1) { - SLJIT_ASSERT(src2 == TMP_REG2); - imm = compiler->imm; - - if (op == SLJIT_ROTR) - imm = (sljit_u32)(-(sljit_s32)imm); - - if (flags & ALT_FORM2) { - imm &= 0x1f; - return push_inst(compiler, RLWINM | S(src1) | A(dst) | RLWI_SH(imm) | RLWI_MBE(0, 31)); - } - - imm &= 0x3f; - return push_inst(compiler, RLDICL | S(src1) | A(dst) | RLDI_SH(imm)); - } - - if (op == SLJIT_ROTR) { - FAIL_IF(push_inst(compiler, SUBFIC | D(TMP_REG2) | A(src2) | 0)); - src2 = TMP_REG2; - } - - return push_inst(compiler, ((flags & ALT_FORM2) ? (RLWNM | RLWI_MBE(0, 31)) : (RLDCL | RLDI_MB(0))) | S(src1) | A(dst) | B(src2)); - } - - SLJIT_UNREACHABLE(); - return SLJIT_SUCCESS; -} - -static sljit_s32 call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_types, sljit_s32 *src) -{ - sljit_s32 arg_count = 0; - sljit_s32 word_arg_count = 0; - sljit_s32 types = 0; - sljit_s32 reg = 0; - - if (src) - reg = *src & REG_MASK; - - arg_types >>= SLJIT_ARG_SHIFT; - - while (arg_types) { - types = (types << SLJIT_ARG_SHIFT) | (arg_types & SLJIT_ARG_MASK); - - switch (arg_types & SLJIT_ARG_MASK) { - case SLJIT_ARG_TYPE_F64: - case SLJIT_ARG_TYPE_F32: - arg_count++; - break; - default: - arg_count++; - word_arg_count++; - - if (arg_count != word_arg_count && arg_count == reg) { - FAIL_IF(push_inst(compiler, OR | S(reg) | A(TMP_CALL_REG) | B(reg))); - *src = TMP_CALL_REG; - } - break; - } - - arg_types >>= SLJIT_ARG_SHIFT; - } - - while (types) { - switch (types & SLJIT_ARG_MASK) { - case SLJIT_ARG_TYPE_F64: - case SLJIT_ARG_TYPE_F32: - arg_count--; - break; - default: - if (arg_count != word_arg_count) - FAIL_IF(push_inst(compiler, OR | S(word_arg_count) | A(arg_count) | B(word_arg_count))); - - arg_count--; - word_arg_count--; - break; - } - - types >>= SLJIT_ARG_SHIFT; - } - - return SLJIT_SUCCESS; -} - -static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 reg, sljit_sw init_value) -{ - FAIL_IF(push_inst(compiler, ADDIS | D(reg) | A(0) | IMM(init_value >> 48))); - FAIL_IF(push_inst(compiler, ORI | S(reg) | A(reg) | IMM(init_value >> 32))); - FAIL_IF(push_inst(compiler, SLDI(32) | S(reg) | A(reg))); - FAIL_IF(push_inst(compiler, ORIS | S(reg) | A(reg) | IMM(init_value >> 16))); - return push_inst(compiler, ORI | S(reg) | A(reg) | IMM(init_value)); -} - -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset) -{ - sljit_ins *inst = (sljit_ins*)addr; - SLJIT_UNUSED_ARG(executable_offset); - - SLJIT_UPDATE_WX_FLAGS(inst, inst + 5, 0); - inst[0] = (inst[0] & 0xffff0000u) | ((sljit_ins)(new_target >> 48) & 0xffff); - inst[1] = (inst[1] & 0xffff0000u) | ((sljit_ins)(new_target >> 32) & 0xffff); - inst[3] = (inst[3] & 0xffff0000u) | ((sljit_ins)(new_target >> 16) & 0xffff); - inst[4] = (inst[4] & 0xffff0000u) | ((sljit_ins)new_target & 0xffff); - SLJIT_UPDATE_WX_FLAGS(inst, inst + 5, 1); - inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset); - SLJIT_CACHE_FLUSH(inst, inst + 5); -} diff --git a/modules/regex/pcre2/src/sljit/sljitNativePPC_common.c b/modules/regex/pcre2/src/sljit/sljitNativePPC_common.c deleted file mode 100644 index f387114..0000000 --- a/modules/regex/pcre2/src/sljit/sljitNativePPC_common.c +++ /dev/null @@ -1,2851 +0,0 @@ -/* - * 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 const char* sljit_get_platform_name(void) -{ - return "PowerPC" SLJIT_CPUINFO; -} - -/* Length of an instruction word. - Both for ppc-32 and ppc-64. */ -typedef sljit_u32 sljit_ins; - -#if ((defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) && (defined _AIX)) \ - || (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) -#define SLJIT_PPC_STACK_FRAME_V2 1 -#endif - -#ifdef _AIX -#include -#endif - -#if (defined _CALL_ELF && _CALL_ELF == 2) -#define SLJIT_PASS_ENTRY_ADDR_TO_CALL 1 -#endif - -#if (defined SLJIT_CACHE_FLUSH_OWN_IMPL && SLJIT_CACHE_FLUSH_OWN_IMPL) - -static void ppc_cache_flush(sljit_ins *from, sljit_ins *to) -{ -#ifdef _AIX - _sync_cache_range((caddr_t)from, (int)((size_t)to - (size_t)from)); -#elif defined(__GNUC__) || (defined(__IBM_GCC_ASM) && __IBM_GCC_ASM) -# if defined(_ARCH_PWR) || defined(_ARCH_PWR2) - /* Cache flush for POWER architecture. */ - while (from < to) { - __asm__ volatile ( - "clf 0, %0\n" - "dcs\n" - : : "r"(from) - ); - from++; - } - __asm__ volatile ( "ics" ); -# elif defined(_ARCH_COM) && !defined(_ARCH_PPC) -# error "Cache flush is not implemented for PowerPC/POWER common mode." -# else - /* Cache flush for PowerPC architecture. */ - while (from < to) { - __asm__ volatile ( - "dcbf 0, %0\n" - "sync\n" - "icbi 0, %0\n" - : : "r"(from) - ); - from++; - } - __asm__ volatile ( "isync" ); -# endif -# ifdef __xlc__ -# warning "This file may fail to compile if -qfuncsect is used" -# endif -#elif defined(__xlc__) -#error "Please enable GCC syntax for inline assembly statements with -qasm=gcc" -#else -#error "This platform requires a cache flush implementation." -#endif /* _AIX */ -} - -#endif /* (defined SLJIT_CACHE_FLUSH_OWN_IMPL && SLJIT_CACHE_FLUSH_OWN_IMPL) */ - -#define TMP_REG1 (SLJIT_NUMBER_OF_REGISTERS + 2) -#define TMP_REG2 (SLJIT_NUMBER_OF_REGISTERS + 3) -#define TMP_ZERO (SLJIT_NUMBER_OF_REGISTERS + 4) - -#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 -#endif - -#define TMP_FREG1 (SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1) -#define TMP_FREG2 (SLJIT_NUMBER_OF_FLOAT_REGISTERS + 2) - -static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 7] = { - 0, 3, 4, 5, 6, 7, 8, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 1, 9, 10, 31, 12 -}; - -static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 3] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 0, 13 -}; - -/* --------------------------------------------------------------------- */ -/* Instrucion forms */ -/* --------------------------------------------------------------------- */ -#define D(d) ((sljit_ins)reg_map[d] << 21) -#define S(s) ((sljit_ins)reg_map[s] << 21) -#define A(a) ((sljit_ins)reg_map[a] << 16) -#define B(b) ((sljit_ins)reg_map[b] << 11) -#define C(c) ((sljit_ins)reg_map[c] << 6) -#define FD(fd) ((sljit_ins)freg_map[fd] << 21) -#define FS(fs) ((sljit_ins)freg_map[fs] << 21) -#define FA(fa) ((sljit_ins)freg_map[fa] << 16) -#define FB(fb) ((sljit_ins)freg_map[fb] << 11) -#define FC(fc) ((sljit_ins)freg_map[fc] << 6) -#define IMM(imm) ((sljit_ins)(imm) & 0xffff) -#define CRD(d) ((sljit_ins)(d) << 21) - -/* Instruction bit sections. - OE and Rc flag (see ALT_SET_FLAGS). */ -#define OE(flags) ((flags) & ALT_SET_FLAGS) -/* Rc flag (see ALT_SET_FLAGS). */ -#define RC(flags) (((flags) & ALT_SET_FLAGS) >> 10) -#define HI(opcode) ((sljit_ins)(opcode) << 26) -#define LO(opcode) ((sljit_ins)(opcode) << 1) - -#define ADD (HI(31) | LO(266)) -#define ADDC (HI(31) | LO(10)) -#define ADDE (HI(31) | LO(138)) -#define ADDI (HI(14)) -#define ADDIC (HI(13)) -#define ADDIS (HI(15)) -#define ADDME (HI(31) | LO(234)) -#define AND (HI(31) | LO(28)) -#define ANDI (HI(28)) -#define ANDIS (HI(29)) -#define Bx (HI(18)) -#define BCx (HI(16)) -#define BCCTR (HI(19) | LO(528) | (3 << 11)) -#define BLR (HI(19) | LO(16) | (0x14 << 21)) -#define CNTLZD (HI(31) | LO(58)) -#define CNTLZW (HI(31) | LO(26)) -#define CMP (HI(31) | LO(0)) -#define CMPI (HI(11)) -#define CMPL (HI(31) | LO(32)) -#define CMPLI (HI(10)) -#define CROR (HI(19) | LO(449)) -#define DCBT (HI(31) | LO(278)) -#define DIVD (HI(31) | LO(489)) -#define DIVDU (HI(31) | LO(457)) -#define DIVW (HI(31) | LO(491)) -#define DIVWU (HI(31) | LO(459)) -#define EXTSB (HI(31) | LO(954)) -#define EXTSH (HI(31) | LO(922)) -#define EXTSW (HI(31) | LO(986)) -#define FABS (HI(63) | LO(264)) -#define FADD (HI(63) | LO(21)) -#define FADDS (HI(59) | LO(21)) -#define FCFID (HI(63) | LO(846)) -#define FCMPU (HI(63) | LO(0)) -#define FCTIDZ (HI(63) | LO(815)) -#define FCTIWZ (HI(63) | LO(15)) -#define FDIV (HI(63) | LO(18)) -#define FDIVS (HI(59) | LO(18)) -#define FMR (HI(63) | LO(72)) -#define FMUL (HI(63) | LO(25)) -#define FMULS (HI(59) | LO(25)) -#define FNEG (HI(63) | LO(40)) -#define FRSP (HI(63) | LO(12)) -#define FSUB (HI(63) | LO(20)) -#define FSUBS (HI(59) | LO(20)) -#define LD (HI(58) | 0) -#define LFD (HI(50)) -#define LWZ (HI(32)) -#define MFCR (HI(31) | LO(19)) -#define MFLR (HI(31) | LO(339) | 0x80000) -#define MFXER (HI(31) | LO(339) | 0x10000) -#define MTCTR (HI(31) | LO(467) | 0x90000) -#define MTLR (HI(31) | LO(467) | 0x80000) -#define MTXER (HI(31) | LO(467) | 0x10000) -#define MULHD (HI(31) | LO(73)) -#define MULHDU (HI(31) | LO(9)) -#define MULHW (HI(31) | LO(75)) -#define MULHWU (HI(31) | LO(11)) -#define MULLD (HI(31) | LO(233)) -#define MULLI (HI(7)) -#define MULLW (HI(31) | LO(235)) -#define NEG (HI(31) | LO(104)) -#define NOP (HI(24)) -#define NOR (HI(31) | LO(124)) -#define OR (HI(31) | LO(444)) -#define ORI (HI(24)) -#define ORIS (HI(25)) -#define RLDCL (HI(30) | LO(8)) -#define RLDICL (HI(30) | LO(0 << 1)) -#define RLDICR (HI(30) | LO(1 << 1)) -#define RLDIMI (HI(30) | LO(3 << 1)) -#define RLWIMI (HI(20)) -#define RLWINM (HI(21)) -#define RLWNM (HI(23)) -#define SLD (HI(31) | LO(27)) -#define SLW (HI(31) | LO(24)) -#define SRAD (HI(31) | LO(794)) -#define SRADI (HI(31) | LO(413 << 1)) -#define SRAW (HI(31) | LO(792)) -#define SRAWI (HI(31) | LO(824)) -#define SRD (HI(31) | LO(539)) -#define SRW (HI(31) | LO(536)) -#define STD (HI(62) | 0) -#define STDU (HI(62) | 1) -#define STDUX (HI(31) | LO(181)) -#define STFD (HI(54)) -#define STFIWX (HI(31) | LO(983)) -#define STW (HI(36)) -#define STWU (HI(37)) -#define STWUX (HI(31) | LO(183)) -#define SUBF (HI(31) | LO(40)) -#define SUBFC (HI(31) | LO(8)) -#define SUBFE (HI(31) | LO(136)) -#define SUBFIC (HI(8)) -#define XOR (HI(31) | LO(316)) -#define XORI (HI(26)) -#define XORIS (HI(27)) - -#define SIMM_MAX (0x7fff) -#define SIMM_MIN (-0x8000) -#define UIMM_MAX (0xffff) - -/* Shift helpers. */ -#define RLWI_SH(sh) ((sljit_ins)(sh) << 11) -#define RLWI_MBE(mb, me) (((sljit_ins)(mb) << 6) | ((sljit_ins)(me) << 1)) -#define RLDI_SH(sh) ((((sljit_ins)(sh) & 0x1f) << 11) | (((sljit_ins)(sh) & 0x20) >> 4)) -#define RLDI_MB(mb) ((((sljit_ins)(mb) & 0x1f) << 6) | ((sljit_ins)(mb) & 0x20)) -#define RLDI_ME(me) RLDI_MB(me) - -#define SLWI(shift) (RLWINM | RLWI_SH(shift) | RLWI_MBE(0, 31 - (shift))) -#define SLDI(shift) (RLDICR | RLDI_SH(shift) | RLDI_ME(63 - (shift))) -/* shift > 0 */ -#define SRWI(shift) (RLWINM | RLWI_SH(32 - (shift)) | RLWI_MBE((shift), 31)) -#define SRDI(shift) (RLDICL | RLDI_SH(64 - (shift)) | RLDI_MB(shift)) - -#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) -#define SLWI_W(shift) SLWI(shift) -#else /* !SLJIT_CONFIG_PPC_32 */ -#define SLWI_W(shift) SLDI(shift) -#endif /* SLJIT_CONFIG_PPC_32 */ - -#if (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL) -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_function_context(void** func_ptr, struct sljit_function_context* context, sljit_uw addr, void* func) -{ - sljit_uw* ptrs; - - if (func_ptr) - *func_ptr = (void*)context; - - ptrs = (sljit_uw*)func; - context->addr = addr ? addr : ptrs[0]; - context->r2 = ptrs[1]; - context->r11 = ptrs[2]; -} -#endif - -static sljit_s32 push_inst(struct sljit_compiler *compiler, sljit_ins ins) -{ - sljit_ins *ptr = (sljit_ins*)ensure_buf(compiler, sizeof(sljit_ins)); - FAIL_IF(!ptr); - *ptr = ins; - compiler->size++; - 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) -{ - 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; -#else - if (jump->flags & SLJIT_REWRITABLE_JUMP) - return 0; -#endif - - if (jump->flags & JUMP_ADDR) - target_addr = jump->u.target; - else { - SLJIT_ASSERT(jump->flags & JUMP_LABEL); - target_addr = (sljit_uw)(code + jump->u.label->size) + (sljit_uw)executable_offset; - } - -#if (defined SLJIT_PASS_ENTRY_ADDR_TO_CALL && SLJIT_PASS_ENTRY_ADDR_TO_CALL) && (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) - if (jump->flags & IS_CALL) - goto keep_address; -#endif - - diff = ((sljit_sw)target_addr - (sljit_sw)(code_ptr) - executable_offset) & ~0x3l; - - extra_jump_flags = 0; - if (jump->flags & IS_COND) { - if (diff <= 0x7fff && diff >= -0x8000) { - jump->flags |= PATCH_B; - return 1; - } - if (target_addr <= 0xffff) { - jump->flags |= PATCH_B | PATCH_ABS_B; - return 1; - } - extra_jump_flags = REMOVE_COND; - - diff -= SSIZE_OF(ins); - } - - if (diff <= 0x01ffffff && diff >= -0x02000000) { - jump->flags |= PATCH_B | extra_jump_flags; - return 1; - } - - if (target_addr <= 0x03ffffff) { - jump->flags |= PATCH_B | PATCH_ABS_B | extra_jump_flags; - return 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) { - jump->flags |= PATCH_ABS32; - return 1; - } - - if (target_addr <= 0x7fffffffffffl) { - jump->flags |= PATCH_ABS48; - return 1; - } -#endif - - return 0; -} - -#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) -{ - if (max_label < 0x100000000l) { - put_label->flags = 0; - return 1; - } - - if (max_label < 0x1000000000000l) { - put_label->flags = 1; - return 3; - } - - put_label->flags = 2; - 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; - - 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); - } - else { - inst[0] = ORIS | S(TMP_ZERO) | A(reg) | IMM(addr >> 48); - inst[1] = ORI | S(reg) | A(reg) | IMM((addr >> 32) & 0xffff); - inst++; - } - - inst[1] = SLDI(32) | S(reg) | A(reg); - inst[2] = ORIS | S(reg) | A(reg) | IMM((addr >> 16) & 0xffff); - inst += 2; - } - - inst[1] = ORI | S(reg) | A(reg) | IMM(addr & 0xffff); -} - -#endif /* SLJIT_CONFIG_PPC_64 */ - -SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler) -{ - struct sljit_memory_fragment *buf; - sljit_ins *code; - sljit_ins *code_ptr; - sljit_ins *buf_ptr; - sljit_ins *buf_end; - sljit_uw word_count; - sljit_uw next_addr; - 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); - -#if (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL) -#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) - compiler->size += (compiler->size & 0x1) + (sizeof(struct sljit_function_context) / sizeof(sljit_ins)); -#else - compiler->size += (sizeof(struct sljit_function_context) / sizeof(sljit_ins)); -#endif -#endif - code = (sljit_ins*)SLJIT_MALLOC_EXEC(compiler->size * sizeof(sljit_ins), compiler->exec_allocator_data); - 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; - - 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) { - 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) { - /* Just recording the address. */ - label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset); - label->size = (sljit_uw)(code_ptr - code); - label = label->next; - } - 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; - } - } - jump = jump->next; - } - if (const_ && const_->addr == word_count) { - const_->addr = (sljit_uw)code_ptr; - const_ = const_->next; - } - 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); - } - code_ptr++; - word_count++; - } while (buf_ptr < buf_end); - - buf = buf->next; - } while (buf); - - if (label && label->size == word_count) { - label->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_INDIRECT_CALL && SLJIT_INDIRECT_CALL) - SLJIT_ASSERT(code_ptr - code <= (sljit_sw)(compiler->size - (sizeof(struct sljit_function_context) / sizeof(sljit_ins)))); -#else - SLJIT_ASSERT(code_ptr - code <= (sljit_sw)compiler->size); -#endif - - 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); - 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; - compiler->executable_size = (sljit_uw)(code_ptr - code) * sizeof(sljit_ins); - - code = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(code, executable_offset); - -#if (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL) -#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) - if (((sljit_sw)code_ptr) & 0x4) - code_ptr++; -#endif - sljit_set_function_context(NULL, (struct sljit_function_context*)code_ptr, (sljit_uw)code, (void*)sljit_generate_code); -#endif - - code_ptr = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset); - - SLJIT_CACHE_FLUSH(code, code_ptr); - SLJIT_UPDATE_WX_FLAGS(code, code_ptr, 1); - -#if (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL) - return code_ptr; -#else - return code; -#endif -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type) -{ - switch (feature_type) { - case SLJIT_HAS_FPU: -#ifdef SLJIT_IS_FPU_AVAILABLE - return SLJIT_IS_FPU_AVAILABLE; -#else - /* Available by default. */ - return 1; -#endif - - /* A saved register is set to a zero value. */ - case SLJIT_HAS_ZERO_REGISTER: - case SLJIT_HAS_CLZ: - case SLJIT_HAS_ROT: - case SLJIT_HAS_PREFETCH: - return 1; - - case SLJIT_HAS_CTZ: - return 2; - - default: - return 0; - } -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_cmp_info(sljit_s32 type) -{ - return (type >= SLJIT_UNORDERED && type <= SLJIT_ORDERED_LESS_EQUAL); -} - -/* --------------------------------------------------------------------- */ -/* Entry, exit */ -/* --------------------------------------------------------------------- */ - -/* inp_flags: */ - -/* Creates an index in data_transfer_insts array. */ -#define LOAD_DATA 0x01 -#define INDEXED 0x02 -#define SIGNED_DATA 0x04 - -#define WORD_DATA 0x00 -#define BYTE_DATA 0x08 -#define HALF_DATA 0x10 -#define INT_DATA 0x18 -/* Separates integer and floating point registers */ -#define GPR_REG 0x1f -#define DOUBLE_DATA 0x20 - -#define MEM_MASK 0x7f - -/* Other inp_flags. */ - -/* Integer opertion and set flags -> requires exts on 64 bit systems. */ -#define ALT_SIGN_EXT 0x000100 -/* This flag affects the RC() and OERC() macros. */ -#define ALT_SET_FLAGS 0x000400 -#define ALT_FORM1 0x001000 -#define ALT_FORM2 0x002000 -#define ALT_FORM3 0x004000 -#define ALT_FORM4 0x008000 -#define ALT_FORM5 0x010000 - -/* Source and destination is register. */ -#define REG_DEST 0x000001 -#define REG1_SOURCE 0x000002 -#define REG2_SOURCE 0x000004 -/* -ALT_SIGN_EXT 0x000100 -ALT_SET_FLAGS 0x000200 -ALT_FORM1 0x001000 -... -ALT_FORM5 0x010000 */ - -#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) -#include "sljitNativePPC_32.c" -#else -#include "sljitNativePPC_64.c" -#endif - -#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) -#define STACK_STORE STW -#define STACK_LOAD LWZ -#else -#define STACK_STORE STD -#define STACK_LOAD LD -#endif - -#if (defined SLJIT_PPC_STACK_FRAME_V2 && SLJIT_PPC_STACK_FRAME_V2) -#define LR_SAVE_OFFSET 2 * SSIZE_OF(sw) -#else -#define LR_SAVE_OFFSET SSIZE_OF(sw) -#endif - -#define STACK_MAX_DISTANCE (0x8000 - SSIZE_OF(sw) - LR_SAVE_OFFSET) - -static sljit_s32 emit_op_mem(struct sljit_compiler *compiler, sljit_s32 inp_flags, sljit_s32 reg, - sljit_s32 arg, sljit_sw argw, sljit_s32 tmp_reg); - -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, - sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size) -{ - sljit_s32 i, tmp, base, offset; - sljit_s32 word_arg_count = 0; - sljit_s32 saved_arg_count = SLJIT_KEPT_SAVEDS_COUNT(options); -#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) - sljit_s32 arg_count = 0; -#endif - - CHECK_ERROR(); - CHECK(check_sljit_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size)); - set_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size); - - local_size += GET_SAVED_REGISTERS_SIZE(scratches, saveds - saved_arg_count, 0) - + GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, sizeof(sljit_f64)); - - if (!(options & SLJIT_ENTER_REG_ARG)) - local_size += SSIZE_OF(sw); - - local_size = (local_size + SLJIT_LOCALS_OFFSET + 15) & ~0xf; - compiler->local_size = local_size; - - FAIL_IF(push_inst(compiler, MFLR | D(0))); - - base = SLJIT_SP; - offset = local_size; - - if (local_size <= STACK_MAX_DISTANCE) { -#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) - FAIL_IF(push_inst(compiler, STWU | S(SLJIT_SP) | A(SLJIT_SP) | IMM(-local_size))); -#else - FAIL_IF(push_inst(compiler, STDU | S(SLJIT_SP) | A(SLJIT_SP) | IMM(-local_size))); -#endif - } else { - base = TMP_REG1; - FAIL_IF(push_inst(compiler, OR | S(SLJIT_SP) | A(TMP_REG1) | B(SLJIT_SP))); - FAIL_IF(load_immediate(compiler, TMP_REG2, -local_size)); -#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) - FAIL_IF(push_inst(compiler, STWUX | S(SLJIT_SP) | A(SLJIT_SP) | B(TMP_REG2))); -#else - FAIL_IF(push_inst(compiler, STDUX | S(SLJIT_SP) | A(SLJIT_SP) | B(TMP_REG2))); -#endif - local_size = 0; - offset = 0; - } - - tmp = SLJIT_FS0 - fsaveds; - for (i = SLJIT_FS0; i > tmp; i--) { - offset -= SSIZE_OF(f64); - FAIL_IF(push_inst(compiler, STFD | FS(i) | A(base) | IMM(offset))); - } - - for (i = fscratches; i >= SLJIT_FIRST_SAVED_FLOAT_REG; i--) { - offset -= SSIZE_OF(f64); - FAIL_IF(push_inst(compiler, STFD | FS(i) | A(base) | IMM(offset))); - } - - if (!(options & SLJIT_ENTER_REG_ARG)) { - offset -= SSIZE_OF(sw); - FAIL_IF(push_inst(compiler, STACK_STORE | S(TMP_ZERO) | A(base) | IMM(offset))); - } - - tmp = SLJIT_S0 - saveds; - for (i = SLJIT_S0 - saved_arg_count; i > tmp; i--) { - offset -= SSIZE_OF(sw); - FAIL_IF(push_inst(compiler, STACK_STORE | S(i) | A(base) | IMM(offset))); - } - - for (i = scratches; i >= SLJIT_FIRST_SAVED_REG; i--) { - offset -= SSIZE_OF(sw); - FAIL_IF(push_inst(compiler, STACK_STORE | S(i) | A(base) | IMM(offset))); - } - - FAIL_IF(push_inst(compiler, STACK_STORE | S(0) | A(base) | IMM(local_size + LR_SAVE_OFFSET))); - - if (options & SLJIT_ENTER_REG_ARG) - return SLJIT_SUCCESS; - - FAIL_IF(push_inst(compiler, ADDI | D(TMP_ZERO) | A(0) | 0)); - - arg_types >>= SLJIT_ARG_SHIFT; - saved_arg_count = 0; - - while (arg_types > 0) { - if ((arg_types & SLJIT_ARG_MASK) < SLJIT_ARG_TYPE_F64) { -#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) - do { - if (!(arg_types & SLJIT_ARG_TYPE_SCRATCH_REG)) { - tmp = SLJIT_S0 - saved_arg_count; - saved_arg_count++; - } else if (arg_count != word_arg_count) - tmp = SLJIT_R0 + word_arg_count; - else - break; - - FAIL_IF(push_inst(compiler, OR | S(SLJIT_R0 + arg_count) | A(tmp) | B(SLJIT_R0 + arg_count))); - } while (0); -#else - if (!(arg_types & SLJIT_ARG_TYPE_SCRATCH_REG)) { - FAIL_IF(push_inst(compiler, OR | S(SLJIT_R0 + word_arg_count) | A(SLJIT_S0 - saved_arg_count) | B(SLJIT_R0 + word_arg_count))); - saved_arg_count++; - } -#endif - word_arg_count++; - } - -#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) - arg_count++; -#endif - arg_types >>= SLJIT_ARG_SHIFT; - } - - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(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) -{ - CHECK_ERROR(); - CHECK(check_sljit_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size)); - set_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size); - - local_size += GET_SAVED_REGISTERS_SIZE(scratches, saveds - SLJIT_KEPT_SAVEDS_COUNT(options), 0) - + GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, sizeof(sljit_f64)); - - if (!(options & SLJIT_ENTER_REG_ARG)) - local_size += SSIZE_OF(sw); - - compiler->local_size = (local_size + SLJIT_LOCALS_OFFSET + 15) & ~0xf; - return SLJIT_SUCCESS; -} - -static sljit_s32 emit_stack_frame_release(struct sljit_compiler *compiler, sljit_s32 is_return_to) -{ - sljit_s32 i, tmp, base, offset; - sljit_s32 local_size = compiler->local_size; - - base = SLJIT_SP; - if (local_size > STACK_MAX_DISTANCE) { - base = TMP_REG1; - 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))); - local_size = STACK_MAX_DISTANCE; - } - } - - offset = local_size; - if (!is_return_to) - FAIL_IF(push_inst(compiler, STACK_LOAD | S(0) | A(base) | IMM(offset + LR_SAVE_OFFSET))); - - tmp = SLJIT_FS0 - compiler->fsaveds; - for (i = SLJIT_FS0; i > tmp; i--) { - offset -= SSIZE_OF(f64); - FAIL_IF(push_inst(compiler, LFD | FS(i) | A(base) | IMM(offset))); - } - - for (i = compiler->fscratches; i >= SLJIT_FIRST_SAVED_FLOAT_REG; i--) { - offset -= SSIZE_OF(f64); - FAIL_IF(push_inst(compiler, LFD | FS(i) | A(base) | IMM(offset))); - } - - if (!(compiler->options & SLJIT_ENTER_REG_ARG)) { - offset -= SSIZE_OF(sw); - FAIL_IF(push_inst(compiler, STACK_LOAD | S(TMP_ZERO) | A(base) | IMM(offset))); - } - - tmp = SLJIT_S0 - compiler->saveds; - for (i = SLJIT_S0 - SLJIT_KEPT_SAVEDS_COUNT(compiler->options); i > tmp; i--) { - offset -= SSIZE_OF(sw); - FAIL_IF(push_inst(compiler, STACK_LOAD | S(i) | A(base) | IMM(offset))); - } - - for (i = compiler->scratches; i >= SLJIT_FIRST_SAVED_REG; i--) { - offset -= SSIZE_OF(sw); - FAIL_IF(push_inst(compiler, STACK_LOAD | S(i) | A(base) | IMM(offset))); - } - - if (!is_return_to) - push_inst(compiler, MTLR | S(0)); - - if (local_size > 0) - return push_inst(compiler, ADDI | D(SLJIT_SP) | A(base) | IMM(local_size)); - - SLJIT_ASSERT(base == TMP_REG1); - return push_inst(compiler, OR | S(base) | A(SLJIT_SP) | B(base)); -} - -#undef STACK_STORE -#undef STACK_LOAD - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_void(struct sljit_compiler *compiler) -{ - CHECK_ERROR(); - CHECK(check_sljit_emit_return_void(compiler)); - - FAIL_IF(emit_stack_frame_release(compiler, 0)); - return push_inst(compiler, BLR); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_to(struct sljit_compiler *compiler, - sljit_s32 src, sljit_sw srcw) -{ - CHECK_ERROR(); - CHECK(check_sljit_emit_return_to(compiler, src, srcw)); - - if (src & SLJIT_MEM) { - ADJUST_LOCAL_OFFSET(src, srcw); - FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, TMP_CALL_REG, src, srcw, TMP_CALL_REG)); - src = TMP_CALL_REG; - srcw = 0; - } else if (src >= SLJIT_FIRST_SAVED_REG && src <= (SLJIT_S0 - SLJIT_KEPT_SAVEDS_COUNT(compiler->options))) { - FAIL_IF(push_inst(compiler, OR | S(src) | A(TMP_CALL_REG) | B(src))); - src = TMP_CALL_REG; - srcw = 0; - } - - FAIL_IF(emit_stack_frame_release(compiler, 1)); - - SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_ijump(compiler, SLJIT_JUMP, src, srcw); -} - -/* --------------------------------------------------------------------- */ -/* Operators */ -/* --------------------------------------------------------------------- */ - -/* s/l - store/load (1 bit) - i/x - immediate/indexed form - u/s - signed/unsigned (1 bit) - w/b/h/i - word/byte/half/int allowed (2 bit) - - Some opcodes are repeated (e.g. store signed / unsigned byte is the same instruction). */ - -/* 64 bit only: [reg+imm] must be aligned to 4 bytes. */ -#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) -#define INT_ALIGNED 0x10000 -#endif - -#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) -#define ARCH_32_64(a, b) a -#define INST_CODE_AND_DST(inst, flags, reg) \ - ((sljit_ins)(inst) | (sljit_ins)(((flags) & MEM_MASK) <= GPR_REG ? D(reg) : FD(reg))) -#else -#define ARCH_32_64(a, b) b -#define INST_CODE_AND_DST(inst, flags, reg) \ - (((sljit_ins)(inst) & ~(sljit_ins)INT_ALIGNED) | (sljit_ins)(((flags) & MEM_MASK) <= GPR_REG ? D(reg) : FD(reg))) -#endif - -static const sljit_ins data_transfer_insts[64 + 16] = { - -/* -------- Integer -------- */ - -/* Word. */ - -/* w u i s */ ARCH_32_64(HI(36) /* stw */, HI(62) | INT_ALIGNED | 0x0 /* std */), -/* w u i l */ ARCH_32_64(HI(32) /* lwz */, HI(58) | INT_ALIGNED | 0x0 /* ld */), -/* w u x s */ ARCH_32_64(HI(31) | LO(151) /* stwx */, HI(31) | LO(149) /* stdx */), -/* w u x l */ ARCH_32_64(HI(31) | LO(23) /* lwzx */, HI(31) | LO(21) /* ldx */), - -/* w s i s */ ARCH_32_64(HI(36) /* stw */, HI(62) | INT_ALIGNED | 0x0 /* std */), -/* w s i l */ ARCH_32_64(HI(32) /* lwz */, HI(58) | INT_ALIGNED | 0x0 /* ld */), -/* w s x s */ ARCH_32_64(HI(31) | LO(151) /* stwx */, HI(31) | LO(149) /* stdx */), -/* w s x l */ ARCH_32_64(HI(31) | LO(23) /* lwzx */, HI(31) | LO(21) /* ldx */), - -/* Byte. */ - -/* b u i s */ HI(38) /* stb */, -/* b u i l */ HI(34) /* lbz */, -/* b u x s */ HI(31) | LO(215) /* stbx */, -/* b u x l */ HI(31) | LO(87) /* lbzx */, - -/* b s i s */ HI(38) /* stb */, -/* b s i l */ HI(34) /* lbz */ /* EXTS_REQ */, -/* b s x s */ HI(31) | LO(215) /* stbx */, -/* b s x l */ HI(31) | LO(87) /* lbzx */ /* EXTS_REQ */, - -/* Half. */ - -/* h u i s */ HI(44) /* sth */, -/* h u i l */ HI(40) /* lhz */, -/* h u x s */ HI(31) | LO(407) /* sthx */, -/* h u x l */ HI(31) | LO(279) /* lhzx */, - -/* h s i s */ HI(44) /* sth */, -/* h s i l */ HI(42) /* lha */, -/* h s x s */ HI(31) | LO(407) /* sthx */, -/* h s x l */ HI(31) | LO(343) /* lhax */, - -/* Int. */ - -/* i u i s */ HI(36) /* stw */, -/* i u i l */ HI(32) /* lwz */, -/* i u x s */ HI(31) | LO(151) /* stwx */, -/* i u x l */ HI(31) | LO(23) /* lwzx */, - -/* i s i s */ HI(36) /* stw */, -/* i s i l */ ARCH_32_64(HI(32) /* lwz */, HI(58) | INT_ALIGNED | 0x2 /* lwa */), -/* i s x s */ HI(31) | LO(151) /* stwx */, -/* i s x l */ ARCH_32_64(HI(31) | LO(23) /* lwzx */, HI(31) | LO(341) /* lwax */), - -/* -------- Floating point -------- */ - -/* d i s */ HI(54) /* stfd */, -/* d i l */ HI(50) /* lfd */, -/* d x s */ HI(31) | LO(727) /* stfdx */, -/* d x l */ HI(31) | LO(599) /* lfdx */, - -/* s i s */ HI(52) /* stfs */, -/* s i l */ HI(48) /* lfs */, -/* s x s */ HI(31) | LO(663) /* stfsx */, -/* s x l */ HI(31) | LO(535) /* lfsx */, -}; - -static const sljit_ins updated_data_transfer_insts[64] = { - -/* -------- Integer -------- */ - -/* Word. */ - -/* w u i s */ ARCH_32_64(HI(37) /* stwu */, HI(62) | INT_ALIGNED | 0x1 /* stdu */), -/* w u i l */ ARCH_32_64(HI(33) /* lwzu */, HI(58) | INT_ALIGNED | 0x1 /* ldu */), -/* w u x s */ ARCH_32_64(HI(31) | LO(183) /* stwux */, HI(31) | LO(181) /* stdux */), -/* w u x l */ ARCH_32_64(HI(31) | LO(55) /* lwzux */, HI(31) | LO(53) /* ldux */), - -/* w s i s */ ARCH_32_64(HI(37) /* stwu */, HI(62) | INT_ALIGNED | 0x1 /* stdu */), -/* w s i l */ ARCH_32_64(HI(33) /* lwzu */, HI(58) | INT_ALIGNED | 0x1 /* ldu */), -/* w s x s */ ARCH_32_64(HI(31) | LO(183) /* stwux */, HI(31) | LO(181) /* stdux */), -/* w s x l */ ARCH_32_64(HI(31) | LO(55) /* lwzux */, HI(31) | LO(53) /* ldux */), - -/* Byte. */ - -/* b u i s */ HI(39) /* stbu */, -/* b u i l */ HI(35) /* lbzu */, -/* b u x s */ HI(31) | LO(247) /* stbux */, -/* b u x l */ HI(31) | LO(119) /* lbzux */, - -/* b s i s */ HI(39) /* stbu */, -/* b s i l */ 0 /* no such instruction */, -/* b s x s */ HI(31) | LO(247) /* stbux */, -/* b s x l */ 0 /* no such instruction */, - -/* Half. */ - -/* h u i s */ HI(45) /* sthu */, -/* h u i l */ HI(41) /* lhzu */, -/* h u x s */ HI(31) | LO(439) /* sthux */, -/* h u x l */ HI(31) | LO(311) /* lhzux */, - -/* h s i s */ HI(45) /* sthu */, -/* h s i l */ HI(43) /* lhau */, -/* h s x s */ HI(31) | LO(439) /* sthux */, -/* h s x l */ HI(31) | LO(375) /* lhaux */, - -/* Int. */ - -/* i u i s */ HI(37) /* stwu */, -/* i u i l */ HI(33) /* lwzu */, -/* i u x s */ HI(31) | LO(183) /* stwux */, -/* i u x l */ HI(31) | LO(55) /* lwzux */, - -/* i s i s */ HI(37) /* stwu */, -/* i s i l */ ARCH_32_64(HI(33) /* lwzu */, 0 /* no such instruction */), -/* i s x s */ HI(31) | LO(183) /* stwux */, -/* i s x l */ ARCH_32_64(HI(31) | LO(55) /* lwzux */, HI(31) | LO(373) /* lwaux */), - -/* -------- Floating point -------- */ - -/* d i s */ HI(55) /* stfdu */, -/* d i l */ HI(51) /* lfdu */, -/* d x s */ HI(31) | LO(759) /* stfdux */, -/* d x l */ HI(31) | LO(631) /* lfdux */, - -/* s i s */ HI(53) /* stfsu */, -/* s i l */ HI(49) /* lfsu */, -/* s x s */ HI(31) | LO(695) /* stfsux */, -/* s x l */ HI(31) | LO(567) /* lfsux */, -}; - -#undef ARCH_32_64 - -/* Simple cases, (no caching is required). */ -static sljit_s32 emit_op_mem(struct sljit_compiler *compiler, sljit_s32 inp_flags, sljit_s32 reg, - sljit_s32 arg, sljit_sw argw, sljit_s32 tmp_reg) -{ - sljit_ins inst; - sljit_s32 offs_reg; - - /* Should work when (arg & REG_MASK) == 0. */ - SLJIT_ASSERT(A(0) == 0); - SLJIT_ASSERT(arg & SLJIT_MEM); - - if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) { - argw &= 0x3; - offs_reg = OFFS_REG(arg); - - if (argw != 0) { - FAIL_IF(push_inst(compiler, SLWI_W(argw) | S(OFFS_REG(arg)) | A(tmp_reg))); - offs_reg = tmp_reg; - } - - inst = data_transfer_insts[(inp_flags | INDEXED) & MEM_MASK]; - -#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) - SLJIT_ASSERT(!(inst & INT_ALIGNED)); -#endif /* SLJIT_CONFIG_PPC_64 */ - - return push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(arg & REG_MASK) | B(offs_reg)); - } - - inst = data_transfer_insts[inp_flags & MEM_MASK]; - arg &= REG_MASK; - -#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) - if ((inst & INT_ALIGNED) && (argw & 0x3) != 0) { - FAIL_IF(load_immediate(compiler, tmp_reg, argw)); - - inst = data_transfer_insts[(inp_flags | INDEXED) & MEM_MASK]; - return push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(arg) | B(tmp_reg)); - } -#endif /* SLJIT_CONFIG_PPC_64 */ - - if (argw <= SIMM_MAX && argw >= SIMM_MIN) - return push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(arg) | IMM(argw)); - -#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) - if (argw <= 0x7fff7fffl && argw >= -0x80000000l) { -#endif /* SLJIT_CONFIG_PPC_64 */ - FAIL_IF(push_inst(compiler, ADDIS | D(tmp_reg) | A(arg) | IMM((argw + 0x8000) >> 16))); - return push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(tmp_reg) | IMM(argw)); -#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) - } - - FAIL_IF(load_immediate(compiler, tmp_reg, argw)); - - inst = data_transfer_insts[(inp_flags | INDEXED) & MEM_MASK]; - return push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(arg) | B(tmp_reg)); -#endif /* SLJIT_CONFIG_PPC_64 */ -} - -static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 input_flags, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - /* arg1 goes to TMP_REG1 or src reg - arg2 goes to TMP_REG2, imm or src reg - result goes to TMP_REG2, so put result can use TMP_REG1. */ - sljit_s32 dst_r = TMP_REG2; - sljit_s32 src1_r; - sljit_s32 src2_r; - sljit_s32 sugg_src2_r = 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. */ - if (FAST_IS_REG(dst)) { - dst_r = dst; - /* The REG_DEST is only used by SLJIT_MOV operations, although - * it is set for op2 operations with unset destination. */ - 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; - } - - /* Source 2. */ - if (FAST_IS_REG(src2)) { - src2_r = src2; - flags |= REG2_SOURCE; - - if (!(flags & REG_DEST) && op >= SLJIT_MOV && op <= SLJIT_MOV_P) - dst_r = src2_r; - } - 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; - } - } - else { - FAIL_IF(emit_op_mem(compiler, input_flags | LOAD_DATA, sugg_src2_r, src2, src2w, TMP_REG2)); - src2_r = sugg_src2_r; - } - - FAIL_IF(emit_single_op(compiler, op, flags, dst_r, src1_r, src2_r)); - - if (!(dst & SLJIT_MEM)) - return SLJIT_SUCCESS; - - return emit_op_mem(compiler, input_flags, dst_r, dst, dstw, TMP_REG1); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compiler, sljit_s32 op) -{ -#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) - sljit_s32 int_op = op & SLJIT_32; -#endif - - CHECK_ERROR(); - CHECK(check_sljit_emit_op0(compiler, op)); - - op = GET_OPCODE(op); - switch (op) { - case SLJIT_BREAKPOINT: - case SLJIT_NOP: - return push_inst(compiler, NOP); - case SLJIT_LMUL_UW: - case SLJIT_LMUL_SW: - FAIL_IF(push_inst(compiler, OR | S(SLJIT_R0) | A(TMP_REG1) | B(SLJIT_R0))); -#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) - FAIL_IF(push_inst(compiler, MULLD | D(SLJIT_R0) | A(TMP_REG1) | B(SLJIT_R1))); - return push_inst(compiler, (op == SLJIT_LMUL_UW ? MULHDU : MULHD) | D(SLJIT_R1) | A(TMP_REG1) | B(SLJIT_R1)); -#else - FAIL_IF(push_inst(compiler, MULLW | D(SLJIT_R0) | A(TMP_REG1) | B(SLJIT_R1))); - return push_inst(compiler, (op == SLJIT_LMUL_UW ? MULHWU : MULHW) | D(SLJIT_R1) | A(TMP_REG1) | B(SLJIT_R1)); -#endif - case SLJIT_DIVMOD_UW: - case SLJIT_DIVMOD_SW: - FAIL_IF(push_inst(compiler, OR | S(SLJIT_R0) | A(TMP_REG1) | B(SLJIT_R0))); -#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) - FAIL_IF(push_inst(compiler, (int_op ? (op == SLJIT_DIVMOD_UW ? DIVWU : DIVW) : (op == SLJIT_DIVMOD_UW ? DIVDU : DIVD)) | D(SLJIT_R0) | A(SLJIT_R0) | B(SLJIT_R1))); - FAIL_IF(push_inst(compiler, (int_op ? MULLW : MULLD) | D(SLJIT_R1) | A(SLJIT_R0) | B(SLJIT_R1))); -#else - FAIL_IF(push_inst(compiler, (op == SLJIT_DIVMOD_UW ? DIVWU : DIVW) | D(SLJIT_R0) | A(SLJIT_R0) | B(SLJIT_R1))); - FAIL_IF(push_inst(compiler, MULLW | D(SLJIT_R1) | A(SLJIT_R0) | B(SLJIT_R1))); -#endif - return push_inst(compiler, SUBF | D(SLJIT_R1) | A(SLJIT_R1) | B(TMP_REG1)); - case SLJIT_DIV_UW: - case SLJIT_DIV_SW: -#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) - return push_inst(compiler, (int_op ? (op == SLJIT_DIV_UW ? DIVWU : DIVW) : (op == SLJIT_DIV_UW ? DIVDU : DIVD)) | D(SLJIT_R0) | A(SLJIT_R0) | B(SLJIT_R1)); -#else - return push_inst(compiler, (op == SLJIT_DIV_UW ? DIVWU : DIVW) | D(SLJIT_R0) | A(SLJIT_R0) | B(SLJIT_R1)); -#endif - case SLJIT_ENDBR: - case SLJIT_SKIP_FRAMES_BEFORE_RETURN: - return SLJIT_SUCCESS; - } - - return SLJIT_SUCCESS; -} - -static sljit_s32 emit_prefetch(struct sljit_compiler *compiler, - sljit_s32 src, sljit_sw srcw) -{ - if (!(src & OFFS_REG_MASK)) { - if (srcw == 0 && (src & REG_MASK)) - return push_inst(compiler, DCBT | A(0) | B(src & REG_MASK)); - - FAIL_IF(load_immediate(compiler, TMP_REG1, srcw)); - /* Works with SLJIT_MEM0() case as well. */ - return push_inst(compiler, DCBT | A(src & REG_MASK) | B(TMP_REG1)); - } - - srcw &= 0x3; - - if (srcw == 0) - return push_inst(compiler, DCBT | A(src & REG_MASK) | B(OFFS_REG(src))); - - FAIL_IF(push_inst(compiler, SLWI_W(srcw) | S(OFFS_REG(src)) | A(TMP_REG1))); - return push_inst(compiler, DCBT | A(src & REG_MASK) | B(TMP_REG1)); -} - -#define EMIT_MOV(type, type_flags, type_cast) \ - emit_op(compiler, (src & SLJIT_IMM) ? SLJIT_MOV : type, flags | (type_flags), dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? type_cast srcw : srcw) - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src, sljit_sw srcw) -{ - sljit_s32 flags = HAS_FLAGS(op) ? ALT_SET_FLAGS : 0; - 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); - - op = GET_OPCODE(op); - - if (GET_FLAG_TYPE(op_flags) == SLJIT_OVERFLOW) - FAIL_IF(push_inst(compiler, MTXER | S(TMP_ZERO))); - - if (op < SLJIT_NOT && FAST_IS_REG(src) && src == dst) { - if (!TYPE_CAST_NEEDED(op)) - return SLJIT_SUCCESS; - } - -#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) - if (op_flags & SLJIT_32) { - if (op < SLJIT_NOT) { - if (src & SLJIT_MEM) { - if (op == SLJIT_MOV_S32) - op = SLJIT_MOV_U32; - } - else if (src & SLJIT_IMM) { - if (op == SLJIT_MOV_U32) - op = SLJIT_MOV_S32; - } - } - else { - /* Most operations expect sign extended arguments. */ - flags |= INT_DATA | SIGNED_DATA; - if (HAS_FLAGS(op_flags)) - flags |= ALT_SIGN_EXT; - } - } -#endif - - switch (op) { - case SLJIT_MOV: -#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) - case SLJIT_MOV_U32: - case SLJIT_MOV_S32: - case SLJIT_MOV32: -#endif - case SLJIT_MOV_P: - return emit_op(compiler, SLJIT_MOV, flags | WORD_DATA, dst, dstw, TMP_REG1, 0, src, srcw); - -#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) - case SLJIT_MOV_U32: - return EMIT_MOV(SLJIT_MOV_U32, INT_DATA, (sljit_u32)); - - case SLJIT_MOV_S32: - case SLJIT_MOV32: - return EMIT_MOV(SLJIT_MOV_S32, INT_DATA | SIGNED_DATA, (sljit_s32)); -#endif - - case SLJIT_MOV_U8: - return EMIT_MOV(SLJIT_MOV_U8, BYTE_DATA, (sljit_u8)); - - case SLJIT_MOV_S8: - return EMIT_MOV(SLJIT_MOV_S8, BYTE_DATA | SIGNED_DATA, (sljit_s8)); - - case SLJIT_MOV_U16: - return EMIT_MOV(SLJIT_MOV_U16, HALF_DATA, (sljit_u16)); - - case SLJIT_MOV_S16: - return EMIT_MOV(SLJIT_MOV_S16, HALF_DATA | SIGNED_DATA, (sljit_s16)); - - case SLJIT_NOT: - return emit_op(compiler, SLJIT_NOT, flags, dst, dstw, TMP_REG1, 0, src, srcw); - - case SLJIT_CLZ: - case SLJIT_CTZ: -#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) - return emit_op(compiler, op, flags | (!(op_flags & SLJIT_32) ? 0 : ALT_FORM1), dst, dstw, TMP_REG1, 0, src, srcw); -#else - return emit_op(compiler, op, flags, dst, dstw, TMP_REG1, 0, src, srcw); -#endif - } - - return SLJIT_SUCCESS; -} - -#undef EMIT_MOV - -#define TEST_SL_IMM(src, srcw) \ - (((src) & SLJIT_IMM) && (srcw) <= SIMM_MAX && (srcw) >= SIMM_MIN) - -#define TEST_UL_IMM(src, srcw) \ - (((src) & SLJIT_IMM) && !((srcw) & ~0xffff)) - -#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) -#define TEST_SH_IMM(src, srcw) \ - (((src) & SLJIT_IMM) && !((srcw) & 0xffff) && (srcw) <= 0x7fffffffl && (srcw) >= -0x80000000l) -#else -#define TEST_SH_IMM(src, srcw) \ - (((src) & SLJIT_IMM) && !((srcw) & 0xffff)) -#endif - -#define TEST_UH_IMM(src, srcw) \ - (((src) & SLJIT_IMM) && !((srcw) & ~(sljit_sw)0xffff0000)) - -#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) -#define TEST_ADD_IMM(src, srcw) \ - (((src) & SLJIT_IMM) && (srcw) <= 0x7fff7fffl && (srcw) >= -0x80000000l) -#else -#define TEST_ADD_IMM(src, srcw) \ - ((src) & SLJIT_IMM) -#endif - -#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) -#define TEST_UI_IMM(src, srcw) \ - (((src) & SLJIT_IMM) && !((srcw) & ~0xffffffff)) -#else -#define TEST_UI_IMM(src, srcw) \ - ((src) & SLJIT_IMM) -#endif - -#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) -#define TEST_ADD_FORM1(op) \ - (GET_FLAG_TYPE(op) == SLJIT_OVERFLOW \ - || (op & (SLJIT_32 | SLJIT_SET_Z | VARIABLE_FLAG_MASK)) == (SLJIT_32 | SLJIT_SET_Z | SLJIT_SET_CARRY)) -#define TEST_SUB_FORM2(op) \ - ((GET_FLAG_TYPE(op) >= SLJIT_SIG_LESS && GET_FLAG_TYPE(op) <= SLJIT_SIG_LESS_EQUAL) \ - || (op & (SLJIT_32 | SLJIT_SET_Z | VARIABLE_FLAG_MASK)) == (SLJIT_32 | SLJIT_SET_Z)) -#define TEST_SUB_FORM3(op) \ - (GET_FLAG_TYPE(op) == SLJIT_OVERFLOW \ - || (op & (SLJIT_32 | SLJIT_SET_Z)) == (SLJIT_32 | SLJIT_SET_Z)) -#else -#define TEST_ADD_FORM1(op) \ - (GET_FLAG_TYPE(op) == SLJIT_OVERFLOW) -#define TEST_SUB_FORM2(op) \ - (GET_FLAG_TYPE(op) >= SLJIT_SIG_LESS && GET_FLAG_TYPE(op) <= SLJIT_SIG_LESS_EQUAL) -#define TEST_SUB_FORM3(op) \ - (GET_FLAG_TYPE(op) == SLJIT_OVERFLOW) -#endif - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - sljit_s32 flags = HAS_FLAGS(op) ? ALT_SET_FLAGS : 0; - - CHECK_ERROR(); - CHECK(check_sljit_emit_op2(compiler, op, 0, dst, dstw, src1, src1w, src2, src2w)); - ADJUST_LOCAL_OFFSET(dst, dstw); - ADJUST_LOCAL_OFFSET(src1, src1w); - ADJUST_LOCAL_OFFSET(src2, src2w); - -#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) - if (op & SLJIT_32) { - /* Most operations expect sign extended arguments. */ - flags |= INT_DATA | SIGNED_DATA; - if (src1 & SLJIT_IMM) - src1w = (sljit_s32)(src1w); - if (src2 & SLJIT_IMM) - src2w = (sljit_s32)(src2w); - if (HAS_FLAGS(op)) - flags |= ALT_SIGN_EXT; - } -#endif - if (GET_FLAG_TYPE(op) == SLJIT_OVERFLOW) - FAIL_IF(push_inst(compiler, MTXER | S(TMP_ZERO))); - - switch (GET_OPCODE(op)) { - case SLJIT_ADD: - compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD; - - if (TEST_ADD_FORM1(op)) - return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM1, dst, dstw, src1, src1w, src2, src2w); - - if (!HAS_FLAGS(op) && ((src1 | src2) & SLJIT_IMM)) { - if (TEST_SL_IMM(src2, src2w)) { - compiler->imm = (sljit_ins)src2w & 0xffff; - return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2, dst, dstw, src1, src1w, TMP_REG2, 0); - } - if (TEST_SL_IMM(src1, src1w)) { - compiler->imm = (sljit_ins)src1w & 0xffff; - return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2, dst, dstw, src2, src2w, TMP_REG2, 0); - } - if (TEST_SH_IMM(src2, src2w)) { - compiler->imm = (sljit_ins)(src2w >> 16) & 0xffff; - return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2 | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0); - } - if (TEST_SH_IMM(src1, src1w)) { - compiler->imm = (sljit_ins)(src1w >> 16) & 0xffff; - return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2 | ALT_FORM3, dst, dstw, src2, src2w, TMP_REG2, 0); - } - /* Range between -1 and -32768 is covered above. */ - if (TEST_ADD_IMM(src2, src2w)) { - compiler->imm = (sljit_ins)src2w & 0xffffffff; - return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2 | ALT_FORM4, dst, dstw, src1, src1w, TMP_REG2, 0); - } - if (TEST_ADD_IMM(src1, src1w)) { - compiler->imm = (sljit_ins)src1w & 0xffffffff; - return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2 | ALT_FORM4, dst, dstw, src2, src2w, TMP_REG2, 0); - } - } - -#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) - if ((op & (SLJIT_32 | SLJIT_SET_Z)) == (SLJIT_32 | SLJIT_SET_Z)) { - if (TEST_SL_IMM(src2, src2w)) { - compiler->imm = (sljit_ins)src2w & 0xffff; - return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM4 | ALT_FORM5, dst, dstw, src1, src1w, TMP_REG2, 0); - } - if (TEST_SL_IMM(src1, src1w)) { - compiler->imm = (sljit_ins)src1w & 0xffff; - return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM4 | ALT_FORM5, dst, dstw, src2, src2w, TMP_REG2, 0); - } - return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM4, dst, dstw, src1, src1w, src2, src2w); - } -#endif - if (HAS_FLAGS(op)) { - if (TEST_SL_IMM(src2, src2w)) { - compiler->imm = (sljit_ins)src2w & 0xffff; - return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0); - } - if (TEST_SL_IMM(src1, src1w)) { - compiler->imm = (sljit_ins)src1w & 0xffff; - return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM3, dst, dstw, src2, src2w, TMP_REG2, 0); - } - } - return emit_op(compiler, SLJIT_ADD, flags | ((GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY)) ? ALT_FORM5 : 0), dst, dstw, src1, src1w, src2, src2w); - - case SLJIT_ADDC: - compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD; - return emit_op(compiler, SLJIT_ADDC, flags, dst, dstw, src1, src1w, src2, src2w); - - case SLJIT_SUB: - 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 (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); - } - return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM1, dst, dstw, src1, src1w, src2, src2w); - } - - if ((src2 & SLJIT_IMM) && src2w >= 0 && src2w <= (SIMM_MAX + 1)) { - compiler->imm = (sljit_ins)src2w; - return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM1 | ALT_FORM2 | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0); - } - 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 (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); - } - return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM2, dst, dstw, src1, src1w, src2, src2w); - } - - if (TEST_SUB_FORM2(op)) { - if ((src2 & SLJIT_IMM) && src2w >= -SIMM_MAX && src2w <= SIMM_MAX) { - compiler->imm = (sljit_ins)src2w & 0xffff; - return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM2 | ALT_FORM3 | ALT_FORM4, dst, dstw, src1, src1w, TMP_REG2, 0); - } - return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM2 | ALT_FORM4, dst, dstw, src1, src1w, src2, src2w); - } - - if (TEST_SUB_FORM3(op)) - return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM3, dst, dstw, src1, src1w, src2, src2w); - - if (TEST_SL_IMM(src2, -src2w)) { - compiler->imm = (sljit_ins)(-src2w) & 0xffff; - return emit_op(compiler, SLJIT_ADD, flags | (!HAS_FLAGS(op) ? ALT_FORM2 : ALT_FORM3), dst, dstw, src1, src1w, TMP_REG2, 0); - } - - if (TEST_SL_IMM(src1, src1w) && !(op & SLJIT_SET_Z)) { - compiler->imm = (sljit_ins)src1w & 0xffff; - return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM4, dst, dstw, src2, src2w, TMP_REG2, 0); - } - - if (!HAS_FLAGS(op)) { - if (TEST_SH_IMM(src2, -src2w)) { - compiler->imm = (sljit_ins)((-src2w) >> 16) & 0xffff; - return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2 | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0); - } - /* Range between -1 and -32768 is covered above. */ - if (TEST_ADD_IMM(src2, -src2w)) { - compiler->imm = (sljit_ins)-src2w; - return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2 | ALT_FORM4, dst, dstw, src1, src1w, TMP_REG2, 0); - } - } - - /* We know ALT_SIGN_EXT is set if it is an SLJIT_32 on 64 bit systems. */ - return emit_op(compiler, SLJIT_SUB, flags | ((GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY)) ? ALT_FORM5 : 0), dst, dstw, src1, src1w, src2, src2w); - - case SLJIT_SUBC: - compiler->status_flags_state = SLJIT_CURRENT_FLAGS_SUB; - return emit_op(compiler, SLJIT_SUBC, flags, dst, dstw, src1, src1w, src2, src2w); - - case SLJIT_MUL: -#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) - if (op & SLJIT_32) - flags |= ALT_FORM2; -#endif - if (!HAS_FLAGS(op)) { - if (TEST_SL_IMM(src2, src2w)) { - compiler->imm = (sljit_ins)src2w & 0xffff; - return emit_op(compiler, SLJIT_MUL, flags | ALT_FORM1, dst, dstw, src1, src1w, TMP_REG2, 0); - } - if (TEST_SL_IMM(src1, src1w)) { - compiler->imm = (sljit_ins)src1w & 0xffff; - return emit_op(compiler, SLJIT_MUL, flags | ALT_FORM1, dst, dstw, src2, src2w, TMP_REG2, 0); - } - } - else - FAIL_IF(push_inst(compiler, MTXER | S(TMP_ZERO))); - return emit_op(compiler, SLJIT_MUL, flags, dst, dstw, src1, src1w, src2, src2w); - - case SLJIT_AND: - case SLJIT_OR: - case SLJIT_XOR: - /* Commutative unsigned operations. */ - if (!HAS_FLAGS(op) || GET_OPCODE(op) == SLJIT_AND) { - if (TEST_UL_IMM(src2, src2w)) { - compiler->imm = (sljit_ins)src2w; - return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM1, dst, dstw, src1, src1w, TMP_REG2, 0); - } - if (TEST_UL_IMM(src1, src1w)) { - compiler->imm = (sljit_ins)src1w; - return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM1, dst, dstw, src2, src2w, TMP_REG2, 0); - } - if (TEST_UH_IMM(src2, src2w)) { - compiler->imm = (sljit_ins)(src2w >> 16) & 0xffff; - return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM2, dst, dstw, src1, src1w, TMP_REG2, 0); - } - if (TEST_UH_IMM(src1, src1w)) { - compiler->imm = (sljit_ins)(src1w >> 16) & 0xffff; - return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM2, dst, dstw, src2, src2w, TMP_REG2, 0); - } - } - if (!HAS_FLAGS(op) && GET_OPCODE(op) != SLJIT_AND) { - /* Unlike or and xor, the and resets unwanted bits as well. */ - if (TEST_UI_IMM(src2, src2w)) { - compiler->imm = (sljit_ins)src2w; - return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0); - } - if (TEST_UI_IMM(src1, src1w)) { - compiler->imm = (sljit_ins)src1w; - return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM3, dst, dstw, src2, src2w, TMP_REG2, 0); - } - } - return emit_op(compiler, GET_OPCODE(op), flags, dst, dstw, src1, src1w, src2, src2w); - - case SLJIT_SHL: - case SLJIT_MSHL: - case SLJIT_LSHR: - case SLJIT_MLSHR: - case SLJIT_ASHR: - case SLJIT_MASHR: - case SLJIT_ROTL: - case SLJIT_ROTR: -#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) - if (op & SLJIT_32) - flags |= ALT_FORM2; -#endif - if (src2 & SLJIT_IMM) { - compiler->imm = (sljit_ins)src2w; - return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM1, dst, dstw, src1, src1w, TMP_REG2, 0); - } - return emit_op(compiler, GET_OPCODE(op), flags, dst, dstw, src1, src1w, src2, src2w); - } - - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - 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, TMP_REG2, 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_shift_into(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 src_dst, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - sljit_s32 is_right; -#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) - sljit_s32 inp_flags = ((op & SLJIT_32) ? INT_DATA : WORD_DATA) | LOAD_DATA; - sljit_sw bit_length = (op & SLJIT_32) ? 32 : 64; -#else /* !SLJIT_CONFIG_PPC_64 */ - sljit_s32 inp_flags = WORD_DATA | LOAD_DATA; - sljit_sw bit_length = 32; -#endif /* SLJIT_CONFIG_PPC_64 */ - - CHECK_ERROR(); - CHECK(check_sljit_emit_shift_into(compiler, op, src_dst, src1, src1w, src2, src2w)); - - is_right = (GET_OPCODE(op) == SLJIT_LSHR || GET_OPCODE(op) == SLJIT_MLSHR); - - if (src_dst == src1) { - SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_op2(compiler, (is_right ? SLJIT_ROTR : SLJIT_ROTL) | (op & SLJIT_32), src_dst, 0, src_dst, 0, src2, src2w); - } - - ADJUST_LOCAL_OFFSET(src1, src1w); - ADJUST_LOCAL_OFFSET(src2, src2w); - - if (src2 & SLJIT_IMM) { - src2w &= bit_length - 1; - - if (src2w == 0) - return SLJIT_SUCCESS; - } else if (src2 & SLJIT_MEM) { - FAIL_IF(emit_op_mem(compiler, inp_flags, TMP_REG2, src2, src2w, TMP_REG2)); - src2 = TMP_REG2; - } - - if (src1 & SLJIT_MEM) { - FAIL_IF(emit_op_mem(compiler, inp_flags, TMP_REG1, src1, src1w, TMP_REG1)); - src1 = TMP_REG1; - } else if (src1 & SLJIT_IMM) { - FAIL_IF(load_immediate(compiler, TMP_REG1, src1w)); - src1 = TMP_REG1; - } - - if (src2 & SLJIT_IMM) { -#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) - if (!(op & SLJIT_32)) { - if (is_right) { - FAIL_IF(push_inst(compiler, SRDI(src2w) | S(src_dst) | A(src_dst))); - return push_inst(compiler, RLDIMI | S(src1) | A(src_dst) | RLDI_SH(64 - src2w) | RLDI_MB(0)); - } - - FAIL_IF(push_inst(compiler, SLDI(src2w) | S(src_dst) | A(src_dst))); - /* Computes SRDI(64 - src2w). */ - FAIL_IF(push_inst(compiler, RLDICL | S(src1) | A(TMP_REG1) | RLDI_SH(src2w) | RLDI_MB(64 - src2w))); - return push_inst(compiler, OR | S(src_dst) | A(src_dst) | B(TMP_REG1)); - } -#endif /* SLJIT_CONFIG_PPC_64 */ - - if (is_right) { - FAIL_IF(push_inst(compiler, SRWI(src2w) | S(src_dst) | A(src_dst))); - return push_inst(compiler, RLWIMI | S(src1) | A(src_dst) | RLWI_SH(32 - src2w) | RLWI_MBE(0, src2w - 1)); - } - - FAIL_IF(push_inst(compiler, SLWI(src2w) | S(src_dst) | A(src_dst))); - return push_inst(compiler, RLWIMI | S(src1) | A(src_dst) | RLWI_SH(src2w) | RLWI_MBE(32 - src2w, 31)); - } - -#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) - if (!(op & SLJIT_32)) { - if (GET_OPCODE(op) == SLJIT_MSHL || GET_OPCODE(op) == SLJIT_MLSHR) { - FAIL_IF(push_inst(compiler, ANDI | S(src2) | A(TMP_REG2) | 0x3f)); - src2 = TMP_REG2; - } - - FAIL_IF(push_inst(compiler, (is_right ? SRD : SLD) | S(src_dst) | A(src_dst) | B(src2))); - FAIL_IF(push_inst(compiler, (is_right ? SLDI(1) : SRDI(1)) | S(src1) | A(TMP_REG1))); - FAIL_IF(push_inst(compiler, XORI | S(src2) | A(TMP_REG2) | 0x3f)); - FAIL_IF(push_inst(compiler, (is_right ? SLD : SRD) | S(TMP_REG1) | A(TMP_REG1) | B(TMP_REG2))); - return push_inst(compiler, OR | S(src_dst) | A(src_dst) | B(TMP_REG1)); - } -#endif /* SLJIT_CONFIG_PPC_64 */ - - if (GET_OPCODE(op) == SLJIT_MSHL || GET_OPCODE(op) == SLJIT_MLSHR) { - FAIL_IF(push_inst(compiler, ANDI | S(src2) | A(TMP_REG2) | 0x1f)); - src2 = TMP_REG2; - } - - FAIL_IF(push_inst(compiler, (is_right ? SRW : SLW) | S(src_dst) | A(src_dst) | B(src2))); - FAIL_IF(push_inst(compiler, (is_right ? SLWI(1) : SRWI(1)) | S(src1) | A(TMP_REG1))); - FAIL_IF(push_inst(compiler, XORI | S(src2) | A(TMP_REG2) | 0x1f)); - FAIL_IF(push_inst(compiler, (is_right ? SLW : SRW) | S(TMP_REG1) | A(TMP_REG1) | B(TMP_REG2))); - return push_inst(compiler, OR | S(src_dst) | A(src_dst) | B(TMP_REG1)); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 src, sljit_sw srcw) -{ - CHECK_ERROR(); - CHECK(check_sljit_emit_op_src(compiler, op, src, srcw)); - ADJUST_LOCAL_OFFSET(src, srcw); - - switch (op) { - case SLJIT_FAST_RETURN: - if (FAST_IS_REG(src)) - FAIL_IF(push_inst(compiler, MTLR | S(src))); - else { - FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, TMP_REG2, src, srcw, TMP_REG2)); - FAIL_IF(push_inst(compiler, MTLR | S(TMP_REG2))); - } - - return push_inst(compiler, BLR); - case SLJIT_SKIP_FRAMES_BEFORE_FAST_RETURN: - return SLJIT_SUCCESS; - case SLJIT_PREFETCH_L1: - case SLJIT_PREFETCH_L2: - case SLJIT_PREFETCH_L3: - case SLJIT_PREFETCH_ONCE: - return emit_prefetch(compiler, src, srcw); - } - - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 reg) -{ - CHECK_REG_INDEX(check_sljit_get_register_index(reg)); - return reg_map[reg]; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_float_register_index(sljit_s32 reg) -{ - CHECK_REG_INDEX(check_sljit_get_float_register_index(reg)); - return freg_map[reg]; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler, - void *instruction, sljit_u32 size) -{ - CHECK_ERROR(); - CHECK(check_sljit_emit_op_custom(compiler, instruction, size)); - - return push_inst(compiler, *(sljit_ins*)instruction); -} - -/* --------------------------------------------------------------------- */ -/* Floating point operators */ -/* --------------------------------------------------------------------- */ - -#define FLOAT_DATA(op) (DOUBLE_DATA | ((op & SLJIT_32) >> 6)) -#define SELECT_FOP(op, single, double) ((sljit_ins)((op & SLJIT_32) ? single : double)) - -#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) -#define FLOAT_TMP_MEM_OFFSET (6 * sizeof(sljit_sw)) -#else -#define FLOAT_TMP_MEM_OFFSET (2 * sizeof(sljit_sw)) - -#if (defined SLJIT_LITTLE_ENDIAN && SLJIT_LITTLE_ENDIAN) -#define FLOAT_TMP_MEM_OFFSET_LOW (2 * sizeof(sljit_sw)) -#define FLOAT_TMP_MEM_OFFSET_HI (3 * sizeof(sljit_sw)) -#else -#define FLOAT_TMP_MEM_OFFSET_LOW (3 * sizeof(sljit_sw)) -#define FLOAT_TMP_MEM_OFFSET_HI (2 * sizeof(sljit_sw)) -#endif - -#endif /* SLJIT_CONFIG_PPC_64 */ - -static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src, sljit_sw srcw) -{ - if (src & SLJIT_MEM) { - /* We can ignore the temporary data store on the stack from caching point of view. */ - FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src, srcw, TMP_REG1)); - src = TMP_FREG1; - } - -#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) - op = GET_OPCODE(op); - FAIL_IF(push_inst(compiler, (op == SLJIT_CONV_S32_FROM_F64 ? FCTIWZ : FCTIDZ) | FD(TMP_FREG1) | FB(src))); - - if (op == SLJIT_CONV_SW_FROM_F64) { - if (FAST_IS_REG(dst)) { - FAIL_IF(emit_op_mem(compiler, DOUBLE_DATA, TMP_FREG1, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET, TMP_REG1)); - return emit_op_mem(compiler, WORD_DATA | LOAD_DATA, dst, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET, TMP_REG1); - } - return emit_op_mem(compiler, DOUBLE_DATA, TMP_FREG1, dst, dstw, TMP_REG1); - } -#else - FAIL_IF(push_inst(compiler, FCTIWZ | FD(TMP_FREG1) | FB(src))); -#endif - - if (FAST_IS_REG(dst)) { - FAIL_IF(load_immediate(compiler, TMP_REG1, FLOAT_TMP_MEM_OFFSET)); - FAIL_IF(push_inst(compiler, STFIWX | FS(TMP_FREG1) | A(SLJIT_SP) | B(TMP_REG1))); - return emit_op_mem(compiler, INT_DATA | LOAD_DATA, dst, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET, TMP_REG1); - } - - SLJIT_ASSERT(dst & SLJIT_MEM); - - if (dst & OFFS_REG_MASK) { - dstw &= 0x3; - if (dstw) { - FAIL_IF(push_inst(compiler, SLWI_W(dstw) | S(OFFS_REG(dst)) | A(TMP_REG1))); - dstw = TMP_REG1; - } - else - dstw = OFFS_REG(dst); - } - else { - if ((dst & REG_MASK) && !dstw) { - dstw = dst & REG_MASK; - dst = 0; - } - else { - /* This works regardless we have SLJIT_MEM1 or SLJIT_MEM0. */ - FAIL_IF(load_immediate(compiler, TMP_REG1, dstw)); - dstw = TMP_REG1; - } - } - - return push_inst(compiler, STFIWX | FS(TMP_FREG1) | A(dst & REG_MASK) | B(dstw)); -} - -static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src, sljit_sw srcw) -{ -#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) - - sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1; - - if (src & SLJIT_IMM) { - if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32) - srcw = (sljit_s32)srcw; - - FAIL_IF(load_immediate(compiler, TMP_REG1, srcw)); - src = TMP_REG1; - } - else if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32) { - if (FAST_IS_REG(src)) - FAIL_IF(push_inst(compiler, EXTSW | S(src) | A(TMP_REG1))); - else - FAIL_IF(emit_op_mem(compiler, INT_DATA | SIGNED_DATA | LOAD_DATA, TMP_REG1, src, srcw, TMP_REG1)); - src = TMP_REG1; - } - - if (FAST_IS_REG(src)) { - FAIL_IF(emit_op_mem(compiler, WORD_DATA, src, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET, TMP_REG1)); - FAIL_IF(emit_op_mem(compiler, DOUBLE_DATA | LOAD_DATA, TMP_FREG1, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET, TMP_REG1)); - } - else - FAIL_IF(emit_op_mem(compiler, DOUBLE_DATA | LOAD_DATA, TMP_FREG1, src, srcw, TMP_REG1)); - - FAIL_IF(push_inst(compiler, FCFID | FD(dst_r) | FB(TMP_FREG1))); - - if (dst & SLJIT_MEM) - return emit_op_mem(compiler, FLOAT_DATA(op), TMP_FREG1, dst, dstw, TMP_REG1); - if (op & SLJIT_32) - return push_inst(compiler, FRSP | FD(dst_r) | FB(dst_r)); - return SLJIT_SUCCESS; - -#else - - sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1; - sljit_s32 invert_sign = 1; - - if (src & SLJIT_IMM) { - FAIL_IF(load_immediate(compiler, TMP_REG1, srcw ^ (sljit_sw)0x80000000)); - src = TMP_REG1; - invert_sign = 0; - } - else if (!FAST_IS_REG(src)) { - FAIL_IF(emit_op_mem(compiler, WORD_DATA | SIGNED_DATA | LOAD_DATA, TMP_REG1, src, srcw, TMP_REG1)); - src = TMP_REG1; - } - - /* First, a special double floating point value is constructed: (2^53 + (input xor (2^31))) - The double precision format has exactly 53 bit precision, so the lower 32 bit represents - the lower 32 bit of such value. The result of xor 2^31 is the same as adding 0x80000000 - to the input, which shifts it into the 0 - 0xffffffff range. To get the converted floating - point value, we need to subtract 2^53 + 2^31 from the constructed value. */ - FAIL_IF(push_inst(compiler, ADDIS | D(TMP_REG2) | A(0) | 0x4330)); - if (invert_sign) - FAIL_IF(push_inst(compiler, XORIS | S(src) | A(TMP_REG1) | 0x8000)); - FAIL_IF(emit_op_mem(compiler, WORD_DATA, TMP_REG2, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET_HI, TMP_REG1)); - FAIL_IF(emit_op_mem(compiler, WORD_DATA, TMP_REG1, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET_LOW, TMP_REG2)); - FAIL_IF(push_inst(compiler, ADDIS | D(TMP_REG1) | A(0) | 0x8000)); - FAIL_IF(emit_op_mem(compiler, DOUBLE_DATA | LOAD_DATA, TMP_FREG1, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET, TMP_REG1)); - FAIL_IF(emit_op_mem(compiler, WORD_DATA, TMP_REG1, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET_LOW, TMP_REG2)); - FAIL_IF(emit_op_mem(compiler, DOUBLE_DATA | LOAD_DATA, TMP_FREG2, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET, TMP_REG1)); - - FAIL_IF(push_inst(compiler, FSUB | FD(dst_r) | FA(TMP_FREG1) | FB(TMP_FREG2))); - - if (dst & SLJIT_MEM) - return emit_op_mem(compiler, FLOAT_DATA(op), TMP_FREG1, dst, dstw, TMP_REG1); - if (op & SLJIT_32) - return push_inst(compiler, FRSP | FD(dst_r) | FB(dst_r)); - return SLJIT_SUCCESS; - -#endif -} - -static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - if (src1 & SLJIT_MEM) { - FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w, TMP_REG1)); - src1 = TMP_FREG1; - } - - if (src2 & SLJIT_MEM) { - FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w, TMP_REG2)); - src2 = TMP_FREG2; - } - - FAIL_IF(push_inst(compiler, FCMPU | CRD(4) | FA(src1) | FB(src2))); - - switch (GET_FLAG_TYPE(op)) { - case SLJIT_UNORDERED_OR_EQUAL: - case SLJIT_ORDERED_NOT_EQUAL: - return push_inst(compiler, CROR | ((4 + 2) << 21) | ((4 + 2) << 16) | ((4 + 3) << 11)); - case SLJIT_UNORDERED_OR_LESS: - case SLJIT_ORDERED_GREATER_EQUAL: - return push_inst(compiler, CROR | ((4 + 0) << 21) | ((4 + 0) << 16) | ((4 + 3) << 11)); - case SLJIT_UNORDERED_OR_GREATER: - case SLJIT_ORDERED_LESS_EQUAL: - return push_inst(compiler, CROR | ((4 + 1) << 21) | ((4 + 1) << 16) | ((4 + 3) << 11)); - } - - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src, sljit_sw srcw) -{ - sljit_s32 dst_r; - - CHECK_ERROR(); - - SLJIT_COMPILE_ASSERT((SLJIT_32 == 0x100) && !(DOUBLE_DATA & 0x4), float_transfer_bit_error); - SELECT_FOP1_OPERATION_WITH_CHECKS(compiler, op, dst, dstw, src, srcw); - - if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_F32) - op ^= SLJIT_32; - - dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1; - - if (src & SLJIT_MEM) { - FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(op) | LOAD_DATA, dst_r, src, srcw, TMP_REG1)); - src = dst_r; - } - - switch (GET_OPCODE(op)) { - case SLJIT_CONV_F64_FROM_F32: - op ^= SLJIT_32; - if (op & SLJIT_32) { - FAIL_IF(push_inst(compiler, FRSP | FD(dst_r) | FB(src))); - break; - } - /* Fall through. */ - case SLJIT_MOV_F64: - if (src != dst_r) { - if (dst_r != TMP_FREG1) - FAIL_IF(push_inst(compiler, FMR | FD(dst_r) | FB(src))); - else - dst_r = src; - } - break; - case SLJIT_NEG_F64: - FAIL_IF(push_inst(compiler, FNEG | FD(dst_r) | FB(src))); - break; - case SLJIT_ABS_F64: - FAIL_IF(push_inst(compiler, FABS | FD(dst_r) | FB(src))); - break; - } - - if (dst & SLJIT_MEM) - FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(op), dst_r, dst, dstw, TMP_REG1)); - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - sljit_s32 dst_r; - - CHECK_ERROR(); - CHECK(check_sljit_emit_fop2(compiler, op, dst, dstw, src1, src1w, src2, src2w)); - ADJUST_LOCAL_OFFSET(dst, dstw); - ADJUST_LOCAL_OFFSET(src1, src1w); - ADJUST_LOCAL_OFFSET(src2, src2w); - - dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG2; - - if (src1 & SLJIT_MEM) { - FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w, TMP_REG1)); - src1 = TMP_FREG1; - } - - if (src2 & SLJIT_MEM) { - FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w, TMP_REG2)); - src2 = TMP_FREG2; - } - - switch (GET_OPCODE(op)) { - case SLJIT_ADD_F64: - FAIL_IF(push_inst(compiler, SELECT_FOP(op, FADDS, FADD) | FD(dst_r) | FA(src1) | FB(src2))); - break; - - case SLJIT_SUB_F64: - FAIL_IF(push_inst(compiler, SELECT_FOP(op, FSUBS, FSUB) | FD(dst_r) | FA(src1) | FB(src2))); - break; - - case SLJIT_MUL_F64: - FAIL_IF(push_inst(compiler, SELECT_FOP(op, FMULS, FMUL) | FD(dst_r) | FA(src1) | FC(src2) /* FMUL use FC as src2 */)); - break; - - case SLJIT_DIV_F64: - FAIL_IF(push_inst(compiler, SELECT_FOP(op, FDIVS, FDIV) | FD(dst_r) | FA(src1) | FB(src2))); - break; - } - - if (dst & SLJIT_MEM) - FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(op), TMP_FREG2, dst, dstw, TMP_REG1)); - - return SLJIT_SUCCESS; -} - -#undef SELECT_FOP - -/* --------------------------------------------------------------------- */ -/* Other instructions */ -/* --------------------------------------------------------------------- */ - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw) -{ - CHECK_ERROR(); - CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw)); - ADJUST_LOCAL_OFFSET(dst, dstw); - - if (FAST_IS_REG(dst)) - return push_inst(compiler, MFLR | D(dst)); - - /* Memory. */ - FAIL_IF(push_inst(compiler, MFLR | D(TMP_REG2))); - return emit_op(compiler, SLJIT_MOV, WORD_DATA, dst, dstw, TMP_REG1, 0, TMP_REG2, 0); -} - -/* --------------------------------------------------------------------- */ -/* Conditional instructions */ -/* --------------------------------------------------------------------- */ - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compiler *compiler) -{ - struct sljit_label *label; - - CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_label(compiler)); - - if (compiler->last_label && compiler->last_label->size == compiler->size) - return compiler->last_label; - - label = (struct sljit_label*)ensure_abuf(compiler, sizeof(struct sljit_label)); - PTR_FAIL_IF(!label); - set_label(label, compiler); - return label; -} - -static sljit_ins get_bo_bi_flags(struct sljit_compiler *compiler, sljit_s32 type) -{ - switch (type) { - case SLJIT_NOT_CARRY: - if (compiler->status_flags_state & SLJIT_CURRENT_FLAGS_SUB) - return (4 << 21) | (2 << 16); - /* fallthrough */ - - case SLJIT_EQUAL: - return (12 << 21) | (2 << 16); - - case SLJIT_CARRY: - if (compiler->status_flags_state & SLJIT_CURRENT_FLAGS_SUB) - return (12 << 21) | (2 << 16); - /* fallthrough */ - - case SLJIT_NOT_EQUAL: - return (4 << 21) | (2 << 16); - - case SLJIT_LESS: - case SLJIT_SIG_LESS: - return (12 << 21) | (0 << 16); - - case SLJIT_GREATER_EQUAL: - case SLJIT_SIG_GREATER_EQUAL: - return (4 << 21) | (0 << 16); - - case SLJIT_GREATER: - case SLJIT_SIG_GREATER: - return (12 << 21) | (1 << 16); - - case SLJIT_LESS_EQUAL: - case SLJIT_SIG_LESS_EQUAL: - return (4 << 21) | (1 << 16); - - case SLJIT_OVERFLOW: - return (12 << 21) | (3 << 16); - - case SLJIT_NOT_OVERFLOW: - return (4 << 21) | (3 << 16); - - case SLJIT_F_LESS: - case SLJIT_ORDERED_LESS: - case SLJIT_UNORDERED_OR_LESS: - return (12 << 21) | ((4 + 0) << 16); - - case SLJIT_F_GREATER_EQUAL: - case SLJIT_ORDERED_GREATER_EQUAL: - case SLJIT_UNORDERED_OR_GREATER_EQUAL: - return (4 << 21) | ((4 + 0) << 16); - - case SLJIT_F_GREATER: - case SLJIT_ORDERED_GREATER: - case SLJIT_UNORDERED_OR_GREATER: - return (12 << 21) | ((4 + 1) << 16); - - case SLJIT_F_LESS_EQUAL: - case SLJIT_ORDERED_LESS_EQUAL: - case SLJIT_UNORDERED_OR_LESS_EQUAL: - return (4 << 21) | ((4 + 1) << 16); - - case SLJIT_F_EQUAL: - case SLJIT_ORDERED_EQUAL: - case SLJIT_UNORDERED_OR_EQUAL: - return (12 << 21) | ((4 + 2) << 16); - - case SLJIT_F_NOT_EQUAL: - case SLJIT_ORDERED_NOT_EQUAL: - case SLJIT_UNORDERED_OR_NOT_EQUAL: - return (4 << 21) | ((4 + 2) << 16); - - case SLJIT_UNORDERED: - return (12 << 21) | ((4 + 3) << 16); - - case SLJIT_ORDERED: - return (4 << 21) | ((4 + 3) << 16); - - default: - SLJIT_ASSERT(type >= SLJIT_JUMP && type <= SLJIT_CALL_REG_ARG); - return (20 << 21); - } -} - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type) -{ - struct sljit_jump *jump; - sljit_ins bo_bi_flags; - - CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_jump(compiler, type)); - - bo_bi_flags = get_bo_bi_flags(compiler, type & 0xff); - if (!bo_bi_flags) - return NULL; - - jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump)); - PTR_FAIL_IF(!jump); - set_jump(jump, compiler, (sljit_u32)type & SLJIT_REWRITABLE_JUMP); - type &= 0xff; - - if (type == SLJIT_CARRY || type == SLJIT_NOT_CARRY) - PTR_FAIL_IF(push_inst(compiler, ADDE | RC(ALT_SET_FLAGS) | D(TMP_REG1) | A(TMP_ZERO) | B(TMP_ZERO))); - - /* In PPC, we don't need to touch the arguments. */ - if (type < SLJIT_JUMP) - jump->flags |= IS_COND; -#if (defined SLJIT_PASS_ENTRY_ADDR_TO_CALL && SLJIT_PASS_ENTRY_ADDR_TO_CALL) - if (type >= SLJIT_CALL) - 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))); - return jump; -} - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_call(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 arg_types) -{ - CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_call(compiler, type, arg_types)); - -#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) - if ((type & 0xff) != SLJIT_CALL_REG_ARG) - PTR_FAIL_IF(call_with_args(compiler, arg_types, NULL)); -#endif - - if (type & SLJIT_CALL_RETURN) { - PTR_FAIL_IF(emit_stack_frame_release(compiler, 0)); - type = SLJIT_JUMP | (type & SLJIT_REWRITABLE_JUMP); - } - - SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_jump(compiler, type); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 src, sljit_sw srcw) -{ - struct sljit_jump *jump = NULL; - sljit_s32 src_r; - - 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) { - /* These jumps are converted to jump/call instructions when possible. */ - jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump)); - FAIL_IF(!jump); - set_jump(jump, compiler, JUMP_ADDR); - jump->u.target = (sljit_uw)srcw; - -#if (defined SLJIT_PASS_ENTRY_ADDR_TO_CALL && SLJIT_PASS_ENTRY_ADDR_TO_CALL) - if (type >= SLJIT_CALL) - 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; - } else { - ADJUST_LOCAL_OFFSET(src, srcw); - FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, TMP_CALL_REG, src, srcw, TMP_CALL_REG)); - src_r = TMP_CALL_REG; - } - - 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)); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 arg_types, - sljit_s32 src, sljit_sw srcw) -{ - CHECK_ERROR(); - CHECK(check_sljit_emit_icall(compiler, type, arg_types, src, srcw)); - - if (src & SLJIT_MEM) { - ADJUST_LOCAL_OFFSET(src, srcw); - FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, TMP_CALL_REG, src, srcw, TMP_CALL_REG)); - src = TMP_CALL_REG; - } - - if (type & SLJIT_CALL_RETURN) { - if (src >= SLJIT_FIRST_SAVED_REG && src <= (SLJIT_S0 - SLJIT_KEPT_SAVEDS_COUNT(compiler->options))) { - FAIL_IF(push_inst(compiler, OR | S(src) | A(TMP_CALL_REG) | B(src))); - src = TMP_CALL_REG; - } - - FAIL_IF(emit_stack_frame_release(compiler, 0)); - type = SLJIT_JUMP; - } - -#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) - if ((type & 0xff) != SLJIT_CALL_REG_ARG) - FAIL_IF(call_with_args(compiler, arg_types, &src)); -#endif - - SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_ijump(compiler, type, src, srcw); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 type) -{ - sljit_s32 reg, invert; - sljit_u32 bit, from_xer; - sljit_s32 saved_op = op; - sljit_sw saved_dstw = dstw; -#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) - sljit_s32 input_flags = ((op & SLJIT_32) || op == SLJIT_MOV32) ? INT_DATA : WORD_DATA; -#else - sljit_s32 input_flags = WORD_DATA; -#endif - - CHECK_ERROR(); - CHECK(check_sljit_emit_op_flags(compiler, op, dst, dstw, type)); - ADJUST_LOCAL_OFFSET(dst, dstw); - - op = GET_OPCODE(op); - reg = (op < SLJIT_ADD && FAST_IS_REG(dst)) ? dst : TMP_REG2; - - if (op >= SLJIT_ADD && (dst & SLJIT_MEM)) - FAIL_IF(emit_op_mem(compiler, input_flags | LOAD_DATA, TMP_REG1, dst, dstw, TMP_REG1)); - - invert = 0; - bit = 0; - from_xer = 0; - - switch (type) { - case SLJIT_LESS: - case SLJIT_SIG_LESS: - break; - - case SLJIT_GREATER_EQUAL: - case SLJIT_SIG_GREATER_EQUAL: - invert = 1; - break; - - case SLJIT_GREATER: - case SLJIT_SIG_GREATER: - bit = 1; - break; - - case SLJIT_LESS_EQUAL: - case SLJIT_SIG_LESS_EQUAL: - bit = 1; - invert = 1; - break; - - case SLJIT_EQUAL: - bit = 2; - break; - - case SLJIT_NOT_EQUAL: - bit = 2; - invert = 1; - break; - - case SLJIT_OVERFLOW: - from_xer = 1; - bit = 1; - break; - - case SLJIT_NOT_OVERFLOW: - from_xer = 1; - bit = 1; - invert = 1; - break; - - case SLJIT_CARRY: - from_xer = 1; - bit = 2; - invert = (compiler->status_flags_state & SLJIT_CURRENT_FLAGS_SUB) != 0; - break; - - case SLJIT_NOT_CARRY: - from_xer = 1; - bit = 2; - invert = (compiler->status_flags_state & SLJIT_CURRENT_FLAGS_ADD) != 0; - break; - - case SLJIT_F_LESS: - case SLJIT_ORDERED_LESS: - case SLJIT_UNORDERED_OR_LESS: - bit = 4 + 0; - break; - - case SLJIT_F_GREATER_EQUAL: - case SLJIT_ORDERED_GREATER_EQUAL: - case SLJIT_UNORDERED_OR_GREATER_EQUAL: - bit = 4 + 0; - invert = 1; - break; - - case SLJIT_F_GREATER: - case SLJIT_ORDERED_GREATER: - case SLJIT_UNORDERED_OR_GREATER: - bit = 4 + 1; - break; - - case SLJIT_F_LESS_EQUAL: - case SLJIT_ORDERED_LESS_EQUAL: - case SLJIT_UNORDERED_OR_LESS_EQUAL: - bit = 4 + 1; - invert = 1; - break; - - case SLJIT_F_EQUAL: - case SLJIT_ORDERED_EQUAL: - case SLJIT_UNORDERED_OR_EQUAL: - bit = 4 + 2; - break; - - case SLJIT_F_NOT_EQUAL: - case SLJIT_ORDERED_NOT_EQUAL: - case SLJIT_UNORDERED_OR_NOT_EQUAL: - bit = 4 + 2; - invert = 1; - break; - - case SLJIT_UNORDERED: - bit = 4 + 3; - break; - - case SLJIT_ORDERED: - bit = 4 + 3; - invert = 1; - break; - - default: - SLJIT_UNREACHABLE(); - break; - } - - FAIL_IF(push_inst(compiler, (from_xer ? MFXER : MFCR) | D(reg))); - /* Simplified mnemonics: extrwi. */ - FAIL_IF(push_inst(compiler, RLWINM | S(reg) | A(reg) | RLWI_SH(1 + bit) | RLWI_MBE(31, 31))); - - if (invert) - FAIL_IF(push_inst(compiler, XORI | S(reg) | A(reg) | 0x1)); - - if (op < SLJIT_ADD) { - if (!(dst & SLJIT_MEM)) - return SLJIT_SUCCESS; - return emit_op_mem(compiler, input_flags, reg, dst, dstw, TMP_REG1); - } - - SLJIT_SKIP_CHECKS(compiler); - - if (dst & SLJIT_MEM) - return sljit_emit_op2(compiler, saved_op, dst, saved_dstw, TMP_REG1, 0, TMP_REG2, 0); - return sljit_emit_op2(compiler, saved_op, dst, 0, dst, 0, TMP_REG2, 0); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 dst_reg, - sljit_s32 src, sljit_sw srcw) -{ - CHECK_ERROR(); - CHECK(check_sljit_emit_cmov(compiler, type, dst_reg, src, srcw)); - - return sljit_emit_cmov_generic(compiler, type, dst_reg, src, srcw);; -} - -#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) - -#define EMIT_MEM_LOAD_IMM(inst, mem, memw) \ - ((sljit_s16)(memw) > SIMM_MAX - SSIZE_OF(sw)) - -#else /* !SLJIT_CONFIG_PPC_32 */ - -#define EMIT_MEM_LOAD_IMM(inst, mem, memw) \ - ((((inst) & INT_ALIGNED) && ((memw) & 0x3) != 0) \ - || ((sljit_s16)(memw) > SIMM_MAX - SSIZE_OF(sw)) \ - || ((memw) > 0x7fff7fffl || (memw) < -0x80000000l)) \ - -#endif /* SLJIT_CONFIG_PPC_32 */ - -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) -{ - sljit_ins inst; - - CHECK_ERROR(); - CHECK(check_sljit_emit_mem(compiler, type, reg, mem, memw)); - - if (!(reg & REG_PAIR_MASK)) - return sljit_emit_mem_unaligned(compiler, type, reg, mem, memw); - - ADJUST_LOCAL_OFFSET(mem, memw); - - inst = data_transfer_insts[WORD_DATA | ((type & SLJIT_MEM_STORE) ? 0 : LOAD_DATA)]; - - if (SLJIT_UNLIKELY(mem & OFFS_REG_MASK)) { - memw &= 0x3; - - if (memw != 0) { - FAIL_IF(push_inst(compiler, SLWI_W(memw) | S(OFFS_REG(mem)) | A(TMP_REG1))); - FAIL_IF(push_inst(compiler, ADD | D(TMP_REG1) | A(TMP_REG1) | B(mem & REG_MASK))); - } else - FAIL_IF(push_inst(compiler, ADD | D(TMP_REG1) | A(mem & REG_MASK) | B(OFFS_REG(mem)))); - - mem = TMP_REG1; - memw = 0; - } else { - if (EMIT_MEM_LOAD_IMM(inst, mem, memw)) { - if ((mem & REG_MASK) != 0) { - SLJIT_SKIP_CHECKS(compiler); - FAIL_IF(sljit_emit_op2(compiler, SLJIT_ADD, TMP_REG1, 0, mem & REG_MASK, 0, SLJIT_IMM, memw)); - } else - FAIL_IF(load_immediate(compiler, TMP_REG1, memw)); - - memw = 0; - mem = TMP_REG1; - } else if (memw > SIMM_MAX || memw < SIMM_MIN) { - FAIL_IF(push_inst(compiler, ADDIS | D(TMP_REG1) | A(mem & REG_MASK) | IMM((memw + 0x8000) >> 16))); - - memw &= 0xffff; - mem = TMP_REG1; - } else { - memw &= 0xffff; - mem &= REG_MASK; - } - } - - SLJIT_ASSERT((memw >= 0 && memw <= SIMM_MAX - SSIZE_OF(sw)) || (memw >= 0x8000 && memw <= 0xffff)); - -#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) - inst &= (sljit_ins)~INT_ALIGNED; -#endif /* SLJIT_CONFIG_PPC_64 */ - - if (!(type & SLJIT_MEM_STORE) && mem == REG_PAIR_FIRST(reg)) { - FAIL_IF(push_inst(compiler, inst | D(REG_PAIR_SECOND(reg)) | A(mem) | IMM(memw + SSIZE_OF(sw)))); - return push_inst(compiler, inst | D(REG_PAIR_FIRST(reg)) | A(mem) | IMM(memw)); - } - - FAIL_IF(push_inst(compiler, inst | D(REG_PAIR_FIRST(reg)) | A(mem) | IMM(memw))); - return push_inst(compiler, inst | D(REG_PAIR_SECOND(reg)) | A(mem) | IMM(memw + SSIZE_OF(sw))); -} - -#undef EMIT_MEM_LOAD_IMM - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem_update(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 reg, - sljit_s32 mem, sljit_sw memw) -{ - sljit_s32 mem_flags; - sljit_ins inst; - - CHECK_ERROR(); - CHECK(check_sljit_emit_mem_update(compiler, type, reg, mem, memw)); - - if (type & SLJIT_MEM_POST) - return SLJIT_ERR_UNSUPPORTED; - - switch (type & 0xff) { - case SLJIT_MOV: - case SLJIT_MOV_P: -#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) - case SLJIT_MOV_U32: - case SLJIT_MOV_S32: - case SLJIT_MOV32: -#endif - mem_flags = WORD_DATA; - break; - -#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) - case SLJIT_MOV_U32: - case SLJIT_MOV32: - mem_flags = INT_DATA; - break; - - case SLJIT_MOV_S32: - mem_flags = INT_DATA; - - if (!(type & SLJIT_MEM_STORE) && !(type & SLJIT_32)) { - if (mem & OFFS_REG_MASK) - mem_flags |= SIGNED_DATA; - else - return SLJIT_ERR_UNSUPPORTED; - } - break; -#endif - - case SLJIT_MOV_U8: - case SLJIT_MOV_S8: - mem_flags = BYTE_DATA; - break; - - case SLJIT_MOV_U16: - mem_flags = HALF_DATA; - break; - - case SLJIT_MOV_S16: - mem_flags = HALF_DATA | SIGNED_DATA; - break; - - default: - SLJIT_UNREACHABLE(); - mem_flags = WORD_DATA; - break; - } - - if (!(type & SLJIT_MEM_STORE)) - mem_flags |= LOAD_DATA; - - if (SLJIT_UNLIKELY(mem & OFFS_REG_MASK)) { - if (memw != 0) - return SLJIT_ERR_UNSUPPORTED; - - if (type & SLJIT_MEM_SUPP) - return SLJIT_SUCCESS; - - inst = updated_data_transfer_insts[mem_flags | INDEXED]; - FAIL_IF(push_inst(compiler, INST_CODE_AND_DST(inst, 0, reg) | A(mem & REG_MASK) | B(OFFS_REG(mem)))); - } - else { - if (memw > SIMM_MAX || memw < SIMM_MIN) - return SLJIT_ERR_UNSUPPORTED; - - inst = updated_data_transfer_insts[mem_flags]; - -#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) - if ((inst & INT_ALIGNED) && (memw & 0x3) != 0) - return SLJIT_ERR_UNSUPPORTED; -#endif - - if (type & SLJIT_MEM_SUPP) - return SLJIT_SUCCESS; - - FAIL_IF(push_inst(compiler, INST_CODE_AND_DST(inst, 0, reg) | A(mem & REG_MASK) | IMM(memw))); - } - - if ((mem_flags & LOAD_DATA) && (type & 0xff) == SLJIT_MOV_S8) - return push_inst(compiler, EXTSB | S(reg) | A(reg)); - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fmem_update(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 freg, - sljit_s32 mem, sljit_sw memw) -{ - sljit_s32 mem_flags; - sljit_ins inst; - - CHECK_ERROR(); - CHECK(check_sljit_emit_fmem_update(compiler, type, freg, mem, memw)); - - if (type & SLJIT_MEM_POST) - return SLJIT_ERR_UNSUPPORTED; - - if (SLJIT_UNLIKELY(mem & OFFS_REG_MASK)) { - if (memw != 0) - return SLJIT_ERR_UNSUPPORTED; - } - else { - if (memw > SIMM_MAX || memw < SIMM_MIN) - return SLJIT_ERR_UNSUPPORTED; - } - - if (type & SLJIT_MEM_SUPP) - return SLJIT_SUCCESS; - - mem_flags = FLOAT_DATA(type); - - if (!(type & SLJIT_MEM_STORE)) - mem_flags |= LOAD_DATA; - - if (SLJIT_UNLIKELY(mem & OFFS_REG_MASK)) { - inst = updated_data_transfer_insts[mem_flags | INDEXED]; - return push_inst(compiler, INST_CODE_AND_DST(inst, DOUBLE_DATA, freg) | A(mem & REG_MASK) | B(OFFS_REG(mem))); - } - - inst = updated_data_transfer_insts[mem_flags]; - return push_inst(compiler, INST_CODE_AND_DST(inst, DOUBLE_DATA, freg) | A(mem & REG_MASK) | IMM(memw)); -} - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value) -{ - struct sljit_const *const_; - sljit_s32 dst_r; - - CHECK_ERROR_PTR(); - 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; - PTR_FAIL_IF(emit_const(compiler, dst_r, init_value)); - - if (dst & SLJIT_MEM) - PTR_FAIL_IF(emit_op(compiler, SLJIT_MOV, WORD_DATA, dst, dstw, TMP_REG1, 0, TMP_REG2, 0)); - - return const_; -} - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label* sljit_emit_put_label(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw) -{ - struct sljit_put_label *put_label; - sljit_s32 dst_r; - - CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_put_label(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); - - dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2; -#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) - PTR_FAIL_IF(emit_const(compiler, dst_r, 0)); -#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; -} - -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset) -{ - sljit_set_jump_addr(addr, (sljit_uw)new_constant, executable_offset); -} diff --git a/modules/regex/pcre2/src/sljit/sljitNativeRISCV_32.c b/modules/regex/pcre2/src/sljit/sljitNativeRISCV_32.c deleted file mode 100644 index b38e692..0000000 --- a/modules/regex/pcre2/src/sljit/sljitNativeRISCV_32.c +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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. - */ - -static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_r, sljit_sw imm, sljit_s32 tmp_r) -{ - SLJIT_UNUSED_ARG(tmp_r); - SLJIT_ASSERT(dst_r != tmp_r); - - if (imm <= SIMM_MAX && imm >= SIMM_MIN) - return push_inst(compiler, ADDI | RD(dst_r) | RS1(TMP_ZERO) | IMM_I(imm)); - - if (imm & 0x800) - imm += 0x1000; - - FAIL_IF(push_inst(compiler, LUI | RD(dst_r) | (sljit_ins)(imm & ~0xfff))); - - if ((imm & 0xfff) == 0) - return SLJIT_SUCCESS; - - return push_inst(compiler, ADDI | RD(dst_r) | RS1(dst_r) | IMM_I(imm)); -} - -static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw init_value, sljit_ins last_ins) -{ - if ((init_value & 0x800) != 0) - init_value += 0x1000; - - FAIL_IF(push_inst(compiler, LUI | RD(dst) | (sljit_ins)(init_value & ~0xfff))); - return push_inst(compiler, last_ins | RS1(dst) | IMM_I(init_value)); -} - -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset) -{ - sljit_ins *inst = (sljit_ins*)addr; - SLJIT_UNUSED_ARG(executable_offset); - - if ((new_target & 0x800) != 0) - new_target += 0x1000; - - SLJIT_UPDATE_WX_FLAGS(inst, inst + 5, 0); - - SLJIT_ASSERT((inst[0] & 0x7f) == LUI); - inst[0] = (inst[0] & 0xfff) | (sljit_ins)((sljit_sw)new_target & ~0xfff); - SLJIT_ASSERT((inst[1] & 0x707f) == ADDI || (inst[1] & 0x707f) == JALR); - inst[1] = (inst[1] & 0xfffff) | IMM_I(new_target); - - SLJIT_UPDATE_WX_FLAGS(inst, inst + 5, 1); - inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset); - SLJIT_CACHE_FLUSH(inst, inst + 5); -} diff --git a/modules/regex/pcre2/src/sljit/sljitNativeRISCV_64.c b/modules/regex/pcre2/src/sljit/sljitNativeRISCV_64.c deleted file mode 100644 index 32cec78..0000000 --- a/modules/regex/pcre2/src/sljit/sljitNativeRISCV_64.c +++ /dev/null @@ -1,183 +0,0 @@ -/* - * 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. - */ - -static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_r, sljit_sw imm, sljit_s32 tmp_r) -{ - sljit_sw high; - - SLJIT_ASSERT(dst_r != tmp_r); - - if (imm <= SIMM_MAX && imm >= SIMM_MIN) - return push_inst(compiler, ADDI | RD(dst_r) | RS1(TMP_ZERO) | IMM_I(imm)); - - if (imm <= 0x7fffffffl && imm >= S32_MIN) { - if (imm > S32_MAX) { - SLJIT_ASSERT((imm & 0x800) != 0); - FAIL_IF(push_inst(compiler, LUI | RD(dst_r) | (sljit_ins)0x80000000u)); - return push_inst(compiler, XORI | RD(dst_r) | RS1(dst_r) | IMM_I(imm)); - } - - if ((imm & 0x800) != 0) - imm += 0x1000; - - FAIL_IF(push_inst(compiler, LUI | RD(dst_r) | (sljit_ins)(imm & ~0xfff))); - - if ((imm & 0xfff) == 0) - return SLJIT_SUCCESS; - - return push_inst(compiler, ADDI | RD(dst_r) | RS1(dst_r) | IMM_I(imm)); - } - - /* Trailing zeroes could be used to produce shifted immediates. */ - - if (imm <= 0x7ffffffffffl && imm >= -0x80000000000l) { - high = imm >> 12; - - if (imm & 0x800) - high = ~high; - - if (high > S32_MAX) { - SLJIT_ASSERT((high & 0x800) != 0); - FAIL_IF(push_inst(compiler, LUI | RD(dst_r) | (sljit_ins)0x80000000u)); - FAIL_IF(push_inst(compiler, XORI | RD(dst_r) | RS1(dst_r) | IMM_I(high))); - } else { - if ((high & 0x800) != 0) - high += 0x1000; - - FAIL_IF(push_inst(compiler, LUI | RD(dst_r) | (sljit_ins)(high & ~0xfff))); - - if ((high & 0xfff) != 0) - FAIL_IF(push_inst(compiler, ADDI | RD(dst_r) | RS1(dst_r) | IMM_I(high))); - } - - FAIL_IF(push_inst(compiler, SLLI | RD(dst_r) | RS1(dst_r) | IMM_I(12))); - - if ((imm & 0xfff) != 0) - return push_inst(compiler, XORI | RD(dst_r) | RS1(dst_r) | IMM_I(imm)); - - return SLJIT_SUCCESS; - } - - high = imm >> 32; - imm = (sljit_s32)imm; - - if ((imm & 0x80000000l) != 0) - high = ~high; - - if (high <= 0x7ffff && high >= -0x80000) { - FAIL_IF(push_inst(compiler, LUI | RD(tmp_r) | (sljit_ins)(high << 12))); - high = 0x1000; - } else { - if ((high & 0x800) != 0) - high += 0x1000; - - FAIL_IF(push_inst(compiler, LUI | RD(tmp_r) | (sljit_ins)(high & ~0xfff))); - high &= 0xfff; - } - - if (imm <= SIMM_MAX && imm >= SIMM_MIN) { - FAIL_IF(push_inst(compiler, ADDI | RD(dst_r) | RS1(TMP_ZERO) | IMM_I(imm))); - imm = 0; - } else if (imm > S32_MAX) { - SLJIT_ASSERT((imm & 0x800) != 0); - - FAIL_IF(push_inst(compiler, LUI | RD(dst_r) | (sljit_ins)0x80000000u)); - imm = 0x1000 | (imm & 0xfff); - } else { - if ((imm & 0x800) != 0) - imm += 0x1000; - - FAIL_IF(push_inst(compiler, LUI | RD(dst_r) | (sljit_ins)(imm & ~0xfff))); - imm &= 0xfff; - } - - if ((high & 0xfff) != 0) - FAIL_IF(push_inst(compiler, ADDI | RD(tmp_r) | RS1(tmp_r) | IMM_I(high))); - - if (imm & 0x1000) - FAIL_IF(push_inst(compiler, XORI | RD(dst_r) | RS1(dst_r) | IMM_I(imm))); - else if (imm != 0) - FAIL_IF(push_inst(compiler, ADDI | RD(dst_r) | RS1(dst_r) | IMM_I(imm))); - - FAIL_IF(push_inst(compiler, SLLI | RD(tmp_r) | RS1(tmp_r) | IMM_I((high & 0x1000) ? 20 : 32))); - return push_inst(compiler, XOR | RD(dst_r) | RS1(dst_r) | RS2(tmp_r)); -} - -static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw init_value, sljit_ins last_ins) -{ - sljit_sw high; - - if ((init_value & 0x800) != 0) - init_value += 0x1000; - - high = init_value >> 32; - - if ((init_value & 0x80000000l) != 0) - high = ~high; - - if ((high & 0x800) != 0) - high += 0x1000; - - FAIL_IF(push_inst(compiler, LUI | RD(TMP_REG3) | (sljit_ins)(high & ~0xfff))); - FAIL_IF(push_inst(compiler, ADDI | RD(TMP_REG3) | RS1(TMP_REG3) | IMM_I(high))); - FAIL_IF(push_inst(compiler, LUI | RD(dst) | (sljit_ins)(init_value & ~0xfff))); - FAIL_IF(push_inst(compiler, SLLI | RD(TMP_REG3) | RS1(TMP_REG3) | IMM_I(32))); - FAIL_IF(push_inst(compiler, XOR | RD(dst) | RS1(dst) | RS2(TMP_REG3))); - return push_inst(compiler, last_ins | RS1(dst) | IMM_I(init_value)); -} - -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset) -{ - sljit_ins *inst = (sljit_ins*)addr; - sljit_sw high; - SLJIT_UNUSED_ARG(executable_offset); - - if ((new_target & 0x800) != 0) - new_target += 0x1000; - - high = (sljit_sw)new_target >> 32; - - if ((new_target & 0x80000000l) != 0) - high = ~high; - - if ((high & 0x800) != 0) - high += 0x1000; - - SLJIT_UPDATE_WX_FLAGS(inst, inst + 5, 0); - - SLJIT_ASSERT((inst[0] & 0x7f) == LUI); - inst[0] = (inst[0] & 0xfff) | (sljit_ins)(high & ~0xfff); - SLJIT_ASSERT((inst[1] & 0x707f) == ADDI); - inst[1] = (inst[1] & 0xfffff) | IMM_I(high); - SLJIT_ASSERT((inst[2] & 0x7f) == LUI); - inst[2] = (inst[2] & 0xfff) | (sljit_ins)((sljit_sw)new_target & ~0xfff); - SLJIT_ASSERT((inst[5] & 0x707f) == ADDI || (inst[5] & 0x707f) == JALR); - inst[5] = (inst[5] & 0xfffff) | IMM_I(new_target); - SLJIT_UPDATE_WX_FLAGS(inst, inst + 5, 1); - - inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset); - SLJIT_CACHE_FLUSH(inst, inst + 5); -} diff --git a/modules/regex/pcre2/src/sljit/sljitNativeRISCV_common.c b/modules/regex/pcre2/src/sljit/sljitNativeRISCV_common.c deleted file mode 100644 index 58a48c6..0000000 --- a/modules/regex/pcre2/src/sljit/sljitNativeRISCV_common.c +++ /dev/null @@ -1,2762 +0,0 @@ -/* - * 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 const char* sljit_get_platform_name(void) -{ -#if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) - return "RISC-V-32" SLJIT_CPUINFO; -#else /* !SLJIT_CONFIG_RISCV_32 */ - return "RISC-V-64" SLJIT_CPUINFO; -#endif /* SLJIT_CONFIG_RISCV_32 */ -} - -/* Length of an instruction word - Both for riscv-32 and riscv-64 */ -typedef sljit_u32 sljit_ins; - -#define TMP_REG1 (SLJIT_NUMBER_OF_REGISTERS + 2) -#define TMP_REG2 (SLJIT_NUMBER_OF_REGISTERS + 3) -#define TMP_REG3 (SLJIT_NUMBER_OF_REGISTERS + 4) -#define TMP_ZERO 0 - -/* Flags are kept in volatile registers. */ -#define EQUAL_FLAG (SLJIT_NUMBER_OF_REGISTERS + 5) -#define RETURN_ADDR_REG TMP_REG2 -#define OTHER_FLAG (SLJIT_NUMBER_OF_REGISTERS + 6) - -#define TMP_FREG1 (SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1) -#define TMP_FREG2 (SLJIT_NUMBER_OF_FLOAT_REGISTERS + 2) - -static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 7] = { - 0, 10, 11, 12, 13, 14, 15, 16, 17, 29, 30, 31, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 9, 8, 2, 6, 1, 7, 5, 28 -}; - -static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 3] = { - 0, 10, 11, 12, 13, 14, 15, 16, 17, 2, 3, 4, 5, 6, 7, 28, 29, 30, 31, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 9, 8, 0, 1, -}; - -/* --------------------------------------------------------------------- */ -/* Instrucion forms */ -/* --------------------------------------------------------------------- */ - -#define RD(rd) ((sljit_ins)reg_map[rd] << 7) -#define RS1(rs1) ((sljit_ins)reg_map[rs1] << 15) -#define RS2(rs2) ((sljit_ins)reg_map[rs2] << 20) -#define FRD(rd) ((sljit_ins)freg_map[rd] << 7) -#define FRS1(rs1) ((sljit_ins)freg_map[rs1] << 15) -#define FRS2(rs2) ((sljit_ins)freg_map[rs2] << 20) -#define IMM_I(imm) ((sljit_ins)(imm) << 20) -#define IMM_S(imm) ((((sljit_ins)(imm) & 0xfe0) << 20) | (((sljit_ins)(imm) & 0x1f) << 7)) - -/* Represents funct(i) parts of the instructions. */ -#define OPC(o) ((sljit_ins)(o)) -#define F3(f) ((sljit_ins)(f) << 12) -#define F12(f) ((sljit_ins)(f) << 20) -#define F7(f) ((sljit_ins)(f) << 25) - -#define ADD (F7(0x0) | F3(0x0) | OPC(0x33)) -#define ADDI (F3(0x0) | OPC(0x13)) -#define AND (F7(0x0) | F3(0x7) | OPC(0x33)) -#define ANDI (F3(0x7) | OPC(0x13)) -#define AUIPC (OPC(0x17)) -#define BEQ (F3(0x0) | OPC(0x63)) -#define BNE (F3(0x1) | OPC(0x63)) -#define BLT (F3(0x4) | OPC(0x63)) -#define BGE (F3(0x5) | OPC(0x63)) -#define BLTU (F3(0x6) | OPC(0x63)) -#define BGEU (F3(0x7) | OPC(0x63)) -#define DIV (F7(0x1) | F3(0x4) | OPC(0x33)) -#define DIVU (F7(0x1) | F3(0x5) | OPC(0x33)) -#define EBREAK (F12(0x1) | F3(0x0) | OPC(0x73)) -#define FADD_S (F7(0x0) | F3(0x7) | OPC(0x53)) -#define FDIV_S (F7(0xc) | F3(0x7) | OPC(0x53)) -#define FEQ_S (F7(0x50) | F3(0x2) | OPC(0x53)) -#define FLD (F3(0x3) | OPC(0x7)) -#define FLE_S (F7(0x50) | F3(0x0) | OPC(0x53)) -#define FLT_S (F7(0x50) | F3(0x1) | OPC(0x53)) -#define FSD (F3(0x3) | OPC(0x27)) -/* These conversion opcodes are partly defined. */ -#define FCVT_S_D (F7(0x20) | OPC(0x53)) -#define FCVT_S_W (F7(0x68) | OPC(0x53)) -#define FCVT_W_S (F7(0x60) | F3(0x1) | OPC(0x53)) -#define FMUL_S (F7(0x8) | F3(0x7) | OPC(0x53)) -#define FSGNJ_S (F7(0x10) | F3(0x0) | OPC(0x53)) -#define FSGNJN_S (F7(0x10) | F3(0x1) | OPC(0x53)) -#define FSGNJX_S (F7(0x10) | F3(0x2) | OPC(0x53)) -#define FSUB_S (F7(0x4) | F3(0x7) | OPC(0x53)) -#define JAL (OPC(0x6f)) -#define JALR (F3(0x0) | OPC(0x67)) -#define LD (F3(0x3) | OPC(0x3)) -#define LUI (OPC(0x37)) -#define LW (F3(0x2) | OPC(0x3)) -#define MUL (F7(0x1) | F3(0x0) | OPC(0x33)) -#define MULH (F7(0x1) | F3(0x1) | OPC(0x33)) -#define MULHU (F7(0x1) | F3(0x3) | OPC(0x33)) -#define OR (F7(0x0) | F3(0x6) | OPC(0x33)) -#define ORI (F3(0x6) | OPC(0x13)) -#define REM (F7(0x1) | F3(0x6) | OPC(0x33)) -#define REMU (F7(0x1) | F3(0x7) | OPC(0x33)) -#define SD (F3(0x3) | OPC(0x23)) -#define SLL (F7(0x0) | F3(0x1) | OPC(0x33)) -#define SLLI (IMM_I(0x0) | F3(0x1) | OPC(0x13)) -#define SLT (F7(0x0) | F3(0x2) | OPC(0x33)) -#define SLTI (F3(0x2) | OPC(0x13)) -#define SLTU (F7(0x0) | F3(0x3) | OPC(0x33)) -#define SLTUI (F3(0x3) | OPC(0x13)) -#define SRL (F7(0x0) | F3(0x5) | OPC(0x33)) -#define SRLI (IMM_I(0x0) | F3(0x5) | OPC(0x13)) -#define SRA (F7(0x20) | F3(0x5) | OPC(0x33)) -#define SRAI (IMM_I(0x400) | F3(0x5) | OPC(0x13)) -#define SUB (F7(0x20) | F3(0x0) | OPC(0x33)) -#define SW (F3(0x2) | OPC(0x23)) -#define XOR (F7(0x0) | F3(0x4) | OPC(0x33)) -#define XORI (F3(0x4) | OPC(0x13)) - -#define SIMM_MAX (0x7ff) -#define SIMM_MIN (-0x800) -#define BRANCH_MAX (0xfff) -#define BRANCH_MIN (-0x1000) -#define JUMP_MAX (0xfffff) -#define JUMP_MIN (-0x100000) - -#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64) -#define S32_MAX (0x7ffff7ffl) -#define S32_MIN (-0x80000000l) -#define S44_MAX (0x7fffffff7ffl) -#define S52_MAX (0x7ffffffffffffl) -#endif - -static sljit_s32 push_inst(struct sljit_compiler *compiler, sljit_ins ins) -{ - sljit_ins *ptr = (sljit_ins*)ensure_buf(compiler, sizeof(sljit_ins)); - FAIL_IF(!ptr); - *ptr = ins; - compiler->size++; - return SLJIT_SUCCESS; -} - -static sljit_s32 push_imm_s_inst(struct sljit_compiler *compiler, sljit_ins ins, sljit_sw imm) -{ - return push_inst(compiler, ins | IMM_S(imm)); -} - -static SLJIT_INLINE sljit_ins* detect_jump_type(struct sljit_jump *jump, sljit_ins *code, sljit_sw executable_offset) -{ - sljit_sw diff; - sljit_uw target_addr; - sljit_ins *inst; - - inst = (sljit_ins *)jump->addr; - - 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); - 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[0] = (inst[0] & 0x1fff07f) ^ 0x1000; - jump->addr = (sljit_uw)inst; - return inst; - } - - inst++; - diff -= SSIZE_OF(ins); - } - - if (diff >= JUMP_MIN && diff <= JUMP_MAX) { - if (jump->flags & IS_COND) { -#if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) - inst[-1] -= (sljit_ins)(1 * sizeof(sljit_ins)) << 7; -#else - inst[-1] -= (sljit_ins)(5 * sizeof(sljit_ins)) << 7; -#endif - } - - jump->flags |= PATCH_J; - return inst; - } - -#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64) - if (diff >= S32_MIN && diff <= S32_MAX) { - if (jump->flags & IS_COND) - inst[-1] -= (sljit_ins)(4 * sizeof(sljit_ins)) << 7; - - jump->flags |= PATCH_REL32; - inst[1] = inst[0]; - return inst + 1; - } - - if (target_addr <= (sljit_uw)S32_MAX) { - if (jump->flags & IS_COND) - inst[-1] -= (sljit_ins)(4 * sizeof(sljit_ins)) << 7; - - jump->flags |= PATCH_ABS32; - inst[1] = inst[0]; - return inst + 1; - } - - if (target_addr <= S44_MAX) { - if (jump->flags & IS_COND) - inst[-1] -= (sljit_ins)(2 * sizeof(sljit_ins)) << 7; - - jump->flags |= PATCH_ABS44; - inst[3] = inst[0]; - return inst + 3; - } - - if (target_addr <= S52_MAX) { - if (jump->flags & IS_COND) - inst[-1] -= (sljit_ins)(1 * sizeof(sljit_ins)) << 7; - - jump->flags |= PATCH_ABS52; - inst[4] = inst[0]; - return inst + 4; - } -#endif - -exit: -#if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) - inst[1] = inst[0]; - return inst + 1; -#else - inst[5] = inst[0]; - return inst + 5; -#endif -} - -#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) -{ - if (max_label <= (sljit_uw)S32_MAX) { - put_label->flags = PATCH_ABS32; - return 1; - } - - if (max_label <= S44_MAX) { - put_label->flags = PATCH_ABS44; - return 3; - } - - if (max_label <= S52_MAX) { - put_label->flags = PATCH_ABS52; - return 4; - } - - put_label->flags = 0; - return 5; -} - -#endif /* SLJIT_CONFIG_RISCV_64 */ - -static SLJIT_INLINE void load_addr_to_reg(void *dst, sljit_u32 reg) -{ - struct sljit_jump *jump = NULL; - struct sljit_put_label *put_label; - sljit_uw flags; - sljit_ins *inst; -#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64) - sljit_sw high; -#endif - 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_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 ((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); -#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); - } 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); - } 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); - } - - inst[2] = SLLI | RD(reg) | RS1(reg) | IMM_I(12); - inst += 2; - } else { - high = (sljit_sw)addr >> 32; - - if ((addr & 0x80000000l) != 0) - high = ~high; - - if ((high & 0x800) != 0) - high += 0x1000; - - if (flags & PATCH_ABS52) { - SLJIT_ASSERT(addr <= S52_MAX); - inst[0] = LUI | RD(TMP_REG3) | (sljit_ins)(high << 12); - } else { - inst[0] = LUI | RD(TMP_REG3) | (sljit_ins)(high & ~0xfff); - inst[1] = ADDI | RD(TMP_REG3) | RS1(TMP_REG3) | IMM_I(high); - inst++; - } - - 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; - } -#endif /* !SLJIT_CONFIG_RISCV_32 */ - - if (jump != NULL) { - SLJIT_ASSERT((inst[1] & 0x707f) == JALR); - inst[1] = (inst[1] & 0xfffff) | IMM_I(addr); - } else - inst[1] = ADDI | RD(reg) | RS1(reg) | IMM_I(addr); -} - -SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler) -{ - struct sljit_memory_fragment *buf; - sljit_ins *code; - sljit_ins *code_ptr; - sljit_ins *buf_ptr; - sljit_ins *buf_end; - sljit_uw word_count; - sljit_uw next_addr; - 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); - 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; - - 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) { - 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); - label->size = (sljit_uw)(code_ptr - code); - label = label->next; - } - if (jump && jump->addr == word_count) { -#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); - jump = jump->next; - } - if (const_ && const_->addr == word_count) { - const_->addr = (sljit_uw)code_ptr; - const_ = const_->next; - } - 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); - } - code_ptr++; - word_count++; - } while (buf_ptr < buf_end); - - buf = buf->next; - } while (buf); - - if (label && label->size == word_count) { - label->addr = (sljit_uw)code_ptr; - label->size = (sljit_uw)(code_ptr - code); - label = label->next; - } - - 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); - break; - } - - addr = (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target; - buf_ptr = (sljit_ins *)jump->addr; - addr -= (sljit_uw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset); - - if (jump->flags & PATCH_B) { - SLJIT_ASSERT((sljit_sw)addr >= BRANCH_MIN && (sljit_sw)addr <= BRANCH_MAX); - addr = ((addr & 0x800) >> 4) | ((addr & 0x1e) << 7) | ((addr & 0x7e0) << 20) | ((addr & 0x1000) << 19); - buf_ptr[0] |= (sljit_ins)addr; - 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; - } - - compiler->error = SLJIT_ERR_COMPILED; - compiler->executable_offset = executable_offset; - compiler->executable_size = (sljit_uw)(code_ptr - code) * sizeof(sljit_ins); - - code = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(code, executable_offset); - code_ptr = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset); - - SLJIT_CACHE_FLUSH(code, code_ptr); - SLJIT_UPDATE_WX_FLAGS(code, code_ptr, 1); - return code; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type) -{ - switch (feature_type) { - case SLJIT_HAS_FPU: - case SLJIT_HAS_ZERO_REGISTER: - return 1; - default: - return 0; - } -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_cmp_info(sljit_s32 type) -{ - return (type >= SLJIT_ORDERED_EQUAL && type <= SLJIT_ORDERED_LESS_EQUAL); -} - -/* --------------------------------------------------------------------- */ -/* Entry, exit */ -/* --------------------------------------------------------------------- */ - -/* Creates an index in data_transfer_insts array. */ -#define LOAD_DATA 0x01 -#define WORD_DATA 0x00 -#define BYTE_DATA 0x02 -#define HALF_DATA 0x04 -#define INT_DATA 0x06 -#define SIGNED_DATA 0x08 -/* Separates integer and floating point registers */ -#define GPR_REG 0x0f -#define DOUBLE_DATA 0x10 -#define SINGLE_DATA 0x12 - -#define MEM_MASK 0x1f - -#define ARG_TEST 0x00020 -#define ALT_KEEP_CACHE 0x00040 -#define CUMULATIVE_OP 0x00080 -#define IMM_OP 0x00100 -#define MOVE_OP 0x00200 -#define SRC2_IMM 0x00400 - -#define UNUSED_DEST 0x00800 -#define REG_DEST 0x01000 -#define REG1_SOURCE 0x02000 -#define REG2_SOURCE 0x04000 -#define SLOW_SRC1 0x08000 -#define SLOW_SRC2 0x10000 -#define SLOW_DEST 0x20000 - -#if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) -#define STACK_STORE SW -#define STACK_LOAD LW -#else -#define STACK_STORE SD -#define STACK_LOAD LD -#endif - -#if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) -#include "sljitNativeRISCV_32.c" -#else -#include "sljitNativeRISCV_64.c" -#endif - -#define STACK_MAX_DISTANCE (-SIMM_MIN) - -static sljit_s32 emit_op_mem(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg, sljit_sw argw); - -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, - sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size) -{ - sljit_s32 i, tmp, offset; - sljit_s32 saved_arg_count = SLJIT_KEPT_SAVEDS_COUNT(options); - - CHECK_ERROR(); - CHECK(check_sljit_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size)); - set_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size); - - local_size += GET_SAVED_REGISTERS_SIZE(scratches, saveds - saved_arg_count, 1); -#if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) - if (fsaveds > 0 || fscratches >= SLJIT_FIRST_SAVED_FLOAT_REG) { - if ((local_size & SSIZE_OF(sw)) != 0) - local_size += SSIZE_OF(sw); - local_size += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, sizeof(sljit_f64)); - } -#else - local_size += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, sizeof(sljit_f64)); -#endif - local_size = (local_size + SLJIT_LOCALS_OFFSET + 15) & ~0xf; - compiler->local_size = local_size; - - if (local_size <= STACK_MAX_DISTANCE) { - /* Frequent case. */ - FAIL_IF(push_inst(compiler, ADDI | RD(SLJIT_SP) | RS1(SLJIT_SP) | IMM_I(-local_size))); - offset = local_size - SSIZE_OF(sw); - local_size = 0; - } else { - FAIL_IF(push_inst(compiler, ADDI | RD(SLJIT_SP) | RS1(SLJIT_SP) | IMM_I(STACK_MAX_DISTANCE))); - local_size -= STACK_MAX_DISTANCE; - - if (local_size > STACK_MAX_DISTANCE) - FAIL_IF(load_immediate(compiler, TMP_REG1, local_size, TMP_REG3)); - offset = STACK_MAX_DISTANCE - SSIZE_OF(sw); - } - - FAIL_IF(push_imm_s_inst(compiler, STACK_STORE | RS1(SLJIT_SP) | RS2(RETURN_ADDR_REG), offset)); - - tmp = SLJIT_S0 - saveds; - for (i = SLJIT_S0 - saved_arg_count; i > tmp; i--) { - offset -= SSIZE_OF(sw); - FAIL_IF(push_imm_s_inst(compiler, STACK_STORE | RS1(SLJIT_SP) | RS2(i), offset)); - } - - for (i = scratches; i >= SLJIT_FIRST_SAVED_REG; i--) { - offset -= SSIZE_OF(sw); - FAIL_IF(push_imm_s_inst(compiler, STACK_STORE | RS1(SLJIT_SP) | RS2(i), offset)); - } - -#if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) - /* This alignment is valid because offset is not used after storing FPU regs. */ - if ((offset & SSIZE_OF(sw)) != 0) - offset -= SSIZE_OF(sw); -#endif - - tmp = SLJIT_FS0 - fsaveds; - for (i = SLJIT_FS0; i > tmp; i--) { - offset -= SSIZE_OF(f64); - FAIL_IF(push_imm_s_inst(compiler, FSD | RS1(SLJIT_SP) | FRS2(i), offset)); - } - - for (i = fscratches; i >= SLJIT_FIRST_SAVED_FLOAT_REG; i--) { - offset -= SSIZE_OF(f64); - FAIL_IF(push_imm_s_inst(compiler, FSD | RS1(SLJIT_SP) | FRS2(i), offset)); - } - - if (local_size > STACK_MAX_DISTANCE) - FAIL_IF(push_inst(compiler, SUB | RD(SLJIT_SP) | RS1(SLJIT_SP) | RS2(TMP_REG1))); - else if (local_size > 0) - FAIL_IF(push_inst(compiler, ADDI | RD(SLJIT_SP) | RS1(SLJIT_SP) | IMM_I(-local_size))); - - if (options & SLJIT_ENTER_REG_ARG) - return SLJIT_SUCCESS; - - arg_types >>= SLJIT_ARG_SHIFT; - saved_arg_count = 0; - tmp = SLJIT_R0; - - while (arg_types > 0) { - if ((arg_types & SLJIT_ARG_MASK) < SLJIT_ARG_TYPE_F64) { - if (!(arg_types & SLJIT_ARG_TYPE_SCRATCH_REG)) { - FAIL_IF(push_inst(compiler, ADDI | RD(SLJIT_S0 - saved_arg_count) | RS1(tmp) | IMM_I(0))); - saved_arg_count++; - } - tmp++; - } - - arg_types >>= SLJIT_ARG_SHIFT; - } - - return SLJIT_SUCCESS; -} - -#undef STACK_MAX_DISTANCE - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(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) -{ - CHECK_ERROR(); - CHECK(check_sljit_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size)); - set_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size); - - local_size += GET_SAVED_REGISTERS_SIZE(scratches, saveds - SLJIT_KEPT_SAVEDS_COUNT(options), 1); -#if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) - if (fsaveds > 0 || fscratches >= SLJIT_FIRST_SAVED_FLOAT_REG) { - if ((local_size & SSIZE_OF(sw)) != 0) - local_size += SSIZE_OF(sw); - local_size += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, sizeof(sljit_f64)); - } -#else - local_size += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, sizeof(sljit_f64)); -#endif - compiler->local_size = (local_size + SLJIT_LOCALS_OFFSET + 15) & ~0xf; - - return SLJIT_SUCCESS; -} - -#define STACK_MAX_DISTANCE (-SIMM_MIN - 16) - -static sljit_s32 emit_stack_frame_release(struct sljit_compiler *compiler, sljit_s32 is_return_to) -{ - sljit_s32 i, tmp, offset; - sljit_s32 local_size = compiler->local_size; - - if (local_size > STACK_MAX_DISTANCE) { - local_size -= STACK_MAX_DISTANCE; - - if (local_size > STACK_MAX_DISTANCE) { - FAIL_IF(load_immediate(compiler, TMP_REG2, local_size, TMP_REG3)); - FAIL_IF(push_inst(compiler, ADD | RD(SLJIT_SP) | RS1(SLJIT_SP) | RS2(TMP_REG2))); - } else - FAIL_IF(push_inst(compiler, ADDI | RD(SLJIT_SP) | RS1(SLJIT_SP) | IMM_I(local_size))); - - local_size = STACK_MAX_DISTANCE; - } - - SLJIT_ASSERT(local_size > 0); - - offset = local_size - SSIZE_OF(sw); - if (!is_return_to) - FAIL_IF(push_inst(compiler, STACK_LOAD | RD(RETURN_ADDR_REG) | RS1(SLJIT_SP) | IMM_I(offset))); - - tmp = SLJIT_S0 - compiler->saveds; - for (i = SLJIT_S0 - SLJIT_KEPT_SAVEDS_COUNT(compiler->options); i > tmp; i--) { - offset -= SSIZE_OF(sw); - FAIL_IF(push_inst(compiler, STACK_LOAD | RD(i) | RS1(SLJIT_SP) | IMM_I(offset))); - } - - for (i = compiler->scratches; i >= SLJIT_FIRST_SAVED_REG; i--) { - offset -= SSIZE_OF(sw); - FAIL_IF(push_inst(compiler, STACK_LOAD | RD(i) | RS1(SLJIT_SP) | IMM_I(offset))); - } - -#if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) - /* This alignment is valid because offset is not used after storing FPU regs. */ - if ((offset & SSIZE_OF(sw)) != 0) - offset -= SSIZE_OF(sw); -#endif - - tmp = SLJIT_FS0 - compiler->fsaveds; - for (i = SLJIT_FS0; i > tmp; i--) { - offset -= SSIZE_OF(f64); - FAIL_IF(push_inst(compiler, FLD | FRD(i) | RS1(SLJIT_SP) | IMM_I(offset))); - } - - for (i = compiler->fscratches; i >= SLJIT_FIRST_SAVED_FLOAT_REG; i--) { - offset -= SSIZE_OF(f64); - FAIL_IF(push_inst(compiler, FLD | FRD(i) | RS1(SLJIT_SP) | IMM_I(offset))); - } - - return push_inst(compiler, ADDI | RD(SLJIT_SP) | RS1(SLJIT_SP) | IMM_I(local_size)); -} - -#undef STACK_MAX_DISTANCE - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_void(struct sljit_compiler *compiler) -{ - CHECK_ERROR(); - CHECK(check_sljit_emit_return_void(compiler)); - - FAIL_IF(emit_stack_frame_release(compiler, 0)); - return push_inst(compiler, JALR | RD(TMP_ZERO) | RS1(RETURN_ADDR_REG) | IMM_I(0)); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_to(struct sljit_compiler *compiler, - sljit_s32 src, sljit_sw srcw) -{ - CHECK_ERROR(); - CHECK(check_sljit_emit_return_to(compiler, src, srcw)); - - if (src & SLJIT_MEM) { - ADJUST_LOCAL_OFFSET(src, srcw); - FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, TMP_REG1, src, srcw)); - src = TMP_REG1; - srcw = 0; - } else if (src >= SLJIT_FIRST_SAVED_REG && src <= (SLJIT_S0 - SLJIT_KEPT_SAVEDS_COUNT(compiler->options))) { - FAIL_IF(push_inst(compiler, ADDI | RD(TMP_REG1) | RS1(src) | IMM_I(0))); - src = TMP_REG1; - srcw = 0; - } - - FAIL_IF(emit_stack_frame_release(compiler, 1)); - - SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_ijump(compiler, SLJIT_JUMP, src, srcw); -} - -/* --------------------------------------------------------------------- */ -/* Operators */ -/* --------------------------------------------------------------------- */ - -#if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) -#define ARCH_32_64(a, b) a -#else -#define ARCH_32_64(a, b) b -#endif - -static const sljit_ins data_transfer_insts[16 + 4] = { -/* u w s */ ARCH_32_64(F3(0x2) | OPC(0x23) /* sw */, F3(0x3) | OPC(0x23) /* sd */), -/* u w l */ ARCH_32_64(F3(0x2) | OPC(0x3) /* lw */, F3(0x3) | OPC(0x3) /* ld */), -/* u b s */ F3(0x0) | OPC(0x23) /* sb */, -/* u b l */ F3(0x4) | OPC(0x3) /* lbu */, -/* u h s */ F3(0x1) | OPC(0x23) /* sh */, -/* u h l */ F3(0x5) | OPC(0x3) /* lhu */, -/* u i s */ F3(0x2) | OPC(0x23) /* sw */, -/* u i l */ ARCH_32_64(F3(0x2) | OPC(0x3) /* lw */, F3(0x6) | OPC(0x3) /* lwu */), - -/* s w s */ ARCH_32_64(F3(0x2) | OPC(0x23) /* sw */, F3(0x3) | OPC(0x23) /* sd */), -/* s w l */ ARCH_32_64(F3(0x2) | OPC(0x3) /* lw */, F3(0x3) | OPC(0x3) /* ld */), -/* s b s */ F3(0x0) | OPC(0x23) /* sb */, -/* s b l */ F3(0x0) | OPC(0x3) /* lb */, -/* s h s */ F3(0x1) | OPC(0x23) /* sh */, -/* s h l */ F3(0x1) | OPC(0x3) /* lh */, -/* s i s */ F3(0x2) | OPC(0x23) /* sw */, -/* s i l */ F3(0x2) | OPC(0x3) /* lw */, - -/* d s */ F3(0x3) | OPC(0x27) /* fsd */, -/* d l */ F3(0x3) | OPC(0x7) /* fld */, -/* s s */ F3(0x2) | OPC(0x27) /* fsw */, -/* s l */ F3(0x2) | OPC(0x7) /* flw */, -}; - -#undef ARCH_32_64 - -static sljit_s32 push_mem_inst(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 base, sljit_sw offset) -{ - sljit_ins ins; - - SLJIT_ASSERT(FAST_IS_REG(base) && offset <= 0xfff && offset >= SIMM_MIN); - - ins = data_transfer_insts[flags & MEM_MASK] | RS1(base); - if (flags & LOAD_DATA) - ins |= ((flags & MEM_MASK) <= GPR_REG ? RD(reg) : FRD(reg)) | IMM_I(offset); - else - ins |= ((flags & MEM_MASK) <= GPR_REG ? RS2(reg) : FRS2(reg)) | IMM_S(offset); - - return push_inst(compiler, ins); -} - -/* 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) { - /* Works for both absoulte and relative addresses. */ - if (SLJIT_UNLIKELY(flags & ARG_TEST)) - return 1; - - FAIL_IF(push_mem_inst(compiler, flags, reg, arg & REG_MASK, argw)); - return -1; - } - return 0; -} - -#define TO_ARGW_HI(argw) (((argw) & ~0xfff) + (((argw) & 0x800) ? 0x1000 : 0)) - -/* See getput_arg below. - Note: can_cache is called only for binary operators. */ -static sljit_s32 can_cache(sljit_s32 arg, sljit_sw argw, sljit_s32 next_arg, sljit_sw next_argw) -{ - SLJIT_ASSERT((arg & SLJIT_MEM) && (next_arg & SLJIT_MEM)); - - /* Simple operation except for updates. */ - if (arg & OFFS_REG_MASK) { - argw &= 0x3; - next_argw &= 0x3; - if (argw && argw == next_argw && (arg == next_arg || (arg & OFFS_REG_MASK) == (next_arg & OFFS_REG_MASK))) - return 1; - return 0; - } - - if (arg == next_arg) { - if (((next_argw - argw) <= SIMM_MAX && (next_argw - argw) >= SIMM_MIN) - || TO_ARGW_HI(argw) == TO_ARGW_HI(next_argw)) - return 1; - return 0; - } - - return 0; -} - -/* Emit the necessary instructions. See can_cache above. */ -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_sw offset, argw_hi; - - SLJIT_ASSERT(arg & SLJIT_MEM); - if (!(next_arg & SLJIT_MEM)) { - next_arg = 0; - 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; - - /* Using the cache. */ - if (argw == compiler->cache_argw) { - if (arg == compiler->cache_arg) - return push_mem_inst(compiler, flags, reg, TMP_REG3, 0); - - if ((SLJIT_MEM | (arg & OFFS_REG_MASK)) == compiler->cache_arg) { - if (arg == next_arg && argw == (next_argw & 0x3)) { - compiler->cache_arg = arg; - compiler->cache_argw = argw; - FAIL_IF(push_inst(compiler, ADD | RD(TMP_REG3) | RS1(TMP_REG3) | RS2(base))); - return push_mem_inst(compiler, flags, reg, TMP_REG3, 0); - } - FAIL_IF(push_inst(compiler, ADD | RD(tmp_r) | RS1(base) | RS2(TMP_REG3))); - return push_mem_inst(compiler, flags, reg, tmp_r, 0); - } - } - - if (SLJIT_UNLIKELY(argw)) { - compiler->cache_arg = SLJIT_MEM | (arg & OFFS_REG_MASK); - compiler->cache_argw = argw; - FAIL_IF(push_inst(compiler, SLLI | RD(TMP_REG3) | RS1(OFFS_REG(arg)) | IMM_I(argw))); - } - - if (arg == next_arg && argw == (next_argw & 0x3)) { - compiler->cache_arg = arg; - compiler->cache_argw = argw; - FAIL_IF(push_inst(compiler, ADD | RD(TMP_REG3) | RS1(base) | RS2(!argw ? OFFS_REG(arg) : TMP_REG3))); - tmp_r = TMP_REG3; - } - else - FAIL_IF(push_inst(compiler, ADD | RD(tmp_r) | RS1(base) | RS2(!argw ? OFFS_REG(arg) : TMP_REG3))); - return push_mem_inst(compiler, flags, reg, tmp_r, 0); - } - - if (compiler->cache_arg == arg && argw - compiler->cache_argw <= SIMM_MAX && argw - compiler->cache_argw >= SIMM_MIN) - return push_mem_inst(compiler, flags, reg, TMP_REG3, argw - compiler->cache_argw); - - if (compiler->cache_arg == SLJIT_MEM && (argw - compiler->cache_argw <= SIMM_MAX) && (argw - compiler->cache_argw >= SIMM_MIN)) { - offset = argw - compiler->cache_argw; - } else { - compiler->cache_arg = SLJIT_MEM; - - argw_hi = TO_ARGW_HI(argw); - - if (next_arg && next_argw - argw <= SIMM_MAX && next_argw - argw >= SIMM_MIN && argw_hi != TO_ARGW_HI(next_argw)) { - FAIL_IF(load_immediate(compiler, TMP_REG3, argw, tmp_r)); - compiler->cache_argw = argw; - offset = 0; - } else { - FAIL_IF(load_immediate(compiler, TMP_REG3, argw_hi, tmp_r)); - compiler->cache_argw = argw_hi; - offset = argw & 0xfff; - argw = argw_hi; - } - } - - if (!base) - return push_mem_inst(compiler, flags, reg, TMP_REG3, offset); - - if (arg == next_arg && next_argw - argw <= SIMM_MAX && next_argw - argw >= SIMM_MIN) { - compiler->cache_arg = arg; - FAIL_IF(push_inst(compiler, ADD | RD(TMP_REG3) | RS1(TMP_REG3) | RS2(base))); - return push_mem_inst(compiler, flags, reg, TMP_REG3, offset); - } - - FAIL_IF(push_inst(compiler, ADD | RD(tmp_r) | RS1(TMP_REG3) | RS2(base))); - return push_mem_inst(compiler, flags, reg, tmp_r, offset); -} - -static sljit_s32 emit_op_mem(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg, sljit_sw argw) -{ - sljit_s32 base = arg & REG_MASK; - sljit_s32 tmp_r = TMP_REG1; - - if (getput_arg_fast(compiler, flags, reg, arg, argw)) - return compiler->error; - - if ((flags & MEM_MASK) <= GPR_REG && (flags & LOAD_DATA)) - tmp_r = reg; - - if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) { - argw &= 0x3; - - if (SLJIT_UNLIKELY(argw)) { - FAIL_IF(push_inst(compiler, SLLI | RD(tmp_r) | RS1(OFFS_REG(arg)) | IMM_I(argw))); - FAIL_IF(push_inst(compiler, ADD | RD(tmp_r) | RS1(tmp_r) | RS2(base))); - } - else - FAIL_IF(push_inst(compiler, ADD | RD(tmp_r) | RS1(base) | RS2(OFFS_REG(arg)))); - - argw = 0; - } else { - FAIL_IF(load_immediate(compiler, tmp_r, TO_ARGW_HI(argw), TMP_REG3)); - - if (base != 0) - FAIL_IF(push_inst(compiler, ADD | RD(tmp_r) | RS1(tmp_r) | RS2(base))); - } - - return push_mem_inst(compiler, flags, reg, tmp_r, argw & 0xfff); -} - -static SLJIT_INLINE sljit_s32 emit_op_mem2(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg1, sljit_sw arg1w, sljit_s32 arg2, sljit_sw arg2w) -{ - if (getput_arg_fast(compiler, flags, reg, arg1, arg1w)) - return compiler->error; - return getput_arg(compiler, flags, reg, arg1, arg1w, arg2, arg2w); -} - -#if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) -#define WORD 0 -#define IMM_EXTEND(v) (IMM_I(v)) -#else /* !SLJIT_CONFIG_RISCV_32 */ -#define WORD word -#define IMM_EXTEND(v) (IMM_I((op & SLJIT_32) ? (v) : (32 + (v)))) -#endif /* SLJIT_CONFIG_RISCV_32 */ - -static sljit_s32 emit_clz_ctz(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 dst, sljit_sw src) -{ - sljit_s32 is_clz = (GET_OPCODE(op) == SLJIT_CLZ); -#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64) - sljit_ins word = (op & SLJIT_32) >> 5; - sljit_ins max = (op & SLJIT_32) ? 32 : 64; -#else /* !SLJIT_CONFIG_RISCV_64 */ - sljit_ins max = 32; -#endif /* SLJIT_CONFIG_RISCV_64 */ - - SLJIT_ASSERT(WORD == 0 || WORD == 0x8); - - /* The OTHER_FLAG is the counter. */ - FAIL_IF(push_inst(compiler, ADDI | WORD | RD(OTHER_FLAG) | RS1(TMP_ZERO) | IMM_I(max))); - - /* The TMP_REG2 is the next value. */ - if (src != TMP_REG2) - FAIL_IF(push_inst(compiler, ADDI | WORD | RD(TMP_REG2) | RS1(src) | IMM_I(0))); - - FAIL_IF(push_inst(compiler, BEQ | RS1(TMP_REG2) | RS2(TMP_ZERO) | ((sljit_ins)((is_clz ? 4 : 5) * SSIZE_OF(ins)) << 7) | ((sljit_ins)(8 * SSIZE_OF(ins)) << 20))); - - FAIL_IF(push_inst(compiler, ADDI | WORD | RD(OTHER_FLAG) | RS1(TMP_ZERO) | IMM_I(0))); - if (!is_clz) { - FAIL_IF(push_inst(compiler, ANDI | RD(TMP_REG1) | RS1(TMP_REG2) | IMM_I(1))); - FAIL_IF(push_inst(compiler, BNE | RS1(TMP_REG1) | RS2(TMP_ZERO) | ((sljit_ins)(2 * SSIZE_OF(ins)) << 7) | ((sljit_ins)(8 * SSIZE_OF(ins)) << 20))); - } else - FAIL_IF(push_inst(compiler, BLT | RS1(TMP_REG2) | RS2(TMP_ZERO) | ((sljit_ins)(2 * SSIZE_OF(ins)) << 7) | ((sljit_ins)(8 * SSIZE_OF(ins)) << 20))); - - /* The TMP_REG1 is the next shift. */ - FAIL_IF(push_inst(compiler, ADDI | WORD | RD(TMP_REG1) | RS1(TMP_ZERO) | IMM_I(max))); - - FAIL_IF(push_inst(compiler, ADDI | WORD | RD(EQUAL_FLAG) | RS1(TMP_REG2) | IMM_I(0))); - FAIL_IF(push_inst(compiler, SRLI | WORD | RD(TMP_REG1) | RS1(TMP_REG1) | IMM_I(1))); - - FAIL_IF(push_inst(compiler, (is_clz ? SRL : SLL) | WORD | RD(TMP_REG2) | RS1(EQUAL_FLAG) | RS2(TMP_REG1))); - FAIL_IF(push_inst(compiler, BNE | RS1(TMP_REG2) | RS2(TMP_ZERO) | ((sljit_ins)0xfe000e80 - ((2 * SSIZE_OF(ins)) << 7)))); - FAIL_IF(push_inst(compiler, ADDI | WORD | RD(TMP_REG2) | RS1(TMP_REG1) | IMM_I(-1))); - FAIL_IF(push_inst(compiler, (is_clz ? SRL : SLL) | WORD | RD(TMP_REG2) | RS1(EQUAL_FLAG) | RS2(TMP_REG2))); - FAIL_IF(push_inst(compiler, OR | RD(OTHER_FLAG) | RS1(OTHER_FLAG) | RS2(TMP_REG1))); - FAIL_IF(push_inst(compiler, BEQ | RS1(TMP_REG2) | RS2(TMP_ZERO) | ((sljit_ins)0xfe000e80 - ((5 * SSIZE_OF(ins)) << 7)))); - - return push_inst(compiler, ADDI | WORD | RD(dst) | RS1(OTHER_FLAG) | IMM_I(0)); -} - -#define EMIT_LOGICAL(op_imm, op_reg) \ - if (flags & SRC2_IMM) { \ - if (op & SLJIT_SET_Z) \ - FAIL_IF(push_inst(compiler, op_imm | RD(EQUAL_FLAG) | RS1(src1) | IMM_I(src2))); \ - if (!(flags & UNUSED_DEST)) \ - FAIL_IF(push_inst(compiler, op_imm | RD(dst) | RS1(src1) | IMM_I(src2))); \ - } \ - else { \ - if (op & SLJIT_SET_Z) \ - FAIL_IF(push_inst(compiler, op_reg | RD(EQUAL_FLAG) | RS1(src1) | RS2(src2))); \ - if (!(flags & UNUSED_DEST)) \ - FAIL_IF(push_inst(compiler, op_reg | RD(dst) | RS1(src1) | RS2(src2))); \ - } - -#define EMIT_SHIFT(imm, reg) \ - op_imm = (imm); \ - op_reg = (reg); - -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_ins op_imm, op_reg; -#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64) - sljit_ins word = (op & SLJIT_32) >> 5; -#endif /* SLJIT_CONFIG_RISCV_64 */ - - SLJIT_ASSERT(WORD == 0 || WORD == 0x8); - - switch (GET_OPCODE(op)) { - case SLJIT_MOV: - SLJIT_ASSERT(src1 == TMP_REG1 && !(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)); - 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)); - 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)); - } - SLJIT_ASSERT(dst == src2); - return SLJIT_SUCCESS; - - case SLJIT_MOV_U16: - SLJIT_ASSERT(src1 == TMP_REG1 && !(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)); - } - SLJIT_ASSERT(dst == src2); - return SLJIT_SUCCESS; - - case SLJIT_MOV_S16: - SLJIT_ASSERT(src1 == TMP_REG1 && !(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)); - } - SLJIT_ASSERT(dst == src2); - return SLJIT_SUCCESS; - -#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64) - case SLJIT_MOV_U32: - SLJIT_ASSERT(src1 == TMP_REG1 && !(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)); - } - SLJIT_ASSERT(dst == src2); - return SLJIT_SUCCESS; - - case SLJIT_MOV_S32: - SLJIT_ASSERT(src1 == TMP_REG1 && !(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); - return SLJIT_SUCCESS; -#endif /* SLJIT_CONFIG_RISCV_64 */ - - case SLJIT_CLZ: - case SLJIT_CTZ: - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM)); - return emit_clz_ctz(compiler, op, dst, src2); - - case SLJIT_ADD: - /* Overflow computation (both add and sub): overflow = src1_sign ^ src2_sign ^ result_sign ^ carry_flag */ - is_overflow = GET_FLAG_TYPE(op) == SLJIT_OVERFLOW; - carry_src_r = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY); - - if (flags & SRC2_IMM) { - if (is_overflow) { - if (src2 >= 0) - FAIL_IF(push_inst(compiler, ADDI | RD(EQUAL_FLAG) | RS1(src1) | IMM_I(0))); - else - FAIL_IF(push_inst(compiler, XORI | RD(EQUAL_FLAG) | RS1(src1) | IMM_I(-1))); - } - else if (op & SLJIT_SET_Z) - FAIL_IF(push_inst(compiler, ADDI | WORD | RD(EQUAL_FLAG) | RS1(src1) | IMM_I(src2))); - - /* Only the zero flag is needed. */ - if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK)) - FAIL_IF(push_inst(compiler, ADDI | WORD | RD(dst) | RS1(src1) | IMM_I(src2))); - } - else { - if (is_overflow) - FAIL_IF(push_inst(compiler, XOR | RD(EQUAL_FLAG) | RS1(src1) | RS2(src2))); - else if (op & SLJIT_SET_Z) - FAIL_IF(push_inst(compiler, ADD | WORD | RD(EQUAL_FLAG) | RS1(src1) | RS2(src2))); - - if (is_overflow || carry_src_r != 0) { - if (src1 != dst) - carry_src_r = (sljit_s32)src1; - else if (src2 != dst) - carry_src_r = (sljit_s32)src2; - else { - FAIL_IF(push_inst(compiler, ADDI | RD(OTHER_FLAG) | RS1(src1) | IMM_I(0))); - carry_src_r = OTHER_FLAG; - } - } - - /* Only the zero flag is needed. */ - if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK)) - FAIL_IF(push_inst(compiler, ADD | WORD | RD(dst) | RS1(src1) | RS2(src2))); - } - - /* Carry is zero if a + b >= a or a + b >= b, otherwise it is 1. */ - if (is_overflow || carry_src_r != 0) { - if (flags & SRC2_IMM) - FAIL_IF(push_inst(compiler, SLTUI | RD(OTHER_FLAG) | RS1(dst) | IMM_I(src2))); - else - FAIL_IF(push_inst(compiler, SLTU | RD(OTHER_FLAG) | RS1(dst) | RS2(carry_src_r))); - } - - if (!is_overflow) - return SLJIT_SUCCESS; - - FAIL_IF(push_inst(compiler, XOR | RD(TMP_REG1) | RS1(dst) | RS2(EQUAL_FLAG))); - if (op & SLJIT_SET_Z) - FAIL_IF(push_inst(compiler, ADDI | RD(EQUAL_FLAG) | RS1(dst) | IMM_I(0))); - FAIL_IF(push_inst(compiler, SRLI | WORD | RD(TMP_REG1) | RS1(TMP_REG1) | IMM_EXTEND(31))); - return push_inst(compiler, XOR | RD(OTHER_FLAG) | RS1(TMP_REG1) | RS2(OTHER_FLAG)); - - case SLJIT_ADDC: - carry_src_r = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY); - - if (flags & SRC2_IMM) { - FAIL_IF(push_inst(compiler, ADDI | WORD | RD(dst) | RS1(src1) | IMM_I(src2))); - } else { - if (carry_src_r != 0) { - if (src1 != dst) - carry_src_r = (sljit_s32)src1; - else if (src2 != dst) - carry_src_r = (sljit_s32)src2; - else { - FAIL_IF(push_inst(compiler, ADDI | RD(EQUAL_FLAG) | RS1(src1) | IMM_I(0))); - carry_src_r = EQUAL_FLAG; - } - } - - FAIL_IF(push_inst(compiler, ADD | WORD | RD(dst) | RS1(src1) | RS2(src2))); - } - - /* Carry is zero if a + b >= a or a + b >= b, otherwise it is 1. */ - if (carry_src_r != 0) { - if (flags & SRC2_IMM) - FAIL_IF(push_inst(compiler, SLTUI | RD(EQUAL_FLAG) | RS1(dst) | IMM_I(src2))); - else - FAIL_IF(push_inst(compiler, SLTU | RD(EQUAL_FLAG) | RS1(dst) | RS2(carry_src_r))); - } - - FAIL_IF(push_inst(compiler, ADD | WORD | RD(dst) | RS1(dst) | RS2(OTHER_FLAG))); - - if (carry_src_r == 0) - return SLJIT_SUCCESS; - - /* Set ULESS_FLAG (dst == 0) && (OTHER_FLAG == 1). */ - FAIL_IF(push_inst(compiler, SLTU | RD(OTHER_FLAG) | RS1(dst) | RS2(OTHER_FLAG))); - /* Set carry flag. */ - return push_inst(compiler, OR | RD(OTHER_FLAG) | RS1(OTHER_FLAG) | RS2(EQUAL_FLAG)); - - case SLJIT_SUB: - if ((flags & SRC2_IMM) && src2 == SIMM_MIN) { - FAIL_IF(push_inst(compiler, ADDI | RD(TMP_REG2) | RS1(TMP_ZERO) | IMM_I(src2))); - src2 = TMP_REG2; - flags &= ~SRC2_IMM; - } - - is_handled = 0; - - if (flags & SRC2_IMM) { - if (GET_FLAG_TYPE(op) == SLJIT_LESS || GET_FLAG_TYPE(op) == SLJIT_GREATER_EQUAL) { - FAIL_IF(push_inst(compiler, SLTUI | RD(OTHER_FLAG) | RS1(src1) | IMM_I(src2))); - is_handled = 1; - } - else if (GET_FLAG_TYPE(op) == SLJIT_SIG_LESS || GET_FLAG_TYPE(op) == SLJIT_SIG_GREATER_EQUAL) { - FAIL_IF(push_inst(compiler, SLTI | RD(OTHER_FLAG) | RS1(src1) | IMM_I(src2))); - is_handled = 1; - } - } - - if (!is_handled && GET_FLAG_TYPE(op) >= SLJIT_LESS && GET_FLAG_TYPE(op) <= SLJIT_SIG_LESS_EQUAL) { - 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; - flags &= ~SRC2_IMM; - } - - switch (GET_FLAG_TYPE(op)) { - case SLJIT_LESS: - case SLJIT_GREATER_EQUAL: - FAIL_IF(push_inst(compiler, SLTU | RD(OTHER_FLAG) | RS1(src1) | RS2(src2))); - break; - case SLJIT_GREATER: - case SLJIT_LESS_EQUAL: - FAIL_IF(push_inst(compiler, SLTU | RD(OTHER_FLAG) | RS1(src2) | RS2(src1))); - break; - case SLJIT_SIG_LESS: - case SLJIT_SIG_GREATER_EQUAL: - FAIL_IF(push_inst(compiler, SLT | RD(OTHER_FLAG) | RS1(src1) | RS2(src2))); - break; - case SLJIT_SIG_GREATER: - case SLJIT_SIG_LESS_EQUAL: - FAIL_IF(push_inst(compiler, SLT | RD(OTHER_FLAG) | RS1(src2) | RS2(src1))); - break; - } - } - - if (is_handled) { - if (flags & SRC2_IMM) { - if (op & SLJIT_SET_Z) - FAIL_IF(push_inst(compiler, ADDI | WORD | RD(EQUAL_FLAG) | RS1(src1) | IMM_I(-src2))); - if (!(flags & UNUSED_DEST)) - return push_inst(compiler, ADDI | WORD | RD(dst) | RS1(src1) | IMM_I(-src2)); - } - else { - if (op & SLJIT_SET_Z) - FAIL_IF(push_inst(compiler, SUB | WORD | RD(EQUAL_FLAG) | RS1(src1) | RS2(src2))); - if (!(flags & UNUSED_DEST)) - return push_inst(compiler, SUB | WORD | RD(dst) | RS1(src1) | RS2(src2)); - } - return SLJIT_SUCCESS; - } - - is_overflow = GET_FLAG_TYPE(op) == SLJIT_OVERFLOW; - is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY); - - if (flags & SRC2_IMM) { - if (is_overflow) { - if (src2 >= 0) - FAIL_IF(push_inst(compiler, ADDI | RD(EQUAL_FLAG) | RS1(src1) | IMM_I(0))); - else - FAIL_IF(push_inst(compiler, XORI | RD(EQUAL_FLAG) | RS1(src1) | IMM_I(-1))); - } - else if (op & SLJIT_SET_Z) - FAIL_IF(push_inst(compiler, ADDI | WORD | RD(EQUAL_FLAG) | RS1(src1) | IMM_I(-src2))); - - if (is_overflow || is_carry) - FAIL_IF(push_inst(compiler, SLTUI | RD(OTHER_FLAG) | RS1(src1) | IMM_I(src2))); - - /* Only the zero flag is needed. */ - if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK)) - FAIL_IF(push_inst(compiler, ADDI | WORD | RD(dst) | RS1(src1) | IMM_I(-src2))); - } - else { - if (is_overflow) - FAIL_IF(push_inst(compiler, XOR | RD(EQUAL_FLAG) | RS1(src1) | RS2(src2))); - else if (op & SLJIT_SET_Z) - FAIL_IF(push_inst(compiler, SUB | WORD | RD(EQUAL_FLAG) | RS1(src1) | RS2(src2))); - - if (is_overflow || is_carry) - FAIL_IF(push_inst(compiler, SLTU | RD(OTHER_FLAG) | RS1(src1) | RS2(src2))); - - /* Only the zero flag is needed. */ - if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK)) - FAIL_IF(push_inst(compiler, SUB | WORD | RD(dst) | RS1(src1) | RS2(src2))); - } - - if (!is_overflow) - return SLJIT_SUCCESS; - - FAIL_IF(push_inst(compiler, XOR | RD(TMP_REG1) | RS1(dst) | RS2(EQUAL_FLAG))); - if (op & SLJIT_SET_Z) - FAIL_IF(push_inst(compiler, ADDI | RD(EQUAL_FLAG) | RS1(dst) | IMM_I(0))); - FAIL_IF(push_inst(compiler, SRLI | WORD | RD(TMP_REG1) | RS1(TMP_REG1) | IMM_EXTEND(31))); - return push_inst(compiler, XOR | RD(OTHER_FLAG) | RS1(TMP_REG1) | RS2(OTHER_FLAG)); - - case SLJIT_SUBC: - if ((flags & SRC2_IMM) && src2 == SIMM_MIN) { - FAIL_IF(push_inst(compiler, ADDI | RD(TMP_REG2) | RS1(TMP_ZERO) | IMM_I(src2))); - src2 = TMP_REG2; - flags &= ~SRC2_IMM; - } - - is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY); - - if (flags & SRC2_IMM) { - if (is_carry) - FAIL_IF(push_inst(compiler, SLTUI | RD(EQUAL_FLAG) | RS1(src1) | IMM_I(src2))); - - FAIL_IF(push_inst(compiler, ADDI | WORD | RD(dst) | RS1(src1) | IMM_I(-src2))); - } - else { - if (is_carry) - FAIL_IF(push_inst(compiler, SLTU | RD(EQUAL_FLAG) | RS1(src1) | RS2(src2))); - - FAIL_IF(push_inst(compiler, SUB | WORD | RD(dst) | RS1(src1) | RS2(src2))); - } - - if (is_carry) - FAIL_IF(push_inst(compiler, SLTU | RD(TMP_REG1) | RS1(dst) | RS2(OTHER_FLAG))); - - FAIL_IF(push_inst(compiler, SUB | WORD | RD(dst) | RS1(dst) | RS2(OTHER_FLAG))); - - if (!is_carry) - return SLJIT_SUCCESS; - - return push_inst(compiler, OR | RD(OTHER_FLAG) | RS1(EQUAL_FLAG) | RS2(TMP_REG1)); - - case SLJIT_MUL: - SLJIT_ASSERT(!(flags & SRC2_IMM)); - - if (GET_FLAG_TYPE(op) != SLJIT_OVERFLOW) - return push_inst(compiler, MUL | WORD | RD(dst) | RS1(src1) | RS2(src2)); - -#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64) - if (word) { - FAIL_IF(push_inst(compiler, MUL | RD(OTHER_FLAG) | RS1(src1) | RS2(src2))); - FAIL_IF(push_inst(compiler, MUL | 0x8 | RD(dst) | RS1(src1) | RS2(src2))); - return push_inst(compiler, SUB | RD(OTHER_FLAG) | RS1(dst) | RS2(OTHER_FLAG)); - } -#endif /* SLJIT_CONFIG_RISCV_64 */ - - FAIL_IF(push_inst(compiler, MULH | RD(EQUAL_FLAG) | RS1(src1) | RS2(src2))); - FAIL_IF(push_inst(compiler, MUL | RD(dst) | RS1(src1) | RS2(src2))); -#if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) - FAIL_IF(push_inst(compiler, SRAI | RD(OTHER_FLAG) | RS1(dst) | IMM_I(31))); -#else /* !SLJIT_CONFIG_RISCV_32 */ - FAIL_IF(push_inst(compiler, SRAI | RD(OTHER_FLAG) | RS1(dst) | IMM_I(63))); -#endif /* SLJIT_CONFIG_RISCV_32 */ - return push_inst(compiler, SUB | RD(OTHER_FLAG) | RS1(EQUAL_FLAG) | RS2(OTHER_FLAG)); - - case SLJIT_AND: - EMIT_LOGICAL(ANDI, AND); - return SLJIT_SUCCESS; - - case SLJIT_OR: - EMIT_LOGICAL(ORI, OR); - return SLJIT_SUCCESS; - - case SLJIT_XOR: - EMIT_LOGICAL(XORI, XOR); - return SLJIT_SUCCESS; - - case SLJIT_SHL: - case SLJIT_MSHL: - EMIT_SHIFT(SLLI, SLL); - break; - - case SLJIT_LSHR: - case SLJIT_MLSHR: - EMIT_SHIFT(SRLI, SRL); - break; - - case SLJIT_ASHR: - case SLJIT_MASHR: - EMIT_SHIFT(SRAI, SRA); - break; - - case SLJIT_ROTL: - case SLJIT_ROTR: - if (flags & SRC2_IMM) { - SLJIT_ASSERT(src2 != 0); - - op_imm = (GET_OPCODE(op) == SLJIT_ROTL) ? SLLI : SRLI; - FAIL_IF(push_inst(compiler, op_imm | WORD | RD(OTHER_FLAG) | RS1(src1) | IMM_I(src2))); - -#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64) - src2 = ((op & SLJIT_32) ? 32 : 64) - src2; -#else /* !SLJIT_CONFIG_RISCV_64 */ - src2 = 32 - src2; -#endif /* SLJIT_CONFIG_RISCV_64 */ - op_imm = (GET_OPCODE(op) == SLJIT_ROTL) ? SRLI : SLLI; - FAIL_IF(push_inst(compiler, op_imm | WORD | RD(dst) | RS1(src1) | IMM_I(src2))); - return push_inst(compiler, OR | RD(dst) | RS1(dst) | RS2(OTHER_FLAG)); - } - - if (src2 == TMP_ZERO) { - if (dst != src1) - return push_inst(compiler, ADDI | WORD | RD(dst) | RS1(src1) | IMM_I(0)); - return SLJIT_SUCCESS; - } - - FAIL_IF(push_inst(compiler, SUB | WORD | RD(EQUAL_FLAG) | RS1(TMP_ZERO) | RS2(src2))); - op_reg = (GET_OPCODE(op) == SLJIT_ROTL) ? SLL : SRL; - FAIL_IF(push_inst(compiler, op_reg | WORD | RD(OTHER_FLAG) | RS1(src1) | RS2(src2))); - op_reg = (GET_OPCODE(op) == SLJIT_ROTL) ? SRL : SLL; - FAIL_IF(push_inst(compiler, op_reg | WORD | RD(dst) | RS1(src1) | RS2(EQUAL_FLAG))); - return push_inst(compiler, OR | RD(dst) | RS1(dst) | RS2(OTHER_FLAG)); - - default: - SLJIT_UNREACHABLE(); - return SLJIT_SUCCESS; - } - - if (flags & SRC2_IMM) { - if (op & SLJIT_SET_Z) - FAIL_IF(push_inst(compiler, op_imm | WORD | RD(EQUAL_FLAG) | RS1(src1) | IMM_I(src2))); - - if (flags & UNUSED_DEST) - return SLJIT_SUCCESS; - return push_inst(compiler, op_imm | WORD | RD(dst) | RS1(src1) | IMM_I(src2)); - } - - if (op & SLJIT_SET_Z) - FAIL_IF(push_inst(compiler, op_reg | WORD | RD(EQUAL_FLAG) | RS1(src1) | RS2(src2))); - - if (flags & UNUSED_DEST) - return SLJIT_SUCCESS; - return push_inst(compiler, op_reg | WORD | RD(dst) | RS1(src1) | RS2(src2)); -} - -#undef IMM_EXTEND - -static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 flags, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - /* arg1 goes to TMP_REG1 or src reg - arg2 goes to TMP_REG2, imm or src reg - TMP_REG3 can be used for caching - result goes to TMP_REG2, so put result can use TMP_REG1 and TMP_REG3. */ - sljit_s32 dst_r = TMP_REG2; - sljit_s32 src1_r; - sljit_sw src2_r = 0; - sljit_s32 sugg_src2_r = TMP_REG2; - - if (!(flags & ALT_KEEP_CACHE)) { - compiler->cache_arg = 0; - compiler->cache_argw = 0; - } - - if (dst == TMP_REG2) { - SLJIT_ASSERT(HAS_FLAGS(op)); - flags |= UNUSED_DEST; - } - 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)) - flags |= SLOW_DEST; - - if (flags & IMM_OP) { - if ((src2 & SLJIT_IMM) && src2w != 0 && src2w <= SIMM_MAX && src2w >= SIMM_MIN) { - flags |= SRC2_IMM; - src2_r = src2w; - } - else if ((flags & CUMULATIVE_OP) && (src1 & SLJIT_IMM) && src1w != 0 && src1w <= SIMM_MAX && src1w >= SIMM_MIN) { - flags |= SRC2_IMM; - src2_r = src1w; - - /* And swap arguments. */ - src1 = src2; - src1w = src2w; - src2 = SLJIT_IMM; - /* src2w = src2_r unneeded. */ - } - } - - /* Source 1. */ - if (FAST_IS_REG(src1)) { - src1_r = src1; - flags |= REG1_SOURCE; - } - 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 { - if (getput_arg_fast(compiler, flags | LOAD_DATA, TMP_REG1, src1, src1w)) - FAIL_IF(compiler->error); - else - flags |= SLOW_SRC1; - src1_r = TMP_REG1; - } - - /* Source 2. */ - if (FAST_IS_REG(src2)) { - src2_r = src2; - flags |= REG2_SOURCE; - if ((flags & (REG_DEST | MOVE_OP)) == MOVE_OP) - dst_r = (sljit_s32)src2_r; - } - 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 { - src2_r = TMP_ZERO; - if (flags & MOVE_OP) { - if (dst & SLJIT_MEM) - dst_r = 0; - else - op = SLJIT_MOV; - } - } - } - } - else { - if (getput_arg_fast(compiler, flags | LOAD_DATA, sugg_src2_r, src2, src2w)) - FAIL_IF(compiler->error); - else - flags |= SLOW_SRC2; - src2_r = sugg_src2_r; - } - - 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)) { - 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(emit_single_op(compiler, op, flags, dst_r, src1_r, src2_r)); - - if (dst & SLJIT_MEM) { - if (!(flags & SLOW_DEST)) { - getput_arg_fast(compiler, flags, dst_r, dst, dstw); - return compiler->error; - } - return getput_arg(compiler, flags, dst_r, dst, dstw, 0, 0); - } - - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compiler, sljit_s32 op) -{ -#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64) - sljit_ins word = (op & SLJIT_32) >> 5; - - SLJIT_ASSERT(word == 0 || word == 0x8); -#endif /* SLJIT_CONFIG_RISCV_64 */ - - CHECK_ERROR(); - CHECK(check_sljit_emit_op0(compiler, op)); - - switch (GET_OPCODE(op)) { - case SLJIT_BREAKPOINT: - return push_inst(compiler, EBREAK); - case SLJIT_NOP: - return push_inst(compiler, ADDI | RD(TMP_ZERO) | RS1(TMP_ZERO) | IMM_I(0)); - case SLJIT_LMUL_UW: - FAIL_IF(push_inst(compiler, ADDI | RD(TMP_REG1) | RS1(SLJIT_R1) | IMM_I(0))); - FAIL_IF(push_inst(compiler, MULHU | RD(SLJIT_R1) | RS1(SLJIT_R0) | RS2(SLJIT_R1))); - return push_inst(compiler, MUL | RD(SLJIT_R0) | RS1(SLJIT_R0) | RS2(TMP_REG1)); - case SLJIT_LMUL_SW: - FAIL_IF(push_inst(compiler, ADDI | RD(TMP_REG1) | RS1(SLJIT_R1) | IMM_I(0))); - FAIL_IF(push_inst(compiler, MULH | RD(SLJIT_R1) | RS1(SLJIT_R0) | RS2(SLJIT_R1))); - return push_inst(compiler, MUL | RD(SLJIT_R0) | RS1(SLJIT_R0) | RS2(TMP_REG1)); - case SLJIT_DIVMOD_UW: - FAIL_IF(push_inst(compiler, ADDI | RD(TMP_REG1) | RS1(SLJIT_R0) | IMM_I(0))); - FAIL_IF(push_inst(compiler, DIVU | WORD | RD(SLJIT_R0) | RS1(SLJIT_R0) | RS2(SLJIT_R1))); - return push_inst(compiler, REMU | WORD | RD(SLJIT_R1) | RS1(TMP_REG1) | RS2(SLJIT_R1)); - case SLJIT_DIVMOD_SW: - FAIL_IF(push_inst(compiler, ADDI | RD(TMP_REG1) | RS1(SLJIT_R0) | IMM_I(0))); - FAIL_IF(push_inst(compiler, DIV | WORD | RD(SLJIT_R0) | RS1(SLJIT_R0) | RS2(SLJIT_R1))); - return push_inst(compiler, REM | WORD | RD(SLJIT_R1) | RS1(TMP_REG1) | RS2(SLJIT_R1)); - case SLJIT_DIV_UW: - return push_inst(compiler, DIVU | WORD | RD(SLJIT_R0) | RS1(SLJIT_R0) | RS2(SLJIT_R1)); - case SLJIT_DIV_SW: - return push_inst(compiler, DIV | WORD | RD(SLJIT_R0) | RS1(SLJIT_R0) | RS2(SLJIT_R1)); - case SLJIT_ENDBR: - case SLJIT_SKIP_FRAMES_BEFORE_RETURN: - return SLJIT_SUCCESS; - } - - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src, sljit_sw srcw) -{ - sljit_s32 flags = 0; - - CHECK_ERROR(); - CHECK(check_sljit_emit_op1(compiler, op, dst, dstw, src, srcw)); - ADJUST_LOCAL_OFFSET(dst, dstw); - ADJUST_LOCAL_OFFSET(src, srcw); - -#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64) - if (op & SLJIT_32) - flags = INT_DATA | SIGNED_DATA; -#endif - - switch (GET_OPCODE(op)) { - case SLJIT_MOV: -#if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) - case SLJIT_MOV_U32: - case SLJIT_MOV_S32: - 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); - -#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); - - 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); -#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); - - 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); - - 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); - - 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); - - case SLJIT_NOT: - return emit_op(compiler, SLJIT_XOR | (op & (SLJIT_32 | SLJIT_SET_Z)), flags, dst, dstw, src, srcw, SLJIT_IMM, -1); - - case SLJIT_CLZ: - case SLJIT_CTZ: - return emit_op(compiler, op, flags, dst, dstw, TMP_REG1, 0, src, srcw); - } - - SLJIT_UNREACHABLE(); - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - sljit_s32 flags = 0; - - CHECK_ERROR(); - CHECK(check_sljit_emit_op2(compiler, op, 0, dst, dstw, src1, src1w, src2, src2w)); - ADJUST_LOCAL_OFFSET(dst, dstw); - ADJUST_LOCAL_OFFSET(src1, src1w); - ADJUST_LOCAL_OFFSET(src2, src2w); - -#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64) - if (op & SLJIT_32) { - flags |= INT_DATA | SIGNED_DATA; - if (src1 & SLJIT_IMM) - src1w = (sljit_s32)src1w; - if (src2 & SLJIT_IMM) - src2w = (sljit_s32)src2w; - } -#endif - - switch (GET_OPCODE(op)) { - case SLJIT_ADD: - case SLJIT_ADDC: - compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD; - return emit_op(compiler, op, flags | CUMULATIVE_OP | IMM_OP, dst, dstw, src1, src1w, src2, src2w); - - case SLJIT_SUB: - case SLJIT_SUBC: - compiler->status_flags_state = SLJIT_CURRENT_FLAGS_SUB; - return emit_op(compiler, op, flags | IMM_OP, dst, dstw, src1, src1w, src2, src2w); - - case SLJIT_MUL: - compiler->status_flags_state = 0; - return emit_op(compiler, op, flags | CUMULATIVE_OP, dst, dstw, src1, src1w, src2, src2w); - - case SLJIT_AND: - case SLJIT_OR: - case SLJIT_XOR: - return emit_op(compiler, op, flags | CUMULATIVE_OP | IMM_OP, dst, dstw, src1, src1w, src2, src2w); - - case SLJIT_SHL: - case SLJIT_MSHL: - case SLJIT_LSHR: - case SLJIT_MLSHR: - case SLJIT_ASHR: - case SLJIT_MASHR: - case SLJIT_ROTL: - case SLJIT_ROTR: - if (src2 & SLJIT_IMM) { -#if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) - src2w &= 0x1f; -#else /* !SLJIT_CONFIG_RISCV_32 */ - if (op & SLJIT_32) - src2w &= 0x1f; - else - src2w &= 0x3f; -#endif /* SLJIT_CONFIG_RISCV_32 */ - } - - return emit_op(compiler, op, flags | IMM_OP, dst, dstw, src1, src1w, src2, src2w); - } - - SLJIT_UNREACHABLE(); - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - 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, TMP_REG2, 0, src1, src1w, src2, src2w); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 src_dst, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - sljit_s32 is_left; - sljit_ins ins1, ins2, ins3; -#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64) - sljit_ins word = (op & SLJIT_32) >> 5; - sljit_s32 inp_flags = ((op & SLJIT_32) ? INT_DATA : WORD_DATA) | LOAD_DATA; - sljit_sw bit_length = (op & SLJIT_32) ? 32 : 64; -#else /* !SLJIT_CONFIG_RISCV_64 */ - sljit_s32 inp_flags = WORD_DATA | LOAD_DATA; - sljit_sw bit_length = 32; -#endif /* SLJIT_CONFIG_RISCV_64 */ - - SLJIT_ASSERT(WORD == 0 || WORD == 0x8); - - CHECK_ERROR(); - CHECK(check_sljit_emit_shift_into(compiler, op, src_dst, src1, src1w, src2, src2w)); - - is_left = (GET_OPCODE(op) == SLJIT_SHL || GET_OPCODE(op) == SLJIT_MSHL); - - if (src_dst == src1) { - SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_op2(compiler, (is_left ? SLJIT_ROTL : SLJIT_ROTR) | (op & SLJIT_32), src_dst, 0, src_dst, 0, src2, src2w); - } - - ADJUST_LOCAL_OFFSET(src1, src1w); - ADJUST_LOCAL_OFFSET(src2, src2w); - - if (src2 & SLJIT_IMM) { - src2w &= bit_length - 1; - - if (src2w == 0) - return SLJIT_SUCCESS; - } else if (src2 & SLJIT_MEM) { - FAIL_IF(emit_op_mem(compiler, inp_flags, TMP_REG2, src2, src2w)); - src2 = TMP_REG2; - } - - if (src1 & SLJIT_MEM) { - FAIL_IF(emit_op_mem(compiler, inp_flags, TMP_REG1, src1, src1w)); - src1 = TMP_REG1; - } else if (src1 & SLJIT_IMM) { - FAIL_IF(load_immediate(compiler, TMP_REG1, src1w, TMP_REG3)); - src1 = TMP_REG1; - } - - if (src2 & SLJIT_IMM) { - if (is_left) { - ins1 = SLLI | WORD | IMM_I(src2w); - src2w = bit_length - src2w; - ins2 = SRLI | WORD | IMM_I(src2w); - } else { - ins1 = SRLI | WORD | IMM_I(src2w); - src2w = bit_length - src2w; - ins2 = SLLI | WORD | IMM_I(src2w); - } - - FAIL_IF(push_inst(compiler, ins1 | RD(src_dst) | RS1(src_dst))); - FAIL_IF(push_inst(compiler, ins2 | RD(TMP_REG1) | RS1(src1))); - return push_inst(compiler, OR | RD(src_dst) | RS1(src_dst) | RS2(TMP_REG1)); - } - - if (is_left) { - ins1 = SLL; - ins2 = SRLI; - ins3 = SRL; - } else { - ins1 = SRL; - ins2 = SLLI; - ins3 = SLL; - } - - FAIL_IF(push_inst(compiler, ins1 | WORD | RD(src_dst) | RS1(src_dst) | RS2(src2))); - - if (!(op & SLJIT_SHIFT_INTO_NON_ZERO)) { - FAIL_IF(push_inst(compiler, ins2 | WORD | RD(TMP_REG1) | RS1(src1) | IMM_I(1))); - FAIL_IF(push_inst(compiler, XORI | RD(TMP_REG2) | RS1(src2) | IMM_I((sljit_ins)bit_length - 1))); - src1 = TMP_REG1; - } else - FAIL_IF(push_inst(compiler, SUB | WORD | RD(TMP_REG2) | RS1(TMP_ZERO) | RS2(src2))); - - FAIL_IF(push_inst(compiler, ins3 | WORD | RD(TMP_REG1) | RS1(src1) | RS2(TMP_REG2))); - return push_inst(compiler, OR | RD(src_dst) | RS1(src_dst) | RS2(TMP_REG1)); -} - -#undef WORD - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 src, sljit_sw srcw) -{ - CHECK_ERROR(); - CHECK(check_sljit_emit_op_src(compiler, op, src, srcw)); - ADJUST_LOCAL_OFFSET(src, srcw); - - switch (op) { - case SLJIT_FAST_RETURN: - if (FAST_IS_REG(src)) - FAIL_IF(push_inst(compiler, ADDI | RD(RETURN_ADDR_REG) | RS1(src) | IMM_I(0))); - else - FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, RETURN_ADDR_REG, src, srcw)); - - return push_inst(compiler, JALR | RD(TMP_ZERO) | RS1(RETURN_ADDR_REG) | IMM_I(0)); - case SLJIT_SKIP_FRAMES_BEFORE_FAST_RETURN: - return SLJIT_SUCCESS; - case SLJIT_PREFETCH_L1: - case SLJIT_PREFETCH_L2: - case SLJIT_PREFETCH_L3: - case SLJIT_PREFETCH_ONCE: - return SLJIT_SUCCESS; - } - - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 reg) -{ - CHECK_REG_INDEX(check_sljit_get_register_index(reg)); - return reg_map[reg]; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_float_register_index(sljit_s32 reg) -{ - CHECK_REG_INDEX(check_sljit_get_float_register_index(reg)); - return freg_map[reg]; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler, - void *instruction, sljit_u32 size) -{ - CHECK_ERROR(); - CHECK(check_sljit_emit_op_custom(compiler, instruction, size)); - - return push_inst(compiler, *(sljit_ins*)instruction); -} - -/* --------------------------------------------------------------------- */ -/* Floating point operators */ -/* --------------------------------------------------------------------- */ - -#define FLOAT_DATA(op) (DOUBLE_DATA | ((op & SLJIT_32) >> 7)) -#define FMT(op) ((sljit_ins)((op & SLJIT_32) ^ SLJIT_32) << 17) - -static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src, sljit_sw srcw) -{ -#if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) -# define flags (sljit_u32)0 -#else - sljit_u32 flags = ((sljit_u32)(GET_OPCODE(op) == SLJIT_CONV_SW_FROM_F64)) << 21; -#endif - sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2; - - if (src & SLJIT_MEM) { - FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src, srcw, dst, dstw)); - src = TMP_FREG1; - } - - FAIL_IF(push_inst(compiler, FCVT_W_S | FMT(op) | flags | RD(dst_r) | FRS1(src))); - - /* Store the integer value from a VFP register. */ - if (dst & SLJIT_MEM) { -#if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) - return emit_op_mem2(compiler, WORD_DATA, TMP_REG2, dst, dstw, 0, 0); -#else - return emit_op_mem2(compiler, flags ? WORD_DATA : INT_DATA, TMP_REG2, dst, dstw, 0, 0); -#endif - } - return SLJIT_SUCCESS; - -#if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) -# undef flags -#endif -} - -static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src, sljit_sw srcw) -{ - sljit_ins inst; -#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64) - sljit_u32 flags = ((sljit_u32)(GET_OPCODE(op) == SLJIT_CONV_F64_FROM_SW)) << 21; -#endif - - sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1; - - if (src & SLJIT_MEM) { -#if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) - FAIL_IF(emit_op_mem2(compiler, WORD_DATA | LOAD_DATA, TMP_REG1, src, srcw, dst, dstw)); -#else - FAIL_IF(emit_op_mem2(compiler, (flags ? WORD_DATA : INT_DATA) | LOAD_DATA, TMP_REG1, src, srcw, dst, dstw)); -#endif - src = TMP_REG1; - } else if (src & SLJIT_IMM) { -#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64) - if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32) - srcw = (sljit_s32)srcw; -#endif - - FAIL_IF(load_immediate(compiler, TMP_REG1, srcw, TMP_REG3)); - src = TMP_REG1; - } - - inst = FCVT_S_W | FMT(op) | FRD(dst_r) | RS1(src); - -#if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) - if (op & SLJIT_32) - inst |= F3(0x7); -#else - inst |= flags; - - if (op != SLJIT_CONV_F64_FROM_S32) - inst |= F3(0x7); -#endif - - FAIL_IF(push_inst(compiler, inst)); - - if (dst & SLJIT_MEM) - return emit_op_mem2(compiler, FLOAT_DATA(op), TMP_FREG1, dst, dstw, 0, 0); - return SLJIT_SUCCESS; -} - -static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - sljit_ins inst; - - if (src1 & SLJIT_MEM) { - FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w, src2, src2w)); - src1 = TMP_FREG1; - } - - if (src2 & SLJIT_MEM) { - FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w, 0, 0)); - src2 = TMP_FREG2; - } - - switch (GET_FLAG_TYPE(op)) { - case SLJIT_F_EQUAL: - case SLJIT_F_NOT_EQUAL: - case SLJIT_ORDERED_EQUAL: - case SLJIT_UNORDERED_OR_NOT_EQUAL: - inst = FEQ_S | FMT(op) | RD(OTHER_FLAG) | FRS1(src1) | FRS2(src2); - break; - case SLJIT_F_LESS: - case SLJIT_F_GREATER_EQUAL: - case SLJIT_ORDERED_LESS: - case SLJIT_UNORDERED_OR_GREATER_EQUAL: - inst = FLT_S | FMT(op) | RD(OTHER_FLAG) | FRS1(src1) | FRS2(src2); - break; - case SLJIT_ORDERED_GREATER: - case SLJIT_UNORDERED_OR_LESS_EQUAL: - inst = FLT_S | FMT(op) | RD(OTHER_FLAG) | FRS1(src2) | FRS2(src1); - break; - case SLJIT_F_GREATER: - case SLJIT_F_LESS_EQUAL: - case SLJIT_UNORDERED_OR_GREATER: - case SLJIT_ORDERED_LESS_EQUAL: - inst = FLE_S | FMT(op) | RD(OTHER_FLAG) | FRS1(src1) | FRS2(src2); - break; - case SLJIT_UNORDERED_OR_LESS: - case SLJIT_ORDERED_GREATER_EQUAL: - inst = FLE_S | FMT(op) | RD(OTHER_FLAG) | FRS1(src2) | FRS2(src1); - break; - case SLJIT_UNORDERED_OR_EQUAL: /* Not supported. */ - case SLJIT_ORDERED_NOT_EQUAL: /* Not supported. */ - FAIL_IF(push_inst(compiler, FLT_S | FMT(op) | RD(OTHER_FLAG) | FRS1(src1) | FRS2(src2))); - FAIL_IF(push_inst(compiler, FLT_S | FMT(op) | RD(TMP_REG1) | FRS1(src2) | FRS2(src1))); - inst = OR | RD(OTHER_FLAG) | RS1(OTHER_FLAG) | RS2(TMP_REG1); - break; - default: /* SLJIT_UNORDERED, SLJIT_ORDERED */ - FAIL_IF(push_inst(compiler, FADD_S | FMT(op) | FRD(TMP_FREG1) | FRS1(src1) | FRS2(src2))); - inst = FEQ_S | FMT(op) | RD(OTHER_FLAG) | FRS1(TMP_FREG1) | FRS2(TMP_FREG1); - break; - } - - return push_inst(compiler, inst); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src, sljit_sw srcw) -{ - sljit_s32 dst_r; - - CHECK_ERROR(); - compiler->cache_arg = 0; - compiler->cache_argw = 0; - - SLJIT_COMPILE_ASSERT((SLJIT_32 == 0x100) && !(DOUBLE_DATA & 0x2), float_transfer_bit_error); - SELECT_FOP1_OPERATION_WITH_CHECKS(compiler, op, dst, dstw, src, srcw); - - if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_F32) - op ^= SLJIT_32; - - dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1; - - if (src & SLJIT_MEM) { - FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, dst_r, src, srcw, dst, dstw)); - src = dst_r; - } - - switch (GET_OPCODE(op)) { - case SLJIT_MOV_F64: - if (src != dst_r) { - if (dst_r != TMP_FREG1) - FAIL_IF(push_inst(compiler, FSGNJ_S | FMT(op) | FRD(dst_r) | FRS1(src) | FRS2(src))); - else - dst_r = src; - } - break; - case SLJIT_NEG_F64: - FAIL_IF(push_inst(compiler, FSGNJN_S | FMT(op) | FRD(dst_r) | FRS1(src) | FRS2(src))); - break; - case SLJIT_ABS_F64: - FAIL_IF(push_inst(compiler, FSGNJX_S | FMT(op) | FRD(dst_r) | FRS1(src) | FRS2(src))); - break; - case SLJIT_CONV_F64_FROM_F32: - /* The SLJIT_32 bit is inverted because sljit_f32 needs to be loaded from the memory. */ - FAIL_IF(push_inst(compiler, FCVT_S_D | ((op & SLJIT_32) ? (1 << 25) : ((1 << 20) | F3(7))) | FRD(dst_r) | FRS1(src))); - op ^= SLJIT_32; - break; - } - - if (dst & SLJIT_MEM) - return emit_op_mem2(compiler, FLOAT_DATA(op), dst_r, dst, dstw, 0, 0); - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - sljit_s32 dst_r, flags = 0; - - CHECK_ERROR(); - CHECK(check_sljit_emit_fop2(compiler, op, dst, dstw, src1, src1w, src2, src2w)); - ADJUST_LOCAL_OFFSET(dst, dstw); - ADJUST_LOCAL_OFFSET(src1, src1w); - ADJUST_LOCAL_OFFSET(src2, src2w); - - compiler->cache_arg = 0; - compiler->cache_argw = 0; - - dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG2; - - if (src1 & SLJIT_MEM) { - if (getput_arg_fast(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w)) { - FAIL_IF(compiler->error); - src1 = TMP_FREG1; - } else - flags |= SLOW_SRC1; - } - - if (src2 & SLJIT_MEM) { - if (getput_arg_fast(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w)) { - FAIL_IF(compiler->error); - src2 = TMP_FREG2; - } else - flags |= SLOW_SRC2; - } - - if ((flags & (SLOW_SRC1 | SLOW_SRC2)) == (SLOW_SRC1 | SLOW_SRC2)) { - if (!can_cache(src1, src1w, src2, src2w) && can_cache(src1, src1w, dst, dstw)) { - FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w, src1, src1w)); - FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w, dst, dstw)); - } - else { - FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w, src2, src2w)); - FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w, dst, dstw)); - } - } - else if (flags & SLOW_SRC1) - FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w, dst, dstw)); - else if (flags & SLOW_SRC2) - FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w, dst, dstw)); - - if (flags & SLOW_SRC1) - src1 = TMP_FREG1; - if (flags & SLOW_SRC2) - src2 = TMP_FREG2; - - switch (GET_OPCODE(op)) { - case SLJIT_ADD_F64: - FAIL_IF(push_inst(compiler, FADD_S | FMT(op) | FRD(dst_r) | FRS1(src1) | FRS2(src2))); - break; - - case SLJIT_SUB_F64: - FAIL_IF(push_inst(compiler, FSUB_S | FMT(op) | FRD(dst_r) | FRS1(src1) | FRS2(src2))); - break; - - case SLJIT_MUL_F64: - FAIL_IF(push_inst(compiler, FMUL_S | FMT(op) | FRD(dst_r) | FRS1(src1) | FRS2(src2))); - break; - - case SLJIT_DIV_F64: - FAIL_IF(push_inst(compiler, FDIV_S | FMT(op) | FRD(dst_r) | FRS1(src1) | FRS2(src2))); - break; - } - - if (dst_r == TMP_FREG2) - FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op), TMP_FREG2, dst, dstw, 0, 0)); - - return SLJIT_SUCCESS; -} - -#undef FLOAT_DATA -#undef FMT - -/* --------------------------------------------------------------------- */ -/* Other instructions */ -/* --------------------------------------------------------------------- */ - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw) -{ - CHECK_ERROR(); - CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw)); - ADJUST_LOCAL_OFFSET(dst, dstw); - - if (FAST_IS_REG(dst)) - return push_inst(compiler, ADDI | RD(dst) | RS1(RETURN_ADDR_REG) | IMM_I(0)); - - /* Memory. */ - return emit_op_mem(compiler, WORD_DATA, RETURN_ADDR_REG, dst, dstw); -} - -/* --------------------------------------------------------------------- */ -/* Conditional instructions */ -/* --------------------------------------------------------------------- */ - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compiler *compiler) -{ - struct sljit_label *label; - - CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_label(compiler)); - - if (compiler->last_label && compiler->last_label->size == compiler->size) - return compiler->last_label; - - label = (struct sljit_label*)ensure_abuf(compiler, sizeof(struct sljit_label)); - PTR_FAIL_IF(!label); - set_label(label, compiler); - return label; -} - -#if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) -#define BRANCH_LENGTH ((sljit_ins)(3 * sizeof(sljit_ins)) << 7) -#else -#define BRANCH_LENGTH ((sljit_ins)(7 * sizeof(sljit_ins)) << 7) -#endif - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type) -{ - struct sljit_jump *jump; - sljit_ins inst; - - CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_jump(compiler, type)); - - jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump)); - PTR_FAIL_IF(!jump); - set_jump(jump, compiler, type & SLJIT_REWRITABLE_JUMP); - type &= 0xff; - - switch (type) { - case SLJIT_EQUAL: - inst = BNE | RS1(EQUAL_FLAG) | RS2(TMP_ZERO) | BRANCH_LENGTH; - break; - case SLJIT_NOT_EQUAL: - inst = BEQ | RS1(EQUAL_FLAG) | RS2(TMP_ZERO) | BRANCH_LENGTH; - break; - case SLJIT_LESS: - case SLJIT_GREATER: - case SLJIT_SIG_LESS: - case SLJIT_SIG_GREATER: - case SLJIT_OVERFLOW: - case SLJIT_CARRY: - case SLJIT_F_EQUAL: - case SLJIT_ORDERED_EQUAL: - case SLJIT_ORDERED_NOT_EQUAL: /* Not supported. */ - case SLJIT_F_LESS: - case SLJIT_ORDERED_LESS: - case SLJIT_ORDERED_GREATER: - case SLJIT_F_LESS_EQUAL: - case SLJIT_ORDERED_LESS_EQUAL: - case SLJIT_ORDERED_GREATER_EQUAL: - case SLJIT_ORDERED: - inst = BEQ | RS1(OTHER_FLAG) | RS2(TMP_ZERO) | BRANCH_LENGTH; - break; - case SLJIT_GREATER_EQUAL: - case SLJIT_LESS_EQUAL: - case SLJIT_SIG_GREATER_EQUAL: - case SLJIT_SIG_LESS_EQUAL: - case SLJIT_NOT_OVERFLOW: - case SLJIT_NOT_CARRY: - case SLJIT_F_NOT_EQUAL: - case SLJIT_UNORDERED_OR_NOT_EQUAL: - case SLJIT_UNORDERED_OR_EQUAL: /* Not supported. */ - case SLJIT_F_GREATER_EQUAL: - case SLJIT_UNORDERED_OR_GREATER_EQUAL: - case SLJIT_UNORDERED_OR_LESS_EQUAL: - case SLJIT_F_GREATER: - case SLJIT_UNORDERED_OR_GREATER: - case SLJIT_UNORDERED_OR_LESS: - case SLJIT_UNORDERED: - inst = BNE | RS1(OTHER_FLAG) | RS2(TMP_ZERO) | BRANCH_LENGTH; - break; - default: - /* Not conditional branch. */ - inst = 0; - break; - } - - if (inst != 0) { - PTR_FAIL_IF(push_inst(compiler, inst)); - jump->flags |= IS_COND; - } - - jump->addr = compiler->size; - inst = JALR | RS1(TMP_REG1) | IMM_I(0); - - if (type >= SLJIT_FAST_CALL) { - jump->flags |= IS_CALL; - inst |= RD(RETURN_ADDR_REG); - } - - 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 - return jump; -} - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_call(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 arg_types) -{ - SLJIT_UNUSED_ARG(arg_types); - CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_call(compiler, type, arg_types)); - - if (type & SLJIT_CALL_RETURN) { - PTR_FAIL_IF(emit_stack_frame_release(compiler, 0)); - type = SLJIT_JUMP | (type & SLJIT_REWRITABLE_JUMP); - } - - SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_jump(compiler, type); -} - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - struct sljit_jump *jump; - sljit_s32 flags; - sljit_ins inst; - - CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_cmp(compiler, type, src1, src1w, src2, src2w)); - ADJUST_LOCAL_OFFSET(src1, src1w); - ADJUST_LOCAL_OFFSET(src2, src2w); - - compiler->cache_arg = 0; - compiler->cache_argw = 0; -#if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) - flags = WORD_DATA | LOAD_DATA; -#else /* !SLJIT_CONFIG_RISCV_32 */ - flags = ((type & SLJIT_32) ? INT_DATA : WORD_DATA) | LOAD_DATA; -#endif /* SLJIT_CONFIG_RISCV_32 */ - - if (src1 & SLJIT_MEM) { - PTR_FAIL_IF(emit_op_mem2(compiler, flags, TMP_REG1, src1, src1w, src2, src2w)); - src1 = TMP_REG1; - } - - if (src2 & SLJIT_MEM) { - PTR_FAIL_IF(emit_op_mem2(compiler, flags, TMP_REG2, src2, src2w, 0, 0)); - src2 = TMP_REG2; - } - - if (src1 & SLJIT_IMM) { - if (src1w != 0) { - PTR_FAIL_IF(load_immediate(compiler, TMP_REG1, src1w, TMP_REG3)); - src1 = TMP_REG1; - } - else - src1 = TMP_ZERO; - } - - if (src2 & SLJIT_IMM) { - if (src2w != 0) { - PTR_FAIL_IF(load_immediate(compiler, TMP_REG2, src2w, TMP_REG3)); - src2 = TMP_REG2; - } - else - src2 = TMP_ZERO; - } - - jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump)); - PTR_FAIL_IF(!jump); - set_jump(jump, compiler, (sljit_u32)((type & SLJIT_REWRITABLE_JUMP) | IS_COND)); - type &= 0xff; - - switch (type) { - case SLJIT_EQUAL: - inst = BNE | RS1(src1) | RS2(src2) | BRANCH_LENGTH; - break; - case SLJIT_NOT_EQUAL: - inst = BEQ | RS1(src1) | RS2(src2) | BRANCH_LENGTH; - break; - case SLJIT_LESS: - inst = BGEU | RS1(src1) | RS2(src2) | BRANCH_LENGTH; - break; - case SLJIT_GREATER_EQUAL: - inst = BLTU | RS1(src1) | RS2(src2) | BRANCH_LENGTH; - break; - case SLJIT_GREATER: - inst = BGEU | RS1(src2) | RS2(src1) | BRANCH_LENGTH; - break; - case SLJIT_LESS_EQUAL: - inst = BLTU | RS1(src2) | RS2(src1) | BRANCH_LENGTH; - break; - case SLJIT_SIG_LESS: - inst = BGE | RS1(src1) | RS2(src2) | BRANCH_LENGTH; - break; - case SLJIT_SIG_GREATER_EQUAL: - inst = BLT | RS1(src1) | RS2(src2) | BRANCH_LENGTH; - break; - case SLJIT_SIG_GREATER: - inst = BGE | RS1(src2) | RS2(src1) | BRANCH_LENGTH; - break; - case SLJIT_SIG_LESS_EQUAL: - inst = BLT | RS1(src2) | RS2(src1) | BRANCH_LENGTH; - break; - } - - PTR_FAIL_IF(push_inst(compiler, inst)); - - jump->addr = compiler->size; - 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 - return jump; -} - -#undef BRANCH_LENGTH - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 src, sljit_sw srcw) -{ - struct sljit_jump *jump; - - CHECK_ERROR(); - CHECK(check_sljit_emit_ijump(compiler, type, src, srcw)); - - if (!(src & SLJIT_IMM)) { - if (src & SLJIT_MEM) { - ADJUST_LOCAL_OFFSET(src, srcw); - FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, TMP_REG1, src, srcw)); - src = TMP_REG1; - } - return push_inst(compiler, JALR | RD((type >= SLJIT_FAST_CALL) ? RETURN_ADDR_REG : TMP_ZERO) | RS1(src) | IMM_I(0)); - } - - /* These jumps are converted to jump/call instructions when possible. */ - jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump)); - FAIL_IF(!jump); - set_jump(jump, compiler, JUMP_ADDR | ((type >= SLJIT_FAST_CALL) ? IS_CALL : 0)); - jump->u.target = (sljit_uw)srcw; - - jump->addr = compiler->size; - 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 - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 arg_types, - sljit_s32 src, sljit_sw srcw) -{ - SLJIT_UNUSED_ARG(arg_types); - CHECK_ERROR(); - CHECK(check_sljit_emit_icall(compiler, type, arg_types, src, srcw)); - - if (src & SLJIT_MEM) { - ADJUST_LOCAL_OFFSET(src, srcw); - FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, TMP_REG1, src, srcw)); - src = TMP_REG1; - } - - if (type & SLJIT_CALL_RETURN) { - if (src >= SLJIT_FIRST_SAVED_REG && src <= (SLJIT_S0 - SLJIT_KEPT_SAVEDS_COUNT(compiler->options))) { - FAIL_IF(push_inst(compiler, ADDI | RD(TMP_REG1) | RS1(src) | IMM_I(0))); - src = TMP_REG1; - } - - FAIL_IF(emit_stack_frame_release(compiler, 0)); - type = SLJIT_JUMP; - } - - SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_ijump(compiler, type, src, srcw); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 type) -{ - sljit_s32 src_r, dst_r, invert; - sljit_s32 saved_op = op; -#if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) - sljit_s32 mem_type = WORD_DATA; -#else - sljit_s32 mem_type = ((op & SLJIT_32) || op == SLJIT_MOV32) ? (INT_DATA | SIGNED_DATA) : WORD_DATA; -#endif - - CHECK_ERROR(); - CHECK(check_sljit_emit_op_flags(compiler, op, dst, dstw, type)); - ADJUST_LOCAL_OFFSET(dst, dstw); - - op = GET_OPCODE(op); - dst_r = (op < SLJIT_ADD && FAST_IS_REG(dst)) ? dst : TMP_REG2; - - compiler->cache_arg = 0; - compiler->cache_argw = 0; - - if (op >= SLJIT_ADD && (dst & SLJIT_MEM)) - FAIL_IF(emit_op_mem2(compiler, mem_type | LOAD_DATA, TMP_REG1, dst, dstw, dst, dstw)); - - if (type < SLJIT_F_EQUAL) { - src_r = OTHER_FLAG; - invert = type & 0x1; - - switch (type) { - case SLJIT_EQUAL: - case SLJIT_NOT_EQUAL: - FAIL_IF(push_inst(compiler, SLTUI | RD(dst_r) | RS1(EQUAL_FLAG) | IMM_I(1))); - src_r = dst_r; - break; - case SLJIT_OVERFLOW: - case SLJIT_NOT_OVERFLOW: - if (compiler->status_flags_state & (SLJIT_CURRENT_FLAGS_ADD | SLJIT_CURRENT_FLAGS_SUB)) { - src_r = OTHER_FLAG; - break; - } - FAIL_IF(push_inst(compiler, SLTUI | RD(dst_r) | RS1(OTHER_FLAG) | IMM_I(1))); - src_r = dst_r; - invert ^= 0x1; - break; - } - } else { - invert = 0; - src_r = OTHER_FLAG; - - switch (type) { - case SLJIT_F_NOT_EQUAL: - case SLJIT_UNORDERED_OR_NOT_EQUAL: - case SLJIT_UNORDERED_OR_EQUAL: /* Not supported. */ - case SLJIT_F_GREATER_EQUAL: - case SLJIT_UNORDERED_OR_GREATER_EQUAL: - case SLJIT_UNORDERED_OR_LESS_EQUAL: - case SLJIT_F_GREATER: - case SLJIT_UNORDERED_OR_GREATER: - case SLJIT_UNORDERED_OR_LESS: - case SLJIT_UNORDERED: - invert = 1; - break; - } - } - - if (invert) { - FAIL_IF(push_inst(compiler, XORI | RD(dst_r) | RS1(src_r) | IMM_I(1))); - src_r = dst_r; - } - - if (op < SLJIT_ADD) { - if (dst & SLJIT_MEM) - return emit_op_mem(compiler, mem_type, src_r, dst, dstw); - - if (src_r != dst_r) - return push_inst(compiler, ADDI | RD(dst_r) | RS1(src_r) | IMM_I(0)); - return SLJIT_SUCCESS; - } - - mem_type |= CUMULATIVE_OP | IMM_OP | ALT_KEEP_CACHE; - - if (dst & SLJIT_MEM) - return emit_op(compiler, saved_op, mem_type, dst, dstw, TMP_REG1, 0, src_r, 0); - return emit_op(compiler, saved_op, mem_type, dst, dstw, dst, dstw, src_r, 0); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 dst_reg, - sljit_s32 src, sljit_sw srcw) -{ - CHECK_ERROR(); - CHECK(check_sljit_emit_cmov(compiler, type, dst_reg, src, srcw)); - - return sljit_emit_cmov_generic(compiler, type, dst_reg, src, srcw);; -} - -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) -{ - sljit_s32 flags; - - CHECK_ERROR(); - CHECK(check_sljit_emit_mem(compiler, type, reg, mem, memw)); - - if (!(reg & REG_PAIR_MASK)) - return sljit_emit_mem_unaligned(compiler, type, reg, mem, memw); - - if (SLJIT_UNLIKELY(mem & OFFS_REG_MASK)) { - memw &= 0x3; - - if (SLJIT_UNLIKELY(memw != 0)) { - FAIL_IF(push_inst(compiler, SLLI | RD(TMP_REG1) | RS1(OFFS_REG(mem)) | IMM_I(memw))); - FAIL_IF(push_inst(compiler, ADD | RD(TMP_REG1) | RS1(TMP_REG1) | RS2(mem & REG_MASK))); - } else - FAIL_IF(push_inst(compiler, ADD | RD(TMP_REG1) | RS1(mem & REG_MASK) | RS2(OFFS_REG(mem)))); - - mem = TMP_REG1; - memw = 0; - } else if (memw > SIMM_MAX - SSIZE_OF(sw) || memw < SIMM_MIN) { - if (((memw + 0x800) & 0xfff) <= 0xfff - SSIZE_OF(sw)) { - FAIL_IF(load_immediate(compiler, TMP_REG1, TO_ARGW_HI(memw), TMP_REG3)); - memw &= 0xfff; - } else { - FAIL_IF(load_immediate(compiler, TMP_REG1, memw, TMP_REG3)); - memw = 0; - } - - if (mem & REG_MASK) - FAIL_IF(push_inst(compiler, ADD | RD(TMP_REG1) | RS1(TMP_REG1) | RS2(mem & REG_MASK))); - - mem = TMP_REG1; - } else { - mem &= REG_MASK; - memw &= 0xfff; - } - - SLJIT_ASSERT((memw >= 0 && memw <= SIMM_MAX - SSIZE_OF(sw)) || (memw > SIMM_MAX && memw <= 0xfff)); - - if (!(type & SLJIT_MEM_STORE) && mem == REG_PAIR_FIRST(reg)) { - FAIL_IF(push_mem_inst(compiler, WORD_DATA | LOAD_DATA, REG_PAIR_SECOND(reg), mem, (memw + SSIZE_OF(sw)) & 0xfff)); - return push_mem_inst(compiler, WORD_DATA | LOAD_DATA, REG_PAIR_FIRST(reg), mem, memw); - } - - flags = WORD_DATA | (!(type & SLJIT_MEM_STORE) ? LOAD_DATA : 0); - - FAIL_IF(push_mem_inst(compiler, flags, REG_PAIR_FIRST(reg), mem, memw)); - return push_mem_inst(compiler, flags, REG_PAIR_SECOND(reg), mem, (memw + SSIZE_OF(sw)) & 0xfff); -} - -#undef TO_ARGW_HI - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value) -{ - struct sljit_const *const_; - sljit_s32 dst_r; - - CHECK_ERROR_PTR(); - 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; - PTR_FAIL_IF(emit_const(compiler, dst_r, init_value, ADDI | RD(dst_r))); - - if (dst & SLJIT_MEM) - PTR_FAIL_IF(emit_op_mem(compiler, WORD_DATA, TMP_REG2, dst, dstw)); - - return const_; -} - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label* sljit_emit_put_label(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw) -{ - struct sljit_put_label *put_label; - sljit_s32 dst_r; - - CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_put_label(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); - - 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 - compiler->size += 5; -#endif - - if (dst & SLJIT_MEM) - PTR_FAIL_IF(emit_op_mem(compiler, WORD_DATA, TMP_REG2, dst, dstw)); - - return put_label; -} - -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset) -{ - sljit_set_jump_addr(addr, (sljit_uw)new_constant, executable_offset); -} diff --git a/modules/regex/pcre2/src/sljit/sljitNativeS390X.c b/modules/regex/pcre2/src/sljit/sljitNativeS390X.c deleted file mode 100644 index 8b51bad..0000000 --- a/modules/regex/pcre2/src/sljit/sljitNativeS390X.c +++ /dev/null @@ -1,3747 +0,0 @@ -/* - * 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. - */ - -#include - -#ifdef __ARCH__ -#define ENABLE_STATIC_FACILITY_DETECTION 1 -#else -#define ENABLE_STATIC_FACILITY_DETECTION 0 -#endif -#define ENABLE_DYNAMIC_FACILITY_DETECTION 1 - -SLJIT_API_FUNC_ATTRIBUTE const char* sljit_get_platform_name(void) -{ - return "s390x" SLJIT_CPUINFO; -} - -/* Instructions. */ -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) - -static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 4] = { - 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 15, 0, 1 -}; - -/* there are also a[2-15] available, but they are slower to access and - * their use is limited as mundaym explained: - * https://github.com/zherczeg/sljit/pull/91#discussion_r486895689 - */ - -/* General Purpose Registers [0-15]. */ -typedef sljit_uw sljit_gpr; - -/* - * WARNING - * the following code is non standard and should be improved for - * consistency, but doesn't use SLJIT_NUMBER_OF_REGISTERS based - * registers because r0 and r1 are the ABI recommended volatiles. - * there is a gpr() function that maps sljit to physical register numbers - * that should be used instead of the usual index into reg_map[] and - * will be retired ASAP (TODO: carenas) - */ - -static const sljit_gpr r0 = 0; /* reg_map[SLJIT_NUMBER_OF_REGISTERS + 2]: 0 in address calculations; reserved */ -static const sljit_gpr r1 = 1; /* reg_map[SLJIT_NUMBER_OF_REGISTERS + 3]: reserved */ -static const sljit_gpr r2 = 2; /* reg_map[1]: 1st argument */ -static const sljit_gpr r3 = 3; /* reg_map[2]: 2nd argument */ -static const sljit_gpr r4 = 4; /* reg_map[3]: 3rd argument */ -static const sljit_gpr r5 = 5; /* reg_map[4]: 4th argument */ -static const sljit_gpr r6 = 6; /* reg_map[5]: 5th argument; 1st saved register */ -static const sljit_gpr r7 = 7; /* reg_map[6] */ -static const sljit_gpr r8 = 8; /* reg_map[7] */ -static const sljit_gpr r9 = 9; /* reg_map[8] */ -static const sljit_gpr r10 = 10; /* reg_map[9] */ -static const sljit_gpr r11 = 11; /* reg_map[10] */ -static const sljit_gpr r12 = 12; /* reg_map[11]: GOT */ -static const sljit_gpr r13 = 13; /* reg_map[12]: Literal Pool pointer */ -static const sljit_gpr r14 = 14; /* reg_map[0]: return address and flag register */ -static const sljit_gpr r15 = 15; /* reg_map[SLJIT_NUMBER_OF_REGISTERS + 1]: stack pointer */ - -/* WARNING: r12 and r13 shouldn't be used as per ABI recommendation */ -/* TODO(carenas): r12 might conflict in PIC code, reserve? */ -/* TODO(carenas): r13 is usually pointed to "pool" per ABI, using a tmp - * like we do know might be faster though, reserve? - */ - -/* TODO(carenas): should be named TMP_REG[1-2] for consistency */ -#define tmp0 r0 -#define tmp1 r1 - -/* TODO(carenas): flags should move to a different register so that - * link register doesn't need to change - */ - -/* When reg cannot be unused. */ -#define IS_GPR_REG(reg) ((reg > 0) && (reg) <= SLJIT_SP) - -/* Link register. */ -static const sljit_gpr link_r = 14; /* r14 */ - -#define TMP_FREG1 (0) - -static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1] = { - 1, 0, 2, 4, 6, 3, 5, 7, 15, 14, 13, 12, 11, 10, 9, 8, -}; - -#define R0A(r) (r) -#define R4A(r) ((r) << 4) -#define R8A(r) ((r) << 8) -#define R12A(r) ((r) << 12) -#define R16A(r) ((r) << 16) -#define R20A(r) ((r) << 20) -#define R28A(r) ((r) << 28) -#define R32A(r) ((r) << 32) -#define R36A(r) ((r) << 36) - -#define R0(r) ((sljit_ins)reg_map[r]) - -#define F0(r) ((sljit_ins)freg_map[r]) -#define F4(r) (R4A((sljit_ins)freg_map[r])) -#define F20(r) (R20A((sljit_ins)freg_map[r])) -#define F36(r) (R36A((sljit_ins)freg_map[r])) - -struct sljit_s390x_const { - struct sljit_const const_; /* must be first */ - sljit_sw init_value; /* required to build literal pool */ -}; - -/* Convert SLJIT register to hardware register. */ -static SLJIT_INLINE sljit_gpr gpr(sljit_s32 r) -{ - SLJIT_ASSERT(r >= 0 && r < (sljit_s32)(sizeof(reg_map) / sizeof(reg_map[0]))); - return reg_map[r]; -} - -static SLJIT_INLINE sljit_gpr fgpr(sljit_s32 r) -{ - SLJIT_ASSERT(r >= 0 && r < (sljit_s32)(sizeof(freg_map) / sizeof(freg_map[0]))); - return freg_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; - compiler->size++; - return SLJIT_SUCCESS; -} - -static sljit_s32 encode_inst(void **ptr, sljit_ins ins) -{ - sljit_u16 *ibuf = (sljit_u16 *)*ptr; - sljit_uw size = sizeof_ins(ins); - - 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; -} - -#define SLJIT_ADD_SUB_NO_COMPARE(status_flags_state) \ - (((status_flags_state) & (SLJIT_CURRENT_FLAGS_ADD | SLJIT_CURRENT_FLAGS_SUB)) \ - && !((status_flags_state) & SLJIT_CURRENT_FLAGS_COMPARE)) - -/* Map the given type to a 4-bit condition code mask. */ -static SLJIT_INLINE sljit_u8 get_cc(struct sljit_compiler *compiler, sljit_s32 type) { - const sljit_u8 cc0 = 1 << 3; /* equal {,to zero} */ - const sljit_u8 cc1 = 1 << 2; /* less than {,zero} */ - const sljit_u8 cc2 = 1 << 1; /* greater than {,zero} */ - const sljit_u8 cc3 = 1 << 0; /* {overflow,NaN} */ - - switch (type) { - case SLJIT_EQUAL: - if (SLJIT_ADD_SUB_NO_COMPARE(compiler->status_flags_state)) { - sljit_s32 type = GET_FLAG_TYPE(compiler->status_flags_state); - if (type >= SLJIT_SIG_LESS && type <= SLJIT_SIG_LESS_EQUAL) - return cc0; - if (type == SLJIT_OVERFLOW) - return (cc0 | cc3); - return (cc0 | cc2); - } - /* fallthrough */ - - case SLJIT_F_EQUAL: - case SLJIT_ORDERED_EQUAL: - return cc0; - - case SLJIT_NOT_EQUAL: - if (SLJIT_ADD_SUB_NO_COMPARE(compiler->status_flags_state)) { - sljit_s32 type = GET_FLAG_TYPE(compiler->status_flags_state); - if (type >= SLJIT_SIG_LESS && type <= SLJIT_SIG_LESS_EQUAL) - return (cc1 | cc2 | cc3); - if (type == SLJIT_OVERFLOW) - return (cc1 | cc2); - return (cc1 | cc3); - } - /* fallthrough */ - - case SLJIT_UNORDERED_OR_NOT_EQUAL: - return (cc1 | cc2 | cc3); - - case SLJIT_LESS: - return cc1; - - case SLJIT_GREATER_EQUAL: - case SLJIT_UNORDERED_OR_GREATER_EQUAL: - return (cc0 | cc2 | cc3); - - case SLJIT_GREATER: - if (compiler->status_flags_state & SLJIT_CURRENT_FLAGS_COMPARE) - return cc2; - return cc3; - - case SLJIT_LESS_EQUAL: - if (compiler->status_flags_state & SLJIT_CURRENT_FLAGS_COMPARE) - return (cc0 | cc1); - return (cc0 | cc1 | cc2); - - case SLJIT_SIG_LESS: - case SLJIT_F_LESS: - case SLJIT_ORDERED_LESS: - return cc1; - - case SLJIT_NOT_CARRY: - if (compiler->status_flags_state & SLJIT_CURRENT_FLAGS_SUB) - return (cc2 | cc3); - /* fallthrough */ - - case SLJIT_SIG_LESS_EQUAL: - case SLJIT_F_LESS_EQUAL: - case SLJIT_ORDERED_LESS_EQUAL: - return (cc0 | cc1); - - case SLJIT_CARRY: - if (compiler->status_flags_state & SLJIT_CURRENT_FLAGS_SUB) - return (cc0 | cc1); - /* fallthrough */ - - case SLJIT_SIG_GREATER: - case SLJIT_UNORDERED_OR_GREATER: - /* Overflow is considered greater, see SLJIT_SUB. */ - return cc2 | cc3; - - case SLJIT_SIG_GREATER_EQUAL: - return (cc0 | cc2 | cc3); - - case SLJIT_OVERFLOW: - if (compiler->status_flags_state & SLJIT_SET_Z) - return (cc2 | cc3); - /* fallthrough */ - - case SLJIT_UNORDERED: - return cc3; - - case SLJIT_NOT_OVERFLOW: - if (compiler->status_flags_state & SLJIT_SET_Z) - return (cc0 | cc1); - /* fallthrough */ - - case SLJIT_ORDERED: - return (cc0 | cc1 | cc2); - - case SLJIT_F_NOT_EQUAL: - case SLJIT_ORDERED_NOT_EQUAL: - return (cc1 | cc2); - - case SLJIT_F_GREATER: - case SLJIT_ORDERED_GREATER: - return cc2; - - case SLJIT_F_GREATER_EQUAL: - case SLJIT_ORDERED_GREATER_EQUAL: - return (cc0 | cc2); - - case SLJIT_UNORDERED_OR_LESS_EQUAL: - return (cc0 | cc1 | cc3); - - case SLJIT_UNORDERED_OR_EQUAL: - return (cc0 | cc3); - - case SLJIT_UNORDERED_OR_LESS: - return (cc1 | cc3); - } - - SLJIT_UNREACHABLE(); - return (sljit_u8)-1; -} - -/* Facility to bit index mappings. - Note: some facilities share the same bit index. */ -typedef sljit_uw facility_bit; -#define STORE_FACILITY_LIST_EXTENDED_FACILITY 7 -#define FAST_LONG_DISPLACEMENT_FACILITY 19 -#define EXTENDED_IMMEDIATE_FACILITY 21 -#define GENERAL_INSTRUCTION_EXTENSION_FACILITY 34 -#define DISTINCT_OPERAND_FACILITY 45 -#define HIGH_WORD_FACILITY 45 -#define POPULATION_COUNT_FACILITY 45 -#define LOAD_STORE_ON_CONDITION_1_FACILITY 45 -#define MISCELLANEOUS_INSTRUCTION_EXTENSIONS_1_FACILITY 49 -#define LOAD_STORE_ON_CONDITION_2_FACILITY 53 -#define MISCELLANEOUS_INSTRUCTION_EXTENSIONS_2_FACILITY 58 -#define VECTOR_FACILITY 129 -#define VECTOR_ENHANCEMENTS_1_FACILITY 135 - -/* Report whether a facility is known to be present due to the compiler - settings. This function should always be compiled to a constant - value given a constant argument. */ -static SLJIT_INLINE int have_facility_static(facility_bit x) -{ -#if ENABLE_STATIC_FACILITY_DETECTION - switch (x) { - case FAST_LONG_DISPLACEMENT_FACILITY: - return (__ARCH__ >= 6 /* z990 */); - case EXTENDED_IMMEDIATE_FACILITY: - case STORE_FACILITY_LIST_EXTENDED_FACILITY: - return (__ARCH__ >= 7 /* z9-109 */); - case GENERAL_INSTRUCTION_EXTENSION_FACILITY: - return (__ARCH__ >= 8 /* z10 */); - case DISTINCT_OPERAND_FACILITY: - return (__ARCH__ >= 9 /* z196 */); - case MISCELLANEOUS_INSTRUCTION_EXTENSIONS_1_FACILITY: - return (__ARCH__ >= 10 /* zEC12 */); - case LOAD_STORE_ON_CONDITION_2_FACILITY: - case VECTOR_FACILITY: - return (__ARCH__ >= 11 /* z13 */); - case MISCELLANEOUS_INSTRUCTION_EXTENSIONS_2_FACILITY: - case VECTOR_ENHANCEMENTS_1_FACILITY: - return (__ARCH__ >= 12 /* z14 */); - default: - SLJIT_UNREACHABLE(); - } -#endif - return 0; -} - -static SLJIT_INLINE unsigned long get_hwcap() -{ - static unsigned long hwcap = 0; - if (SLJIT_UNLIKELY(!hwcap)) { - hwcap = getauxval(AT_HWCAP); - SLJIT_ASSERT(hwcap != 0); - } - return hwcap; -} - -static SLJIT_INLINE int have_stfle() -{ - if (have_facility_static(STORE_FACILITY_LIST_EXTENDED_FACILITY)) - return 1; - - return (get_hwcap() & HWCAP_S390_STFLE); -} - -/* Report whether the given facility is available. This function always - performs a runtime check. */ -static int have_facility_dynamic(facility_bit x) -{ -#if ENABLE_DYNAMIC_FACILITY_DETECTION - static struct { - sljit_uw bits[4]; - } cpu_features; - size_t size = sizeof(cpu_features); - const sljit_uw word_index = x >> 6; - const sljit_uw bit_index = ((1UL << 63) >> (x & 63)); - - SLJIT_ASSERT(x < size * 8); - if (SLJIT_UNLIKELY(!have_stfle())) - return 0; - - if (SLJIT_UNLIKELY(cpu_features.bits[0] == 0)) { - __asm__ __volatile__ ( - "lgr %%r0, %0;" - "stfle 0(%1);" - /* outputs */: - /* inputs */: "d" ((size / 8) - 1), "a" (&cpu_features) - /* clobbers */: "r0", "cc", "memory" - ); - SLJIT_ASSERT(cpu_features.bits[0] != 0); - } - return (cpu_features.bits[word_index] & bit_index) != 0; -#else - return 0; -#endif -} - -#define HAVE_FACILITY(name, bit) \ -static SLJIT_INLINE int name() \ -{ \ - static int have = -1; \ - /* Static check first. May allow the function to be optimized away. */ \ - if (have_facility_static(bit)) \ - have = 1; \ - else if (SLJIT_UNLIKELY(have < 0)) \ - have = have_facility_dynamic(bit) ? 1 : 0; \ -\ - return have; \ -} - -HAVE_FACILITY(have_eimm, EXTENDED_IMMEDIATE_FACILITY) -HAVE_FACILITY(have_ldisp, FAST_LONG_DISPLACEMENT_FACILITY) -HAVE_FACILITY(have_genext, GENERAL_INSTRUCTION_EXTENSION_FACILITY) -HAVE_FACILITY(have_lscond1, LOAD_STORE_ON_CONDITION_1_FACILITY) -HAVE_FACILITY(have_lscond2, LOAD_STORE_ON_CONDITION_2_FACILITY) -HAVE_FACILITY(have_misc2, MISCELLANEOUS_INSTRUCTION_EXTENSIONS_2_FACILITY) -#undef HAVE_FACILITY - -#define is_u12(d) (0 <= (d) && (d) <= 0x00000fffL) -#define is_u32(d) (0 <= (d) && (d) <= 0xffffffffL) - -#define CHECK_SIGNED(v, bitlen) \ - ((v) >= -(1 << ((bitlen) - 1)) && (v) < (1 << ((bitlen) - 1))) - -#define is_s8(d) CHECK_SIGNED((d), 8) -#define is_s16(d) CHECK_SIGNED((d), 16) -#define is_s20(d) CHECK_SIGNED((d), 20) -#define is_s32(d) ((d) == (sljit_s32)(d)) - -static SLJIT_INLINE sljit_ins disp_s20(sljit_s32 d) -{ - SLJIT_ASSERT(is_s20(d)); - - sljit_uw dh = (d >> 12) & 0xff; - sljit_uw dl = (d << 8) & 0xfff00; - return (dh | dl) << 8; -} - -/* TODO(carenas): variadic macro is not strictly needed */ -#define SLJIT_S390X_INSTRUCTION(op, ...) \ -static SLJIT_INLINE sljit_ins op(__VA_ARGS__) - -/* RR form instructions. */ -#define SLJIT_S390X_RR(name, pattern) \ -SLJIT_S390X_INSTRUCTION(name, sljit_gpr dst, sljit_gpr src) \ -{ \ - return (pattern) | ((dst & 0xf) << 4) | (src & 0xf); \ -} - -/* AND */ -SLJIT_S390X_RR(nr, 0x1400) - -/* BRANCH AND SAVE */ -SLJIT_S390X_RR(basr, 0x0d00) - -/* BRANCH ON CONDITION */ -SLJIT_S390X_RR(bcr, 0x0700) /* TODO(mundaym): type for mask? */ - -/* DIVIDE */ -SLJIT_S390X_RR(dr, 0x1d00) - -/* EXCLUSIVE OR */ -SLJIT_S390X_RR(xr, 0x1700) - -/* LOAD */ -SLJIT_S390X_RR(lr, 0x1800) - -/* LOAD COMPLEMENT */ -SLJIT_S390X_RR(lcr, 0x1300) - -/* OR */ -SLJIT_S390X_RR(or, 0x1600) - -#undef SLJIT_S390X_RR - -/* RRE form instructions */ -#define SLJIT_S390X_RRE(name, pattern) \ -SLJIT_S390X_INSTRUCTION(name, sljit_gpr dst, sljit_gpr src) \ -{ \ - return (pattern) | R4A(dst) | R0A(src); \ -} - -/* AND */ -SLJIT_S390X_RRE(ngr, 0xb9800000) - -/* DIVIDE LOGICAL */ -SLJIT_S390X_RRE(dlr, 0xb9970000) -SLJIT_S390X_RRE(dlgr, 0xb9870000) - -/* DIVIDE SINGLE */ -SLJIT_S390X_RRE(dsgr, 0xb90d0000) - -/* EXCLUSIVE OR */ -SLJIT_S390X_RRE(xgr, 0xb9820000) - -/* LOAD */ -SLJIT_S390X_RRE(lgr, 0xb9040000) -SLJIT_S390X_RRE(lgfr, 0xb9140000) - -/* LOAD BYTE */ -SLJIT_S390X_RRE(lbr, 0xb9260000) -SLJIT_S390X_RRE(lgbr, 0xb9060000) - -/* LOAD COMPLEMENT */ -SLJIT_S390X_RRE(lcgr, 0xb9030000) - -/* LOAD HALFWORD */ -SLJIT_S390X_RRE(lhr, 0xb9270000) -SLJIT_S390X_RRE(lghr, 0xb9070000) - -/* LOAD LOGICAL */ -SLJIT_S390X_RRE(llgfr, 0xb9160000) - -/* LOAD LOGICAL CHARACTER */ -SLJIT_S390X_RRE(llcr, 0xb9940000) -SLJIT_S390X_RRE(llgcr, 0xb9840000) - -/* LOAD LOGICAL HALFWORD */ -SLJIT_S390X_RRE(llhr, 0xb9950000) -SLJIT_S390X_RRE(llghr, 0xb9850000) - -/* MULTIPLY LOGICAL */ -SLJIT_S390X_RRE(mlgr, 0xb9860000) - -/* MULTIPLY SINGLE */ -SLJIT_S390X_RRE(msgfr, 0xb91c0000) - -/* OR */ -SLJIT_S390X_RRE(ogr, 0xb9810000) - -/* SUBTRACT */ -SLJIT_S390X_RRE(sgr, 0xb9090000) - -#undef SLJIT_S390X_RRE - -/* RI-a form instructions */ -#define SLJIT_S390X_RIA(name, pattern, imm_type) \ -SLJIT_S390X_INSTRUCTION(name, sljit_gpr reg, imm_type imm) \ -{ \ - return (pattern) | R20A(reg) | (imm & 0xffff); \ -} - -/* ADD HALFWORD IMMEDIATE */ -SLJIT_S390X_RIA(aghi, 0xa70b0000, sljit_s16) - -/* LOAD HALFWORD IMMEDIATE */ -SLJIT_S390X_RIA(lhi, 0xa7080000, sljit_s16) -SLJIT_S390X_RIA(lghi, 0xa7090000, sljit_s16) - -/* LOAD LOGICAL IMMEDIATE */ -SLJIT_S390X_RIA(llihh, 0xa50c0000, sljit_u16) -SLJIT_S390X_RIA(llihl, 0xa50d0000, sljit_u16) -SLJIT_S390X_RIA(llilh, 0xa50e0000, sljit_u16) -SLJIT_S390X_RIA(llill, 0xa50f0000, sljit_u16) - -/* MULTIPLY HALFWORD IMMEDIATE */ -SLJIT_S390X_RIA(mhi, 0xa70c0000, sljit_s16) -SLJIT_S390X_RIA(mghi, 0xa70d0000, sljit_s16) - -/* OR IMMEDIATE */ -SLJIT_S390X_RIA(oilh, 0xa50a0000, sljit_u16) - -#undef SLJIT_S390X_RIA - -/* RIL-a form instructions (requires extended immediate facility) */ -#define SLJIT_S390X_RILA(name, pattern, imm_type) \ -SLJIT_S390X_INSTRUCTION(name, sljit_gpr reg, imm_type imm) \ -{ \ - SLJIT_ASSERT(have_eimm()); \ - return (pattern) | R36A(reg) | ((sljit_ins)imm & 0xffffffffu); \ -} - -/* ADD IMMEDIATE */ -SLJIT_S390X_RILA(agfi, 0xc20800000000, sljit_s32) - -/* ADD IMMEDIATE HIGH */ -SLJIT_S390X_RILA(aih, 0xcc0800000000, sljit_s32) /* TODO(mundaym): high-word facility? */ - -/* AND IMMEDIATE */ -SLJIT_S390X_RILA(nihf, 0xc00a00000000, sljit_u32) - -/* EXCLUSIVE OR IMMEDIATE */ -SLJIT_S390X_RILA(xilf, 0xc00700000000, sljit_u32) - -/* INSERT IMMEDIATE */ -SLJIT_S390X_RILA(iihf, 0xc00800000000, sljit_u32) -SLJIT_S390X_RILA(iilf, 0xc00900000000, sljit_u32) - -/* LOAD IMMEDIATE */ -SLJIT_S390X_RILA(lgfi, 0xc00100000000, sljit_s32) - -/* LOAD LOGICAL IMMEDIATE */ -SLJIT_S390X_RILA(llihf, 0xc00e00000000, sljit_u32) -SLJIT_S390X_RILA(llilf, 0xc00f00000000, sljit_u32) - -/* SUBTRACT LOGICAL IMMEDIATE */ -SLJIT_S390X_RILA(slfi, 0xc20500000000, sljit_u32) - -#undef SLJIT_S390X_RILA - -/* RX-a form instructions */ -#define SLJIT_S390X_RXA(name, pattern) \ -SLJIT_S390X_INSTRUCTION(name, sljit_gpr r, sljit_s32 d, sljit_gpr x, sljit_gpr b) \ -{ \ - SLJIT_ASSERT((d & 0xfff) == d); \ -\ - return (pattern) | R20A(r) | R16A(x) | R12A(b) | (sljit_ins)(d & 0xfff); \ -} - -/* LOAD */ -SLJIT_S390X_RXA(l, 0x58000000) - -/* LOAD ADDRESS */ -SLJIT_S390X_RXA(la, 0x41000000) - -/* LOAD HALFWORD */ -SLJIT_S390X_RXA(lh, 0x48000000) - -/* MULTIPLY SINGLE */ -SLJIT_S390X_RXA(ms, 0x71000000) - -/* STORE */ -SLJIT_S390X_RXA(st, 0x50000000) - -/* STORE CHARACTER */ -SLJIT_S390X_RXA(stc, 0x42000000) - -/* STORE HALFWORD */ -SLJIT_S390X_RXA(sth, 0x40000000) - -#undef SLJIT_S390X_RXA - -/* RXY-a instructions */ -#define SLJIT_S390X_RXYA(name, pattern, cond) \ -SLJIT_S390X_INSTRUCTION(name, sljit_gpr r, sljit_s32 d, sljit_gpr x, sljit_gpr b) \ -{ \ - SLJIT_ASSERT(cond); \ -\ - return (pattern) | R36A(r) | R32A(x) | R28A(b) | disp_s20(d); \ -} - -/* LOAD */ -SLJIT_S390X_RXYA(ly, 0xe30000000058, have_ldisp()) -SLJIT_S390X_RXYA(lg, 0xe30000000004, 1) -SLJIT_S390X_RXYA(lgf, 0xe30000000014, 1) - -/* LOAD BYTE */ -SLJIT_S390X_RXYA(lb, 0xe30000000076, have_ldisp()) -SLJIT_S390X_RXYA(lgb, 0xe30000000077, have_ldisp()) - -/* LOAD HALFWORD */ -SLJIT_S390X_RXYA(lhy, 0xe30000000078, have_ldisp()) -SLJIT_S390X_RXYA(lgh, 0xe30000000015, 1) - -/* LOAD LOGICAL */ -SLJIT_S390X_RXYA(llgf, 0xe30000000016, 1) - -/* LOAD LOGICAL CHARACTER */ -SLJIT_S390X_RXYA(llc, 0xe30000000094, have_eimm()) -SLJIT_S390X_RXYA(llgc, 0xe30000000090, 1) - -/* LOAD LOGICAL HALFWORD */ -SLJIT_S390X_RXYA(llh, 0xe30000000095, have_eimm()) -SLJIT_S390X_RXYA(llgh, 0xe30000000091, 1) - -/* MULTIPLY SINGLE */ -SLJIT_S390X_RXYA(msy, 0xe30000000051, have_ldisp()) -SLJIT_S390X_RXYA(msg, 0xe3000000000c, 1) - -/* STORE */ -SLJIT_S390X_RXYA(sty, 0xe30000000050, have_ldisp()) -SLJIT_S390X_RXYA(stg, 0xe30000000024, 1) - -/* STORE CHARACTER */ -SLJIT_S390X_RXYA(stcy, 0xe30000000072, have_ldisp()) - -/* STORE HALFWORD */ -SLJIT_S390X_RXYA(sthy, 0xe30000000070, have_ldisp()) - -#undef SLJIT_S390X_RXYA - -/* RSY-a instructions */ -#define SLJIT_S390X_RSYA(name, pattern, cond) \ -SLJIT_S390X_INSTRUCTION(name, sljit_gpr dst, sljit_gpr src, sljit_s32 d, sljit_gpr b) \ -{ \ - SLJIT_ASSERT(cond); \ -\ - return (pattern) | R36A(dst) | R32A(src) | R28A(b) | disp_s20(d); \ -} - -/* LOAD MULTIPLE */ -SLJIT_S390X_RSYA(lmg, 0xeb0000000004, 1) - -/* SHIFT LEFT LOGICAL */ -SLJIT_S390X_RSYA(sllg, 0xeb000000000d, 1) - -/* SHIFT RIGHT SINGLE */ -SLJIT_S390X_RSYA(srag, 0xeb000000000a, 1) - -/* STORE MULTIPLE */ -SLJIT_S390X_RSYA(stmg, 0xeb0000000024, 1) - -#undef SLJIT_S390X_RSYA - -/* RIE-f instructions (require general-instructions-extension facility) */ -#define SLJIT_S390X_RIEF(name, pattern) \ -SLJIT_S390X_INSTRUCTION(name, sljit_gpr dst, sljit_gpr src, sljit_u8 start, sljit_u8 end, sljit_u8 rot) \ -{ \ - sljit_ins i3, i4, i5; \ -\ - SLJIT_ASSERT(have_genext()); \ - i3 = (sljit_ins)start << 24; \ - i4 = (sljit_ins)end << 16; \ - i5 = (sljit_ins)rot << 8; \ -\ - return (pattern) | R36A(dst & 0xf) | R32A(src & 0xf) | i3 | i4 | i5; \ -} - -/* ROTATE THEN AND SELECTED BITS */ -/* SLJIT_S390X_RIEF(rnsbg, 0xec0000000054) */ - -/* ROTATE THEN EXCLUSIVE OR SELECTED BITS */ -/* SLJIT_S390X_RIEF(rxsbg, 0xec0000000057) */ - -/* ROTATE THEN OR SELECTED BITS */ -SLJIT_S390X_RIEF(rosbg, 0xec0000000056) - -/* ROTATE THEN INSERT SELECTED BITS */ -/* SLJIT_S390X_RIEF(risbg, 0xec0000000055) */ -/* SLJIT_S390X_RIEF(risbgn, 0xec0000000059) */ - -/* ROTATE THEN INSERT SELECTED BITS HIGH */ -SLJIT_S390X_RIEF(risbhg, 0xec000000005d) - -/* ROTATE THEN INSERT SELECTED BITS LOW */ -/* SLJIT_S390X_RIEF(risblg, 0xec0000000051) */ - -#undef SLJIT_S390X_RIEF - -/* RRF-c instructions (require load/store-on-condition 1 facility) */ -#define SLJIT_S390X_RRFC(name, pattern) \ -SLJIT_S390X_INSTRUCTION(name, sljit_gpr dst, sljit_gpr src, sljit_uw mask) \ -{ \ - sljit_ins m3; \ -\ - SLJIT_ASSERT(have_lscond1()); \ - m3 = (sljit_ins)(mask & 0xf) << 12; \ -\ - return (pattern) | m3 | R4A(dst) | R0A(src); \ -} - -/* LOAD HALFWORD IMMEDIATE ON CONDITION */ -SLJIT_S390X_RRFC(locr, 0xb9f20000) -SLJIT_S390X_RRFC(locgr, 0xb9e20000) - -#undef SLJIT_S390X_RRFC - -/* RIE-g instructions (require load/store-on-condition 2 facility) */ -#define SLJIT_S390X_RIEG(name, pattern) \ -SLJIT_S390X_INSTRUCTION(name, sljit_gpr reg, sljit_sw imm, sljit_uw mask) \ -{ \ - sljit_ins m3, i2; \ -\ - SLJIT_ASSERT(have_lscond2()); \ - m3 = (sljit_ins)(mask & 0xf) << 32; \ - i2 = (sljit_ins)(imm & 0xffffL) << 16; \ -\ - return (pattern) | R36A(reg) | m3 | i2; \ -} - -/* LOAD HALFWORD IMMEDIATE ON CONDITION */ -SLJIT_S390X_RIEG(lochi, 0xec0000000042) -SLJIT_S390X_RIEG(locghi, 0xec0000000046) - -#undef SLJIT_S390X_RIEG - -#define SLJIT_S390X_RILB(name, pattern, cond) \ -SLJIT_S390X_INSTRUCTION(name, sljit_gpr reg, sljit_sw ri) \ -{ \ - SLJIT_ASSERT(cond); \ -\ - return (pattern) | R36A(reg) | (sljit_ins)(ri & 0xffffffff); \ -} - -/* BRANCH RELATIVE AND SAVE LONG */ -SLJIT_S390X_RILB(brasl, 0xc00500000000, 1) - -/* LOAD ADDRESS RELATIVE LONG */ -SLJIT_S390X_RILB(larl, 0xc00000000000, 1) - -/* LOAD RELATIVE LONG */ -SLJIT_S390X_RILB(lgrl, 0xc40800000000, have_genext()) - -#undef SLJIT_S390X_RILB - -SLJIT_S390X_INSTRUCTION(br, sljit_gpr target) -{ - return 0x07f0 | target; -} - -SLJIT_S390X_INSTRUCTION(brc, sljit_uw mask, sljit_sw target) -{ - sljit_ins m1 = (sljit_ins)(mask & 0xf) << 20; - sljit_ins ri2 = (sljit_ins)target & 0xffff; - return 0xa7040000L | m1 | ri2; -} - -SLJIT_S390X_INSTRUCTION(brcl, sljit_uw mask, sljit_sw target) -{ - sljit_ins m1 = (sljit_ins)(mask & 0xf) << 36; - sljit_ins ri2 = (sljit_ins)target & 0xffffffff; - return 0xc00400000000L | m1 | ri2; -} - -SLJIT_S390X_INSTRUCTION(flogr, sljit_gpr dst, sljit_gpr src) -{ - SLJIT_ASSERT(have_eimm()); - return 0xb9830000 | R8A(dst) | R0A(src); -} - -/* INSERT PROGRAM MASK */ -SLJIT_S390X_INSTRUCTION(ipm, sljit_gpr dst) -{ - return 0xb2220000 | R4A(dst); -} - -/* SET PROGRAM MASK */ -SLJIT_S390X_INSTRUCTION(spm, sljit_gpr dst) -{ - return 0x0400 | R4A(dst); -} - -/* ROTATE THEN INSERT SELECTED BITS HIGH (ZERO) */ -SLJIT_S390X_INSTRUCTION(risbhgz, sljit_gpr dst, sljit_gpr src, sljit_u8 start, sljit_u8 end, sljit_u8 rot) -{ - return risbhg(dst, src, start, 0x8 | end, rot); -} - -#undef SLJIT_S390X_INSTRUCTION - -static sljit_s32 update_zero_overflow(struct sljit_compiler *compiler, sljit_s32 op, sljit_gpr dst_r) -{ - /* Condition codes: bits 18 and 19. - Transformation: - 0 (zero and no overflow) : unchanged - 1 (non-zero and no overflow) : unchanged - 2 (zero and overflow) : decreased by 1 - 3 (non-zero and overflow) : decreased by 1 if non-zero */ - FAIL_IF(push_inst(compiler, brc(0xc, 2 + 2 + ((op & SLJIT_32) ? 1 : 2) + 2 + 3 + 1))); - FAIL_IF(push_inst(compiler, ipm(tmp1))); - FAIL_IF(push_inst(compiler, (op & SLJIT_32) ? or(dst_r, dst_r) : ogr(dst_r, dst_r))); - FAIL_IF(push_inst(compiler, brc(0x8, 2 + 3))); - FAIL_IF(push_inst(compiler, slfi(tmp1, 0x10000000))); - FAIL_IF(push_inst(compiler, spm(tmp1))); - return SLJIT_SUCCESS; -} - -/* load 64-bit immediate into register without clobbering flags */ -static sljit_s32 push_load_imm_inst(struct sljit_compiler *compiler, sljit_gpr target, sljit_sw v) -{ - /* 4 byte instructions */ - if (is_s16(v)) - return push_inst(compiler, lghi(target, (sljit_s16)v)); - - if (((sljit_uw)v & ~(sljit_uw)0x000000000000ffff) == 0) - return push_inst(compiler, llill(target, (sljit_u16)v)); - - if (((sljit_uw)v & ~(sljit_uw)0x00000000ffff0000) == 0) - return push_inst(compiler, llilh(target, (sljit_u16)(v >> 16))); - - if (((sljit_uw)v & ~(sljit_uw)0x0000ffff00000000) == 0) - return push_inst(compiler, llihl(target, (sljit_u16)(v >> 32))); - - if (((sljit_uw)v & ~(sljit_uw)0xffff000000000000) == 0) - return push_inst(compiler, llihh(target, (sljit_u16)(v >> 48))); - - /* 6 byte instructions (requires extended immediate facility) */ - if (have_eimm()) { - if (is_s32(v)) - return push_inst(compiler, lgfi(target, (sljit_s32)v)); - - if (((sljit_uw)v >> 32) == 0) - return push_inst(compiler, llilf(target, (sljit_u32)v)); - - if (((sljit_uw)v << 32) == 0) - return push_inst(compiler, llihf(target, (sljit_u32)((sljit_uw)v >> 32))); - - FAIL_IF(push_inst(compiler, llilf(target, (sljit_u32)v))); - return push_inst(compiler, iihf(target, (sljit_u32)(v >> 32))); - } - - /* TODO(mundaym): instruction sequences that don't use extended immediates */ - abort(); -} - -struct addr { - sljit_gpr base; - sljit_gpr index; - sljit_s32 offset; -}; - -/* transform memory operand into D(X,B) form with a signed 20-bit offset */ -static sljit_s32 make_addr_bxy(struct sljit_compiler *compiler, - struct addr *addr, sljit_s32 mem, sljit_sw off, - sljit_gpr tmp /* clobbered, must not be r0 */) -{ - sljit_gpr base = r0; - sljit_gpr index = r0; - - SLJIT_ASSERT(tmp != r0); - if (mem & REG_MASK) - base = gpr(mem & REG_MASK); - - if (mem & OFFS_REG_MASK) { - index = gpr(OFFS_REG(mem)); - if (off != 0) { - /* shift and put the result into tmp */ - SLJIT_ASSERT(0 <= off && off < 64); - FAIL_IF(push_inst(compiler, sllg(tmp, index, (sljit_s32)off, 0))); - index = tmp; - off = 0; /* clear offset */ - } - } - else if (!is_s20(off)) { - FAIL_IF(push_load_imm_inst(compiler, tmp, off)); - index = tmp; - off = 0; /* clear offset */ - } - addr->base = base; - addr->index = index; - addr->offset = (sljit_s32)off; - return SLJIT_SUCCESS; -} - -/* transform memory operand into D(X,B) form with an unsigned 12-bit offset */ -static sljit_s32 make_addr_bx(struct sljit_compiler *compiler, - struct addr *addr, sljit_s32 mem, sljit_sw off, - sljit_gpr tmp /* clobbered, must not be r0 */) -{ - sljit_gpr base = r0; - sljit_gpr index = r0; - - SLJIT_ASSERT(tmp != r0); - if (mem & REG_MASK) - base = gpr(mem & REG_MASK); - - if (mem & OFFS_REG_MASK) { - index = gpr(OFFS_REG(mem)); - if (off != 0) { - /* shift and put the result into tmp */ - SLJIT_ASSERT(0 <= off && off < 64); - FAIL_IF(push_inst(compiler, sllg(tmp, index, (sljit_s32)off, 0))); - index = tmp; - off = 0; /* clear offset */ - } - } - else if (!is_u12(off)) { - FAIL_IF(push_load_imm_inst(compiler, tmp, off)); - index = tmp; - off = 0; /* clear offset */ - } - addr->base = base; - addr->index = index; - addr->offset = (sljit_s32)off; - return SLJIT_SUCCESS; -} - -#define EVAL(op, r, addr) op(r, addr.offset, addr.index, addr.base) -#define WHEN(cond, r, i1, i2, addr) \ - (cond) ? EVAL(i1, r, addr) : EVAL(i2, r, addr) - -/* May clobber tmp1. */ -static sljit_s32 load_word(struct sljit_compiler *compiler, sljit_gpr dst_r, - sljit_s32 src, sljit_sw srcw, - sljit_s32 is_32bit) -{ - struct addr addr; - sljit_ins ins; - - SLJIT_ASSERT(src & SLJIT_MEM); - - if (is_32bit && ((src & OFFS_REG_MASK) || is_u12(srcw) || !is_s20(srcw))) { - FAIL_IF(make_addr_bx(compiler, &addr, src, srcw, tmp1)); - return push_inst(compiler, 0x58000000 /* l */ | R20A(dst_r) | R16A(addr.index) | R12A(addr.base) | (sljit_ins)addr.offset); - } - - FAIL_IF(make_addr_bxy(compiler, &addr, src, srcw, tmp1)); - - ins = is_32bit ? 0xe30000000058 /* ly */ : 0xe30000000004 /* lg */; - return push_inst(compiler, ins | R36A(dst_r) | R32A(addr.index) | R28A(addr.base) | disp_s20(addr.offset)); -} - -/* May clobber tmp1. */ -static sljit_s32 load_unsigned_word(struct sljit_compiler *compiler, sljit_gpr dst_r, - sljit_s32 src, sljit_sw srcw, - sljit_s32 is_32bit) -{ - struct addr addr; - sljit_ins ins; - - SLJIT_ASSERT(src & SLJIT_MEM); - - FAIL_IF(make_addr_bxy(compiler, &addr, src, srcw, tmp1)); - - ins = is_32bit ? 0xe30000000016 /* llgf */ : 0xe30000000004 /* lg */; - return push_inst(compiler, ins | R36A(dst_r) | R32A(addr.index) | R28A(addr.base) | disp_s20(addr.offset)); -} - -/* May clobber tmp1. */ -static sljit_s32 store_word(struct sljit_compiler *compiler, sljit_gpr src_r, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 is_32bit) -{ - struct addr addr; - sljit_ins ins; - - SLJIT_ASSERT(dst & SLJIT_MEM); - - if (is_32bit && ((dst & OFFS_REG_MASK) || is_u12(dstw) || !is_s20(dstw))) { - FAIL_IF(make_addr_bx(compiler, &addr, dst, dstw, tmp1)); - return push_inst(compiler, 0x50000000 /* st */ | R20A(src_r) | R16A(addr.index) | R12A(addr.base) | (sljit_ins)addr.offset); - } - - FAIL_IF(make_addr_bxy(compiler, &addr, dst, dstw, tmp1)); - - ins = is_32bit ? 0xe30000000050 /* sty */ : 0xe30000000024 /* stg */; - return push_inst(compiler, ins | R36A(src_r) | R32A(addr.index) | R28A(addr.base) | disp_s20(addr.offset)); -} - -#undef WHEN - -static sljit_s32 emit_move(struct sljit_compiler *compiler, - sljit_gpr dst_r, - sljit_s32 src, sljit_sw srcw) -{ - SLJIT_ASSERT(!IS_GPR_REG(src) || dst_r != gpr(src & REG_MASK)); - - if (src & SLJIT_IMM) - return push_load_imm_inst(compiler, dst_r, srcw); - - if (src & SLJIT_MEM) - return load_word(compiler, dst_r, src, srcw, (compiler->mode & SLJIT_32) != 0); - - sljit_gpr src_r = gpr(src & REG_MASK); - return push_inst(compiler, (compiler->mode & SLJIT_32) ? lr(dst_r, src_r) : lgr(dst_r, src_r)); -} - -static sljit_s32 emit_rr(struct sljit_compiler *compiler, sljit_ins ins, - sljit_s32 dst, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - sljit_gpr dst_r = tmp0; - sljit_gpr src_r = tmp1; - sljit_s32 needs_move = 1; - - if (FAST_IS_REG(dst)) { - dst_r = gpr(dst); - - if (dst == src1) - needs_move = 0; - else if (dst == src2) { - dst_r = tmp0; - needs_move = 2; - } - } - - if (needs_move) - FAIL_IF(emit_move(compiler, dst_r, src1, src1w)); - - if (FAST_IS_REG(src2)) - src_r = gpr(src2); - else - FAIL_IF(emit_move(compiler, tmp1, src2, src2w)); - - FAIL_IF(push_inst(compiler, ins | R4A(dst_r) | R0A(src_r))); - - if (needs_move != 2) - return SLJIT_SUCCESS; - - dst_r = gpr(dst & REG_MASK); - return push_inst(compiler, (compiler->mode & SLJIT_32) ? lr(dst_r, tmp0) : lgr(dst_r, tmp0)); -} - -static sljit_s32 emit_rr1(struct sljit_compiler *compiler, sljit_ins ins, - sljit_s32 dst, - sljit_s32 src1, sljit_sw src1w) -{ - sljit_gpr dst_r = FAST_IS_REG(dst) ? gpr(dst) : tmp0; - sljit_gpr src_r = tmp1; - - if (FAST_IS_REG(src1)) - src_r = gpr(src1); - else - FAIL_IF(emit_move(compiler, tmp1, src1, src1w)); - - return push_inst(compiler, ins | R4A(dst_r) | R0A(src_r)); -} - -static sljit_s32 emit_rrf(struct sljit_compiler *compiler, sljit_ins ins, - sljit_s32 dst, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - sljit_gpr dst_r = FAST_IS_REG(dst) ? gpr(dst & REG_MASK) : tmp0; - sljit_gpr src1_r = tmp0; - sljit_gpr src2_r = tmp1; - - if (FAST_IS_REG(src1)) - src1_r = gpr(src1); - else - FAIL_IF(emit_move(compiler, tmp0, src1, src1w)); - - if (FAST_IS_REG(src2)) - src2_r = gpr(src2); - else - FAIL_IF(emit_move(compiler, tmp1, src2, src2w)); - - return push_inst(compiler, ins | R4A(dst_r) | R0A(src1_r) | R12A(src2_r)); -} - -typedef enum { - RI_A, - RIL_A, -} emit_ril_type; - -static sljit_s32 emit_ri(struct sljit_compiler *compiler, sljit_ins ins, - sljit_s32 dst, - sljit_s32 src1, sljit_sw src1w, - sljit_sw src2w, - emit_ril_type type) -{ - sljit_gpr dst_r = tmp0; - sljit_s32 needs_move = 1; - - if (FAST_IS_REG(dst)) { - dst_r = gpr(dst); - - if (dst == src1) - needs_move = 0; - } - - if (needs_move) - FAIL_IF(emit_move(compiler, dst_r, src1, src1w)); - - if (type == RIL_A) - return push_inst(compiler, ins | R36A(dst_r) | (src2w & 0xffffffff)); - return push_inst(compiler, ins | R20A(dst_r) | (src2w & 0xffff)); -} - -static sljit_s32 emit_rie_d(struct sljit_compiler *compiler, sljit_ins ins, - sljit_s32 dst, - sljit_s32 src1, sljit_sw src1w, - sljit_sw src2w) -{ - sljit_gpr dst_r = FAST_IS_REG(dst) ? gpr(dst) : tmp0; - sljit_gpr src_r = tmp0; - - if (!FAST_IS_REG(src1)) - FAIL_IF(emit_move(compiler, tmp0, src1, src1w)); - else - src_r = gpr(src1 & REG_MASK); - - return push_inst(compiler, ins | R36A(dst_r) | R32A(src_r) | (sljit_ins)(src2w & 0xffff) << 16); -} - -typedef enum { - RX_A, - RXY_A, -} emit_rx_type; - -static sljit_s32 emit_rx(struct sljit_compiler *compiler, sljit_ins ins, - sljit_s32 dst, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w, - emit_rx_type type) -{ - sljit_gpr dst_r = tmp0; - sljit_s32 needs_move = 1; - sljit_gpr base, index; - - SLJIT_ASSERT(src2 & SLJIT_MEM); - - if (FAST_IS_REG(dst)) { - dst_r = gpr(dst); - - if (dst == src1) - needs_move = 0; - else if (dst == (src2 & REG_MASK) || (dst == OFFS_REG(src2))) { - dst_r = tmp0; - needs_move = 2; - } - } - - if (needs_move) - FAIL_IF(emit_move(compiler, dst_r, src1, src1w)); - - base = gpr(src2 & REG_MASK); - index = tmp0; - - if (src2 & OFFS_REG_MASK) { - index = gpr(OFFS_REG(src2)); - - if (src2w != 0) { - FAIL_IF(push_inst(compiler, sllg(tmp1, index, src2w & 0x3, 0))); - src2w = 0; - index = tmp1; - } - } else if ((type == RX_A && !is_u12(src2w)) || (type == RXY_A && !is_s20(src2w))) { - FAIL_IF(push_load_imm_inst(compiler, tmp1, src2w)); - - if (src2 & REG_MASK) - index = tmp1; - else - base = tmp1; - src2w = 0; - } - - if (type == RX_A) - ins |= R20A(dst_r) | R16A(index) | R12A(base) | (sljit_ins)src2w; - else - ins |= R36A(dst_r) | R32A(index) | R28A(base) | disp_s20((sljit_s32)src2w); - - FAIL_IF(push_inst(compiler, ins)); - - if (needs_move != 2) - return SLJIT_SUCCESS; - - dst_r = gpr(dst); - return push_inst(compiler, (compiler->mode & SLJIT_32) ? lr(dst_r, tmp0) : lgr(dst_r, tmp0)); -} - -static sljit_s32 emit_siy(struct sljit_compiler *compiler, sljit_ins ins, - sljit_s32 dst, sljit_sw dstw, - sljit_sw srcw) -{ - SLJIT_ASSERT(dst & SLJIT_MEM); - - sljit_gpr dst_r = tmp1; - - if (dst & OFFS_REG_MASK) { - sljit_gpr index = tmp1; - - if ((dstw & 0x3) == 0) - index = gpr(OFFS_REG(dst)); - else - FAIL_IF(push_inst(compiler, sllg(tmp1, index, dstw & 0x3, 0))); - - FAIL_IF(push_inst(compiler, la(tmp1, 0, dst_r, index))); - dstw = 0; - } - else if (!is_s20(dstw)) { - FAIL_IF(push_load_imm_inst(compiler, tmp1, dstw)); - - if (dst & REG_MASK) - FAIL_IF(push_inst(compiler, la(tmp1, 0, dst_r, tmp1))); - - dstw = 0; - } - else - dst_r = gpr(dst & REG_MASK); - - return push_inst(compiler, ins | ((sljit_ins)(srcw & 0xff) << 32) | R28A(dst_r) | disp_s20((sljit_s32)dstw)); -} - -struct ins_forms { - sljit_ins op_r; - sljit_ins op_gr; - sljit_ins op_rk; - sljit_ins op_grk; - sljit_ins op; - sljit_ins op_y; - sljit_ins op_g; -}; - -static sljit_s32 emit_commutative(struct sljit_compiler *compiler, const struct ins_forms *forms, - sljit_s32 dst, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - sljit_s32 mode = compiler->mode; - sljit_ins ins, ins_k; - - if ((src1 | src2) & SLJIT_MEM) { - sljit_ins ins12, ins20; - - if (mode & SLJIT_32) { - ins12 = forms->op; - ins20 = forms->op_y; - } - else { - ins12 = 0; - ins20 = forms->op_g; - } - - if (ins12 && ins20) { - /* Extra instructions needed for address computation can be executed independently. */ - if ((src2 & SLJIT_MEM) && (!(src1 & SLJIT_MEM) - || ((src1 & OFFS_REG_MASK) ? (src1w & 0x3) == 0 : is_s20(src1w)))) { - if ((src2 & OFFS_REG_MASK) || is_u12(src2w) || !is_s20(src2w)) - return emit_rx(compiler, ins12, dst, src1, src1w, src2, src2w, RX_A); - - return emit_rx(compiler, ins20, dst, src1, src1w, src2, src2w, RXY_A); - } - - if (src1 & SLJIT_MEM) { - if ((src1 & OFFS_REG_MASK) || is_u12(src1w) || !is_s20(src1w)) - return emit_rx(compiler, ins12, dst, src2, src2w, src1, src1w, RX_A); - - return emit_rx(compiler, ins20, dst, src2, src2w, src1, src1w, RXY_A); - } - } - else if (ins12 || ins20) { - emit_rx_type rx_type; - - if (ins12) { - rx_type = RX_A; - ins = ins12; - } - else { - rx_type = RXY_A; - ins = ins20; - } - - if ((src2 & SLJIT_MEM) && (!(src1 & SLJIT_MEM) - || ((src1 & OFFS_REG_MASK) ? (src1w & 0x3) == 0 : (rx_type == RX_A ? is_u12(src1w) : is_s20(src1w))))) - return emit_rx(compiler, ins, dst, src1, src1w, src2, src2w, rx_type); - - if (src1 & SLJIT_MEM) - return emit_rx(compiler, ins, dst, src2, src2w, src1, src1w, rx_type); - } - } - - if (mode & SLJIT_32) { - ins = forms->op_r; - ins_k = forms->op_rk; - } - else { - ins = forms->op_gr; - ins_k = forms->op_grk; - } - - SLJIT_ASSERT(ins != 0 || ins_k != 0); - - if (ins && FAST_IS_REG(dst)) { - if (dst == src1) - return emit_rr(compiler, ins, dst, src1, src1w, src2, src2w); - - if (dst == src2) - return emit_rr(compiler, ins, dst, src2, src2w, src1, src1w); - } - - if (ins_k == 0) - return emit_rr(compiler, ins, dst, src1, src1w, src2, src2w); - - return emit_rrf(compiler, ins_k, dst, src1, src1w, src2, src2w); -} - -static sljit_s32 emit_non_commutative(struct sljit_compiler *compiler, const struct ins_forms *forms, - sljit_s32 dst, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - sljit_s32 mode = compiler->mode; - sljit_ins ins; - - if (src2 & SLJIT_MEM) { - sljit_ins ins12, ins20; - - if (mode & SLJIT_32) { - ins12 = forms->op; - ins20 = forms->op_y; - } - else { - ins12 = 0; - ins20 = forms->op_g; - } - - if (ins12 && ins20) { - if ((src2 & OFFS_REG_MASK) || is_u12(src2w) || !is_s20(src2w)) - return emit_rx(compiler, ins12, dst, src1, src1w, src2, src2w, RX_A); - - return emit_rx(compiler, ins20, dst, src1, src1w, src2, src2w, RXY_A); - } - else if (ins12) - return emit_rx(compiler, ins12, dst, src1, src1w, src2, src2w, RX_A); - else if (ins20) - return emit_rx(compiler, ins20, dst, src1, src1w, src2, src2w, RXY_A); - } - - ins = (mode & SLJIT_32) ? forms->op_rk : forms->op_grk; - - if (ins == 0 || (FAST_IS_REG(dst) && dst == src1)) - return emit_rr(compiler, (mode & SLJIT_32) ? forms->op_r : forms->op_gr, dst, src1, src1w, src2, src2w); - - return emit_rrf(compiler, ins, dst, src1, src1w, src2, src2w); -} - -SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler) -{ - struct sljit_label *label; - struct sljit_jump *jump; - struct sljit_s390x_const *const_; - struct sljit_put_label *put_label; - sljit_sw executable_offset; - sljit_uw ins_size = 0; /* instructions */ - sljit_uw pool_size = 0; /* literal pool */ - sljit_uw pad_size; - sljit_uw i, j = 0; - struct sljit_memory_fragment *buf; - void *code, *code_ptr; - sljit_uw *pool, *pool_ptr; - sljit_sw source, offset; /* TODO(carenas): only need 32 bit */ - - 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); - } - } - - /* emit trailing label */ - if (label && label->size == j) { - label->size = ins_size; - label = label->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); - 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 - * globally; if generated code is too big could - * need offsets bigger than 32bit words and asser() - */ - pool = (sljit_uw *)((sljit_uw)code + ins_size + pad_size); - pool_ptr = pool; - const_ = (struct sljit_s390x_const *)compiler->consts; - - /* 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; - - /* 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; - - /* update instruction with relative address of constant */ - source = (sljit_sw)code_ptr; - offset = (sljit_sw)pool_ptr - source; - - SLJIT_ASSERT(!(offset & 1)); - offset >>= 1; /* halfword (not byte) offset */ - SLJIT_ASSERT(is_s32(offset)); - - ins |= (sljit_ins)offset & 0xffffffff; - - /* update address */ - const_->const_.addr = (sljit_uw)pool_ptr; - - /* store initial value into pool and update pool address */ - *(pool_ptr++) = (sljit_uw)const_->init_value; - - /* move to next constant */ - const_ = (struct sljit_s390x_const *)const_->const_.next; - } - 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)) { - 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)); - - 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 */ - sljit_ins op = (ins >> 32) & 0xf; - sljit_ins 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; - - /* offset must be halfword aligned */ - SLJIT_ASSERT(!(offset & 1)); - offset >>= 1; - SLJIT_ASSERT(is_s32(offset)); /* TODO(mundaym): handle arbitrary offsets */ - - /* 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(put_label->label); - put_label->addr = (sljit_uw)code_ptr; - - /* store target into pool */ - *pool_ptr = put_label->label->addr; - 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; - - put_label = put_label->next; - } - encode_inst(&code_ptr, ins); - } - } - 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; - code = SLJIT_ADD_EXEC_OFFSET(code, executable_offset); - code_ptr = SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset); - SLJIT_CACHE_FLUSH(code, code_ptr); - SLJIT_UPDATE_WX_FLAGS(code, code_ptr, 1); - return code; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type) -{ - /* TODO(mundaym): implement all */ - switch (feature_type) { - case SLJIT_HAS_FPU: - case SLJIT_HAS_CLZ: - case SLJIT_HAS_ROT: - case SLJIT_HAS_PREFETCH: - return 1; - case SLJIT_HAS_CTZ: - return 2; - case SLJIT_HAS_CMOV: - return have_lscond1() ? 1 : 0; - } - return 0; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_cmp_info(sljit_s32 type) -{ - return (type >= SLJIT_UNORDERED && type <= SLJIT_ORDERED_LESS_EQUAL); -} - -/* --------------------------------------------------------------------- */ -/* Entry, exit */ -/* --------------------------------------------------------------------- */ - -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, - sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size) -{ - sljit_s32 saved_arg_count = SLJIT_KEPT_SAVEDS_COUNT(options); - sljit_s32 offset, i, tmp; - - CHECK_ERROR(); - CHECK(check_sljit_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size)); - set_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size); - - /* Saved registers are stored in callee allocated save area. */ - SLJIT_ASSERT(gpr(SLJIT_FIRST_SAVED_REG) == r6 && gpr(SLJIT_S0) == r13); - - offset = 2 * SSIZE_OF(sw); - if (saveds + scratches >= SLJIT_NUMBER_OF_REGISTERS) { - if (saved_arg_count == 0) { - FAIL_IF(push_inst(compiler, stmg(r6, r14, offset, r15))); - offset += 9 * SSIZE_OF(sw); - } else { - FAIL_IF(push_inst(compiler, stmg(r6, r13 - (sljit_gpr)saved_arg_count, offset, r15))); - offset += (8 - saved_arg_count) * SSIZE_OF(sw); - } - } else { - if (scratches == SLJIT_FIRST_SAVED_REG) { - FAIL_IF(push_inst(compiler, stg(r6, offset, 0, r15))); - offset += SSIZE_OF(sw); - } else if (scratches > SLJIT_FIRST_SAVED_REG) { - FAIL_IF(push_inst(compiler, stmg(r6, r6 + (sljit_gpr)(scratches - SLJIT_FIRST_SAVED_REG), offset, r15))); - offset += (scratches - (SLJIT_FIRST_SAVED_REG - 1)) * SSIZE_OF(sw); - } - - if (saved_arg_count == 0) { - if (saveds == 0) { - FAIL_IF(push_inst(compiler, stg(r14, offset, 0, r15))); - offset += SSIZE_OF(sw); - } else { - FAIL_IF(push_inst(compiler, stmg(r14 - (sljit_gpr)saveds, r14, offset, r15))); - offset += (saveds + 1) * SSIZE_OF(sw); - } - } else if (saveds > saved_arg_count) { - if (saveds == saved_arg_count + 1) { - FAIL_IF(push_inst(compiler, stg(r14 - (sljit_gpr)saveds, offset, 0, r15))); - offset += SSIZE_OF(sw); - } else { - FAIL_IF(push_inst(compiler, stmg(r14 - (sljit_gpr)saveds, r13 - (sljit_gpr)saved_arg_count, offset, r15))); - offset += (saveds - saved_arg_count) * SSIZE_OF(sw); - } - } - } - - if (saved_arg_count > 0) { - FAIL_IF(push_inst(compiler, stg(r14, offset, 0, r15))); - offset += SSIZE_OF(sw); - } - - tmp = SLJIT_FS0 - fsaveds; - for (i = SLJIT_FS0; i > tmp; i--) { - FAIL_IF(push_inst(compiler, 0x60000000 /* std */ | F20(i) | R12A(r15) | (sljit_ins)offset)); - offset += SSIZE_OF(sw); - } - - for (i = fscratches; i >= SLJIT_FIRST_SAVED_FLOAT_REG; i--) { - FAIL_IF(push_inst(compiler, 0x60000000 /* std */ | F20(i) | R12A(r15) | (sljit_ins)offset)); - offset += SSIZE_OF(sw); - } - - local_size = (local_size + SLJIT_S390X_DEFAULT_STACK_FRAME_SIZE + 0xf) & ~0xf; - compiler->local_size = local_size; - - FAIL_IF(push_inst(compiler, 0xe30000000071 /* lay */ | R36A(r15) | R28A(r15) | disp_s20(-local_size))); - - if (options & SLJIT_ENTER_REG_ARG) - return SLJIT_SUCCESS; - - arg_types >>= SLJIT_ARG_SHIFT; - saved_arg_count = 0; - tmp = 0; - while (arg_types > 0) { - if ((arg_types & SLJIT_ARG_MASK) < SLJIT_ARG_TYPE_F64) { - if (!(arg_types & SLJIT_ARG_TYPE_SCRATCH_REG)) { - FAIL_IF(push_inst(compiler, lgr(gpr(SLJIT_S0 - saved_arg_count), gpr(SLJIT_R0 + tmp)))); - saved_arg_count++; - } - tmp++; - } - - arg_types >>= SLJIT_ARG_SHIFT; - } - - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(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) -{ - CHECK_ERROR(); - CHECK(check_sljit_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size)); - set_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size); - - compiler->local_size = (local_size + SLJIT_S390X_DEFAULT_STACK_FRAME_SIZE + 0xf) & ~0xf; - return SLJIT_SUCCESS; -} - -static sljit_s32 emit_stack_frame_release(struct sljit_compiler *compiler, sljit_gpr last_reg) -{ - sljit_s32 offset, i, tmp; - sljit_s32 local_size = compiler->local_size; - sljit_s32 saveds = compiler->saveds; - sljit_s32 scratches = compiler->scratches; - sljit_s32 kept_saveds_count = SLJIT_KEPT_SAVEDS_COUNT(compiler->options); - - if (is_u12(local_size)) - FAIL_IF(push_inst(compiler, 0x41000000 /* ly */ | R20A(r15) | R12A(r15) | (sljit_ins)local_size)); - else - FAIL_IF(push_inst(compiler, 0xe30000000071 /* lay */ | R36A(r15) | R28A(r15) | disp_s20(local_size))); - - offset = 2 * SSIZE_OF(sw); - if (saveds + scratches >= SLJIT_NUMBER_OF_REGISTERS) { - if (kept_saveds_count == 0) { - FAIL_IF(push_inst(compiler, lmg(r6, last_reg, offset, r15))); - offset += 9 * SSIZE_OF(sw); - } else { - FAIL_IF(push_inst(compiler, lmg(r6, r13 - (sljit_gpr)kept_saveds_count, offset, r15))); - offset += (8 - kept_saveds_count) * SSIZE_OF(sw); - } - } else { - if (scratches == SLJIT_FIRST_SAVED_REG) { - FAIL_IF(push_inst(compiler, lg(r6, offset, 0, r15))); - offset += SSIZE_OF(sw); - } else if (scratches > SLJIT_FIRST_SAVED_REG) { - FAIL_IF(push_inst(compiler, lmg(r6, r6 + (sljit_gpr)(scratches - SLJIT_FIRST_SAVED_REG), offset, r15))); - offset += (scratches - (SLJIT_FIRST_SAVED_REG - 1)) * SSIZE_OF(sw); - } - - if (kept_saveds_count == 0) { - if (saveds == 0) { - if (last_reg == r14) - FAIL_IF(push_inst(compiler, lg(r14, offset, 0, r15))); - offset += SSIZE_OF(sw); - } else if (saveds == 1 && last_reg == r13) { - FAIL_IF(push_inst(compiler, lg(r13, offset, 0, r15))); - offset += 2 * SSIZE_OF(sw); - } else { - FAIL_IF(push_inst(compiler, lmg(r14 - (sljit_gpr)saveds, last_reg, offset, r15))); - offset += (saveds + 1) * SSIZE_OF(sw); - } - } else if (saveds > kept_saveds_count) { - if (saveds == kept_saveds_count + 1) { - FAIL_IF(push_inst(compiler, lg(r14 - (sljit_gpr)saveds, offset, 0, r15))); - offset += SSIZE_OF(sw); - } else { - FAIL_IF(push_inst(compiler, lmg(r14 - (sljit_gpr)saveds, r13 - (sljit_gpr)kept_saveds_count, offset, r15))); - offset += (saveds - kept_saveds_count) * SSIZE_OF(sw); - } - } - } - - if (kept_saveds_count > 0) { - if (last_reg == r14) - FAIL_IF(push_inst(compiler, lg(r14, offset, 0, r15))); - offset += SSIZE_OF(sw); - } - - tmp = SLJIT_FS0 - compiler->fsaveds; - for (i = SLJIT_FS0; i > tmp; i--) { - FAIL_IF(push_inst(compiler, 0x68000000 /* ld */ | F20(i) | R12A(r15) | (sljit_ins)offset)); - offset += SSIZE_OF(sw); - } - - for (i = compiler->fscratches; i >= SLJIT_FIRST_SAVED_FLOAT_REG; i--) { - FAIL_IF(push_inst(compiler, 0x68000000 /* ld */ | F20(i) | R12A(r15) | (sljit_ins)offset)); - offset += SSIZE_OF(sw); - } - - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_void(struct sljit_compiler *compiler) -{ - CHECK_ERROR(); - CHECK(check_sljit_emit_return_void(compiler)); - - FAIL_IF(emit_stack_frame_release(compiler, r14)); - return push_inst(compiler, br(r14)); /* return */ -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_to(struct sljit_compiler *compiler, - sljit_s32 src, sljit_sw srcw) -{ - CHECK_ERROR(); - CHECK(check_sljit_emit_return_to(compiler, src, srcw)); - - if (src & SLJIT_MEM) { - ADJUST_LOCAL_OFFSET(src, srcw); - FAIL_IF(load_word(compiler, tmp1, src, srcw, 0 /* 64-bit */)); - src = TMP_REG2; - srcw = 0; - } else if (src >= SLJIT_FIRST_SAVED_REG && src <= (SLJIT_S0 - SLJIT_KEPT_SAVEDS_COUNT(compiler->options))) { - FAIL_IF(push_inst(compiler, lgr(tmp1, gpr(src)))); - src = TMP_REG2; - srcw = 0; - } - - FAIL_IF(emit_stack_frame_release(compiler, r13)); - - SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_ijump(compiler, SLJIT_JUMP, src, srcw); -} - -/* --------------------------------------------------------------------- */ -/* Operators */ -/* --------------------------------------------------------------------- */ - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compiler, sljit_s32 op) -{ - sljit_gpr arg0 = gpr(SLJIT_R0); - sljit_gpr arg1 = gpr(SLJIT_R1); - - CHECK_ERROR(); - CHECK(check_sljit_emit_op0(compiler, op)); - - op = GET_OPCODE(op) | (op & SLJIT_32); - switch (op) { - case SLJIT_BREAKPOINT: - /* The following invalid instruction is emitted by gdb. */ - return push_inst(compiler, 0x0001 /* 2-byte trap */); - case SLJIT_NOP: - return push_inst(compiler, 0x0700 /* 2-byte nop */); - case SLJIT_LMUL_UW: - FAIL_IF(push_inst(compiler, mlgr(arg0, arg0))); - break; - case SLJIT_LMUL_SW: - /* signed multiplication from: */ - /* Hacker's Delight, Second Edition: Chapter 8-3. */ - FAIL_IF(push_inst(compiler, srag(tmp0, arg0, 63, 0))); - FAIL_IF(push_inst(compiler, srag(tmp1, arg1, 63, 0))); - FAIL_IF(push_inst(compiler, ngr(tmp0, arg1))); - FAIL_IF(push_inst(compiler, ngr(tmp1, arg0))); - - /* unsigned multiplication */ - FAIL_IF(push_inst(compiler, mlgr(arg0, arg0))); - - FAIL_IF(push_inst(compiler, sgr(arg0, tmp0))); - FAIL_IF(push_inst(compiler, sgr(arg0, tmp1))); - break; - case SLJIT_DIV_U32: - case SLJIT_DIVMOD_U32: - FAIL_IF(push_inst(compiler, lhi(tmp0, 0))); - FAIL_IF(push_inst(compiler, lr(tmp1, arg0))); - FAIL_IF(push_inst(compiler, dlr(tmp0, arg1))); - FAIL_IF(push_inst(compiler, lr(arg0, tmp1))); /* quotient */ - if (op == SLJIT_DIVMOD_U32) - return push_inst(compiler, lr(arg1, tmp0)); /* remainder */ - - return SLJIT_SUCCESS; - case SLJIT_DIV_S32: - case SLJIT_DIVMOD_S32: - FAIL_IF(push_inst(compiler, lhi(tmp0, 0))); - FAIL_IF(push_inst(compiler, lr(tmp1, arg0))); - FAIL_IF(push_inst(compiler, dr(tmp0, arg1))); - FAIL_IF(push_inst(compiler, lr(arg0, tmp1))); /* quotient */ - if (op == SLJIT_DIVMOD_S32) - return push_inst(compiler, lr(arg1, tmp0)); /* remainder */ - - return SLJIT_SUCCESS; - case SLJIT_DIV_UW: - case SLJIT_DIVMOD_UW: - FAIL_IF(push_inst(compiler, lghi(tmp0, 0))); - FAIL_IF(push_inst(compiler, lgr(tmp1, arg0))); - FAIL_IF(push_inst(compiler, dlgr(tmp0, arg1))); - FAIL_IF(push_inst(compiler, lgr(arg0, tmp1))); /* quotient */ - if (op == SLJIT_DIVMOD_UW) - return push_inst(compiler, lgr(arg1, tmp0)); /* remainder */ - - return SLJIT_SUCCESS; - case SLJIT_DIV_SW: - case SLJIT_DIVMOD_SW: - FAIL_IF(push_inst(compiler, lgr(tmp1, arg0))); - FAIL_IF(push_inst(compiler, dsgr(tmp0, arg1))); - FAIL_IF(push_inst(compiler, lgr(arg0, tmp1))); /* quotient */ - if (op == SLJIT_DIVMOD_SW) - return push_inst(compiler, lgr(arg1, tmp0)); /* remainder */ - - return SLJIT_SUCCESS; - case SLJIT_ENDBR: - return SLJIT_SUCCESS; - case SLJIT_SKIP_FRAMES_BEFORE_RETURN: - return SLJIT_SUCCESS; - default: - SLJIT_UNREACHABLE(); - } - /* swap result registers */ - FAIL_IF(push_inst(compiler, lgr(tmp0, arg0))); - FAIL_IF(push_inst(compiler, lgr(arg0, arg1))); - return push_inst(compiler, lgr(arg1, tmp0)); -} - -static sljit_s32 sljit_emit_clz_ctz(struct sljit_compiler *compiler, sljit_s32 op, sljit_gpr dst_r, sljit_gpr src_r) -{ - sljit_s32 is_ctz = (GET_OPCODE(op) == SLJIT_CTZ); - - if ((op & SLJIT_32) && src_r != tmp0) { - FAIL_IF(push_inst(compiler, 0xb9160000 /* llgfr */ | R4A(tmp0) | R0A(src_r))); - src_r = tmp0; - } - - if (is_ctz) { - FAIL_IF(push_inst(compiler, ((op & SLJIT_32) ? 0x1300 /* lcr */ : 0xb9030000 /* lcgr */) | R4A(tmp1) | R0A(src_r))); - - if (src_r == tmp0) - FAIL_IF(push_inst(compiler, ((op & SLJIT_32) ? 0x1400 /* nr */ : 0xb9800000 /* ngr */) | R4A(tmp0) | R0A(tmp1))); - else - FAIL_IF(push_inst(compiler, 0xb9e40000 /* ngrk */ | R12A(tmp1) | R4A(tmp0) | R0A(src_r))); - - src_r = tmp0; - } - - FAIL_IF(push_inst(compiler, 0xb9830000 /* flogr */ | R4A(tmp0) | R0A(src_r))); - - if (is_ctz) - FAIL_IF(push_inst(compiler, 0xec00000000d9 /* aghik */ | R36A(tmp1) | R32A(tmp0) | ((sljit_ins)(-64 & 0xffff) << 16))); - - if (op & SLJIT_32) { - if (!is_ctz && dst_r != tmp0) - return push_inst(compiler, 0xec00000000d9 /* aghik */ | R36A(dst_r) | R32A(tmp0) | ((sljit_ins)(-32 & 0xffff) << 16)); - - FAIL_IF(push_inst(compiler, 0xc20800000000 /* agfi */ | R36A(tmp0) | (sljit_u32)-32)); - } - - if (is_ctz) - FAIL_IF(push_inst(compiler, 0xec0000000057 /* rxsbg */ | R36A(tmp0) | R32A(tmp1) | ((sljit_ins)((op & SLJIT_32) ? 59 : 58) << 24) | (63 << 16) | ((sljit_ins)((op & SLJIT_32) ? 5 : 6) << 8))); - - if (dst_r == tmp0) - return SLJIT_SUCCESS; - - return push_inst(compiler, ((op & SLJIT_32) ? 0x1800 /* lr */ : 0xb9040000 /* lgr */) | R4A(dst_r) | R0A(tmp0)); -} - -/* LEVAL will be defined later with different parameters as needed */ -#define WHEN2(cond, i1, i2) (cond) ? LEVAL(i1) : LEVAL(i2) - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src, sljit_sw srcw) -{ - sljit_ins ins; - struct addr mem; - sljit_gpr dst_r; - sljit_gpr src_r; - sljit_s32 opcode = GET_OPCODE(op); - - CHECK_ERROR(); - CHECK(check_sljit_emit_op1(compiler, op, dst, dstw, src, srcw)); - ADJUST_LOCAL_OFFSET(dst, dstw); - ADJUST_LOCAL_OFFSET(src, srcw); - - if (opcode >= SLJIT_MOV && opcode <= SLJIT_MOV_P) { - /* LOAD REGISTER */ - if (FAST_IS_REG(dst) && FAST_IS_REG(src)) { - dst_r = gpr(dst); - src_r = gpr(src); - switch (opcode | (op & SLJIT_32)) { - /* 32-bit */ - case SLJIT_MOV32_U8: - ins = llcr(dst_r, src_r); - break; - case SLJIT_MOV32_S8: - ins = lbr(dst_r, src_r); - break; - case SLJIT_MOV32_U16: - ins = llhr(dst_r, src_r); - break; - case SLJIT_MOV32_S16: - ins = lhr(dst_r, src_r); - break; - case SLJIT_MOV32: - if (dst_r == src_r) - return SLJIT_SUCCESS; - ins = lr(dst_r, src_r); - break; - /* 64-bit */ - case SLJIT_MOV_U8: - ins = llgcr(dst_r, src_r); - break; - case SLJIT_MOV_S8: - ins = lgbr(dst_r, src_r); - break; - case SLJIT_MOV_U16: - ins = llghr(dst_r, src_r); - break; - case SLJIT_MOV_S16: - ins = lghr(dst_r, src_r); - break; - case SLJIT_MOV_U32: - ins = llgfr(dst_r, src_r); - break; - case SLJIT_MOV_S32: - ins = lgfr(dst_r, src_r); - break; - case SLJIT_MOV: - case SLJIT_MOV_P: - if (dst_r == src_r) - return SLJIT_SUCCESS; - ins = lgr(dst_r, src_r); - break; - default: - ins = 0; - SLJIT_UNREACHABLE(); - break; - } - FAIL_IF(push_inst(compiler, ins)); - return SLJIT_SUCCESS; - } - /* LOAD IMMEDIATE */ - if (FAST_IS_REG(dst) && (src & SLJIT_IMM)) { - switch (opcode) { - case SLJIT_MOV_U8: - srcw = (sljit_sw)((sljit_u8)(srcw)); - break; - case SLJIT_MOV_S8: - srcw = (sljit_sw)((sljit_s8)(srcw)); - break; - case SLJIT_MOV_U16: - srcw = (sljit_sw)((sljit_u16)(srcw)); - break; - case SLJIT_MOV_S16: - srcw = (sljit_sw)((sljit_s16)(srcw)); - break; - case SLJIT_MOV_U32: - srcw = (sljit_sw)((sljit_u32)(srcw)); - break; - case SLJIT_MOV_S32: - case SLJIT_MOV32: - srcw = (sljit_sw)((sljit_s32)(srcw)); - break; - } - return push_load_imm_inst(compiler, gpr(dst), srcw); - } - /* LOAD */ - /* TODO(carenas): avoid reg being defined later */ - #define LEVAL(i) EVAL(i, reg, mem) - if (FAST_IS_REG(dst) && (src & SLJIT_MEM)) { - sljit_gpr reg = gpr(dst); - - FAIL_IF(make_addr_bxy(compiler, &mem, src, srcw, tmp1)); - /* TODO(carenas): convert all calls below to LEVAL */ - switch (opcode | (op & SLJIT_32)) { - case SLJIT_MOV32_U8: - ins = llc(reg, mem.offset, mem.index, mem.base); - break; - case SLJIT_MOV32_S8: - ins = lb(reg, mem.offset, mem.index, mem.base); - break; - case SLJIT_MOV32_U16: - ins = llh(reg, mem.offset, mem.index, mem.base); - break; - case SLJIT_MOV32_S16: - ins = WHEN2(is_u12(mem.offset), lh, lhy); - break; - case SLJIT_MOV32: - ins = WHEN2(is_u12(mem.offset), l, ly); - break; - case SLJIT_MOV_U8: - ins = LEVAL(llgc); - break; - case SLJIT_MOV_S8: - ins = lgb(reg, mem.offset, mem.index, mem.base); - break; - case SLJIT_MOV_U16: - ins = LEVAL(llgh); - break; - case SLJIT_MOV_S16: - ins = lgh(reg, mem.offset, mem.index, mem.base); - break; - case SLJIT_MOV_U32: - ins = LEVAL(llgf); - break; - case SLJIT_MOV_S32: - ins = lgf(reg, mem.offset, mem.index, mem.base); - break; - case SLJIT_MOV_P: - case SLJIT_MOV: - ins = lg(reg, mem.offset, mem.index, mem.base); - break; - default: - ins = 0; - SLJIT_UNREACHABLE(); - break; - } - FAIL_IF(push_inst(compiler, ins)); - return SLJIT_SUCCESS; - } - /* STORE and STORE IMMEDIATE */ - if ((dst & SLJIT_MEM) - && (FAST_IS_REG(src) || (src & SLJIT_IMM))) { - sljit_gpr reg = FAST_IS_REG(src) ? gpr(src) : tmp0; - if (src & SLJIT_IMM) { - /* TODO(mundaym): MOVE IMMEDIATE? */ - FAIL_IF(push_load_imm_inst(compiler, reg, srcw)); - } - struct addr mem; - FAIL_IF(make_addr_bxy(compiler, &mem, dst, dstw, tmp1)); - switch (opcode) { - case SLJIT_MOV_U8: - case SLJIT_MOV_S8: - return push_inst(compiler, - WHEN2(is_u12(mem.offset), stc, stcy)); - case SLJIT_MOV_U16: - case SLJIT_MOV_S16: - return push_inst(compiler, - WHEN2(is_u12(mem.offset), sth, sthy)); - case SLJIT_MOV_U32: - case SLJIT_MOV_S32: - case SLJIT_MOV32: - return push_inst(compiler, - WHEN2(is_u12(mem.offset), st, sty)); - case SLJIT_MOV_P: - case SLJIT_MOV: - FAIL_IF(push_inst(compiler, LEVAL(stg))); - return SLJIT_SUCCESS; - default: - SLJIT_UNREACHABLE(); - } - } - #undef LEVAL - /* MOVE CHARACTERS */ - if ((dst & SLJIT_MEM) && (src & SLJIT_MEM)) { - struct addr mem; - FAIL_IF(make_addr_bxy(compiler, &mem, src, srcw, tmp1)); - switch (opcode) { - case SLJIT_MOV_U8: - case SLJIT_MOV_S8: - FAIL_IF(push_inst(compiler, - EVAL(llgc, tmp0, mem))); - FAIL_IF(make_addr_bxy(compiler, &mem, dst, dstw, tmp1)); - return push_inst(compiler, - EVAL(stcy, tmp0, mem)); - case SLJIT_MOV_U16: - case SLJIT_MOV_S16: - FAIL_IF(push_inst(compiler, - EVAL(llgh, tmp0, mem))); - FAIL_IF(make_addr_bxy(compiler, &mem, dst, dstw, tmp1)); - return push_inst(compiler, - EVAL(sthy, tmp0, mem)); - case SLJIT_MOV_U32: - case SLJIT_MOV_S32: - case SLJIT_MOV32: - FAIL_IF(push_inst(compiler, - EVAL(ly, tmp0, mem))); - FAIL_IF(make_addr_bxy(compiler, &mem, dst, dstw, tmp1)); - return push_inst(compiler, - EVAL(sty, tmp0, mem)); - case SLJIT_MOV_P: - case SLJIT_MOV: - FAIL_IF(push_inst(compiler, - EVAL(lg, tmp0, mem))); - FAIL_IF(make_addr_bxy(compiler, &mem, dst, dstw, tmp1)); - FAIL_IF(push_inst(compiler, - EVAL(stg, tmp0, mem))); - return SLJIT_SUCCESS; - default: - SLJIT_UNREACHABLE(); - } - } - SLJIT_UNREACHABLE(); - } - - SLJIT_ASSERT((src & SLJIT_IMM) == 0); /* no immediates */ - - dst_r = FAST_IS_REG(dst) ? gpr(REG_MASK & dst) : tmp0; - src_r = FAST_IS_REG(src) ? gpr(REG_MASK & src) : tmp0; - - compiler->status_flags_state = op & (VARIABLE_FLAG_MASK | SLJIT_SET_Z); - - /* TODO(mundaym): optimize loads and stores */ - switch (opcode) { - case SLJIT_NOT: - if (src & SLJIT_MEM) - FAIL_IF(load_word(compiler, src_r, src, srcw, op & SLJIT_32)); - - /* emulate ~x with x^-1 */ - if (!(op & SLJIT_32)) { - FAIL_IF(push_load_imm_inst(compiler, tmp1, -1)); - if (src_r != dst_r) - FAIL_IF(push_inst(compiler, lgr(dst_r, src_r))); - - FAIL_IF(push_inst(compiler, xgr(dst_r, tmp1))); - break; - } - - if (have_eimm()) - FAIL_IF(push_inst(compiler, xilf(dst_r, 0xffffffff))); - else { - FAIL_IF(push_load_imm_inst(compiler, tmp1, -1)); - if (src_r != dst_r) - FAIL_IF(push_inst(compiler, lr(dst_r, src_r))); - - FAIL_IF(push_inst(compiler, xr(dst_r, tmp1))); - } - break; - case SLJIT_CLZ: - case SLJIT_CTZ: - if (src & SLJIT_MEM) - FAIL_IF(load_unsigned_word(compiler, src_r, src, srcw, op & SLJIT_32)); - - FAIL_IF(sljit_emit_clz_ctz(compiler, op, dst_r, src_r)); - break; - default: - SLJIT_UNREACHABLE(); - } - - if ((op & (SLJIT_SET_Z | VARIABLE_FLAG_MASK)) == (SLJIT_SET_Z | SLJIT_SET_OVERFLOW)) - FAIL_IF(update_zero_overflow(compiler, op, dst_r)); - - if (dst & SLJIT_MEM) - return store_word(compiler, dst_r, dst, dstw, op & SLJIT_32); - - return SLJIT_SUCCESS; -} - -static SLJIT_INLINE int is_commutative(sljit_s32 op) -{ - switch (GET_OPCODE(op)) { - case SLJIT_ADD: - case SLJIT_ADDC: - case SLJIT_MUL: - case SLJIT_AND: - case SLJIT_OR: - case SLJIT_XOR: - return 1; - } - return 0; -} - -static const struct ins_forms add_forms = { - 0x1a00, /* ar */ - 0xb9080000, /* agr */ - 0xb9f80000, /* ark */ - 0xb9e80000, /* agrk */ - 0x5a000000, /* a */ - 0xe3000000005a, /* ay */ - 0xe30000000008, /* ag */ -}; - -static const struct ins_forms logical_add_forms = { - 0x1e00, /* alr */ - 0xb90a0000, /* algr */ - 0xb9fa0000, /* alrk */ - 0xb9ea0000, /* algrk */ - 0x5e000000, /* al */ - 0xe3000000005e, /* aly */ - 0xe3000000000a, /* alg */ -}; - -static sljit_s32 sljit_emit_add(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - int sets_overflow = (op & VARIABLE_FLAG_MASK) == SLJIT_SET_OVERFLOW; - int sets_zero_overflow = (op & (SLJIT_SET_Z | VARIABLE_FLAG_MASK)) == (SLJIT_SET_Z | SLJIT_SET_OVERFLOW); - const struct ins_forms *forms; - sljit_ins ins; - - if (src2 & SLJIT_IMM) { - if (!sets_zero_overflow && is_s8(src2w) && (src1 & SLJIT_MEM) && (dst == src1 && dstw == src1w)) { - if (sets_overflow) - ins = (op & SLJIT_32) ? 0xeb000000006a /* asi */ : 0xeb000000007a /* agsi */; - else - ins = (op & SLJIT_32) ? 0xeb000000006e /* alsi */ : 0xeb000000007e /* algsi */; - return emit_siy(compiler, ins, dst, dstw, src2w); - } - - if (is_s16(src2w)) { - if (sets_overflow) - ins = (op & SLJIT_32) ? 0xec00000000d8 /* ahik */ : 0xec00000000d9 /* aghik */; - else - ins = (op & SLJIT_32) ? 0xec00000000da /* alhsik */ : 0xec00000000db /* alghsik */; - FAIL_IF(emit_rie_d(compiler, ins, dst, src1, src1w, src2w)); - goto done; - } - - if (!sets_overflow) { - if ((op & SLJIT_32) || is_u32(src2w)) { - ins = (op & SLJIT_32) ? 0xc20b00000000 /* alfi */ : 0xc20a00000000 /* algfi */; - FAIL_IF(emit_ri(compiler, ins, dst, src1, src1w, src2w, RIL_A)); - goto done; - } - if (is_u32(-src2w)) { - FAIL_IF(emit_ri(compiler, 0xc20400000000 /* slgfi */, dst, src1, src1w, -src2w, RIL_A)); - goto done; - } - } - else if ((op & SLJIT_32) || is_s32(src2w)) { - ins = (op & SLJIT_32) ? 0xc20900000000 /* afi */ : 0xc20800000000 /* agfi */; - FAIL_IF(emit_ri(compiler, ins, dst, src1, src1w, src2w, RIL_A)); - goto done; - } - } - - forms = sets_overflow ? &add_forms : &logical_add_forms; - FAIL_IF(emit_commutative(compiler, forms, dst, src1, src1w, src2, src2w)); - -done: - if (sets_zero_overflow) - FAIL_IF(update_zero_overflow(compiler, op, FAST_IS_REG(dst) ? gpr(dst & REG_MASK) : tmp0)); - - if (dst & SLJIT_MEM) - return store_word(compiler, tmp0, dst, dstw, op & SLJIT_32); - - return SLJIT_SUCCESS; -} - -static const struct ins_forms sub_forms = { - 0x1b00, /* sr */ - 0xb9090000, /* sgr */ - 0xb9f90000, /* srk */ - 0xb9e90000, /* sgrk */ - 0x5b000000, /* s */ - 0xe3000000005b, /* sy */ - 0xe30000000009, /* sg */ -}; - -static const struct ins_forms logical_sub_forms = { - 0x1f00, /* slr */ - 0xb90b0000, /* slgr */ - 0xb9fb0000, /* slrk */ - 0xb9eb0000, /* slgrk */ - 0x5f000000, /* sl */ - 0xe3000000005f, /* sly */ - 0xe3000000000b, /* slg */ -}; - -static sljit_s32 sljit_emit_sub(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - sljit_s32 flag_type = GET_FLAG_TYPE(op); - int sets_signed = (flag_type >= SLJIT_SIG_LESS && flag_type <= SLJIT_NOT_OVERFLOW); - int sets_zero_overflow = (op & (SLJIT_SET_Z | VARIABLE_FLAG_MASK)) == (SLJIT_SET_Z | SLJIT_SET_OVERFLOW); - const struct ins_forms *forms; - sljit_ins ins; - - if (dst == (sljit_s32)tmp0 && flag_type <= SLJIT_SIG_LESS_EQUAL) { - int compare_signed = flag_type >= SLJIT_SIG_LESS; - - compiler->status_flags_state |= SLJIT_CURRENT_FLAGS_COMPARE; - - if (src2 & SLJIT_IMM) { - if (compare_signed || ((op & VARIABLE_FLAG_MASK) == 0 && is_s32(src2w))) - { - if ((op & SLJIT_32) || is_s32(src2w)) { - ins = (op & SLJIT_32) ? 0xc20d00000000 /* cfi */ : 0xc20c00000000 /* cgfi */; - return emit_ri(compiler, ins, src1, src1, src1w, src2w, RIL_A); - } - } - else { - if ((op & SLJIT_32) || is_u32(src2w)) { - ins = (op & SLJIT_32) ? 0xc20f00000000 /* clfi */ : 0xc20e00000000 /* clgfi */; - return emit_ri(compiler, ins, src1, src1, src1w, src2w, RIL_A); - } - if (is_s16(src2w)) - return emit_rie_d(compiler, 0xec00000000db /* alghsik */, (sljit_s32)tmp0, src1, src1w, src2w); - } - } - else if (src2 & SLJIT_MEM) { - if ((op & SLJIT_32) && ((src2 & OFFS_REG_MASK) || is_u12(src2w))) { - ins = compare_signed ? 0x59000000 /* c */ : 0x55000000 /* cl */; - return emit_rx(compiler, ins, src1, src1, src1w, src2, src2w, RX_A); - } - - if (compare_signed) - ins = (op & SLJIT_32) ? 0xe30000000059 /* cy */ : 0xe30000000020 /* cg */; - else - ins = (op & SLJIT_32) ? 0xe30000000055 /* cly */ : 0xe30000000021 /* clg */; - return emit_rx(compiler, ins, src1, src1, src1w, src2, src2w, RXY_A); - } - - if (compare_signed) - ins = (op & SLJIT_32) ? 0x1900 /* cr */ : 0xb9200000 /* cgr */; - else - ins = (op & SLJIT_32) ? 0x1500 /* clr */ : 0xb9210000 /* clgr */; - return emit_rr(compiler, ins, src1, src1, src1w, src2, src2w); - } - - if (src1 == SLJIT_IMM && src1w == 0 && (flag_type == 0 || sets_signed)) { - ins = (op & SLJIT_32) ? 0x1300 /* lcr */ : 0xb9030000 /* lcgr */; - FAIL_IF(emit_rr1(compiler, ins, dst, src2, src2w)); - goto done; - } - - if (src2 & SLJIT_IMM) { - sljit_sw neg_src2w = -src2w; - - if (sets_signed || neg_src2w != 0 || (op & (SLJIT_SET_Z | VARIABLE_FLAG_MASK)) == 0) { - if (!sets_zero_overflow && is_s8(neg_src2w) && (src1 & SLJIT_MEM) && (dst == src1 && dstw == src1w)) { - if (sets_signed) - ins = (op & SLJIT_32) ? 0xeb000000006a /* asi */ : 0xeb000000007a /* agsi */; - else - ins = (op & SLJIT_32) ? 0xeb000000006e /* alsi */ : 0xeb000000007e /* algsi */; - return emit_siy(compiler, ins, dst, dstw, neg_src2w); - } - - if (is_s16(neg_src2w)) { - if (sets_signed) - ins = (op & SLJIT_32) ? 0xec00000000d8 /* ahik */ : 0xec00000000d9 /* aghik */; - else - ins = (op & SLJIT_32) ? 0xec00000000da /* alhsik */ : 0xec00000000db /* alghsik */; - FAIL_IF(emit_rie_d(compiler, ins, dst, src1, src1w, neg_src2w)); - goto done; - } - } - - if (!sets_signed) { - if ((op & SLJIT_32) || is_u32(src2w)) { - ins = (op & SLJIT_32) ? 0xc20500000000 /* slfi */ : 0xc20400000000 /* slgfi */; - FAIL_IF(emit_ri(compiler, ins, dst, src1, src1w, src2w, RIL_A)); - goto done; - } - if (is_u32(neg_src2w)) { - FAIL_IF(emit_ri(compiler, 0xc20a00000000 /* algfi */, dst, src1, src1w, neg_src2w, RIL_A)); - goto done; - } - } - else if ((op & SLJIT_32) || is_s32(neg_src2w)) { - ins = (op & SLJIT_32) ? 0xc20900000000 /* afi */ : 0xc20800000000 /* agfi */; - FAIL_IF(emit_ri(compiler, ins, dst, src1, src1w, neg_src2w, RIL_A)); - goto done; - } - } - - forms = sets_signed ? &sub_forms : &logical_sub_forms; - FAIL_IF(emit_non_commutative(compiler, forms, dst, src1, src1w, src2, src2w)); - -done: - if (sets_signed) { - sljit_gpr dst_r = FAST_IS_REG(dst) ? gpr(dst & REG_MASK) : tmp0; - - if ((op & VARIABLE_FLAG_MASK) != SLJIT_SET_OVERFLOW) { - /* In case of overflow, the sign bit of the two source operands must be different, and - - the first operand is greater if the sign bit of the result is set - - 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, (op & SLJIT_32) ? lcr(tmp1, dst_r) : lcgr(tmp1, dst_r))); - } - else if (op & SLJIT_SET_Z) - FAIL_IF(update_zero_overflow(compiler, op, dst_r)); - } - - if (dst & SLJIT_MEM) - return store_word(compiler, tmp0, dst, dstw, op & SLJIT_32); - - return SLJIT_SUCCESS; -} - -static const struct ins_forms multiply_forms = { - 0xb2520000, /* msr */ - 0xb90c0000, /* msgr */ - 0xb9fd0000, /* msrkc */ - 0xb9ed0000, /* msgrkc */ - 0x71000000, /* ms */ - 0xe30000000051, /* msy */ - 0xe3000000000c, /* msg */ -}; - -static const struct ins_forms multiply_overflow_forms = { - 0, - 0, - 0xb9fd0000, /* msrkc */ - 0xb9ed0000, /* msgrkc */ - 0, - 0xe30000000053, /* msc */ - 0xe30000000083, /* msgc */ -}; - -static sljit_s32 sljit_emit_multiply(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - sljit_ins ins; - - if (HAS_FLAGS(op)) { - /* if have_misc2 fails, this operation should be emulated. 32 bit emulation: - FAIL_IF(push_inst(compiler, lgfr(tmp0, src1_r))); - FAIL_IF(push_inst(compiler, msgfr(tmp0, src2_r))); - if (dst_r != tmp0) { - FAIL_IF(push_inst(compiler, lr(dst_r, tmp0))); - } - FAIL_IF(push_inst(compiler, aih(tmp0, 1))); - FAIL_IF(push_inst(compiler, nihf(tmp0, ~1U))); - FAIL_IF(push_inst(compiler, ipm(tmp1))); - FAIL_IF(push_inst(compiler, oilh(tmp1, 0x2000))); */ - - return emit_commutative(compiler, &multiply_overflow_forms, dst, src1, src1w, src2, src2w); - } - - if (src2 & SLJIT_IMM) { - if (is_s16(src2w)) { - ins = (op & SLJIT_32) ? 0xa70c0000 /* mhi */ : 0xa70d0000 /* mghi */; - return emit_ri(compiler, ins, dst, src1, src1w, src2w, RI_A); - } - - if (is_s32(src2w)) { - ins = (op & SLJIT_32) ? 0xc20100000000 /* msfi */ : 0xc20000000000 /* msgfi */; - return emit_ri(compiler, ins, dst, src1, src1w, src2w, RIL_A); - } - } - - return emit_commutative(compiler, &multiply_forms, dst, src1, src1w, src2, src2w); -} - -static sljit_s32 sljit_emit_bitwise_imm(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 dst, - sljit_s32 src1, sljit_sw src1w, - sljit_uw imm, sljit_s32 count16) -{ - sljit_s32 mode = compiler->mode; - sljit_gpr dst_r = tmp0; - sljit_s32 needs_move = 1; - - if (IS_GPR_REG(dst)) { - dst_r = gpr(dst & REG_MASK); - if (dst == src1) - needs_move = 0; - } - - if (needs_move) - FAIL_IF(emit_move(compiler, dst_r, src1, src1w)); - - if (type == SLJIT_AND) { - if (!(mode & SLJIT_32)) - FAIL_IF(push_inst(compiler, 0xc00a00000000 /* nihf */ | R36A(dst_r) | (imm >> 32))); - return push_inst(compiler, 0xc00b00000000 /* nilf */ | R36A(dst_r) | (imm & 0xffffffff)); - } - else if (type == SLJIT_OR) { - if (count16 >= 3) { - FAIL_IF(push_inst(compiler, 0xc00c00000000 /* oihf */ | R36A(dst_r) | (imm >> 32))); - return push_inst(compiler, 0xc00d00000000 /* oilf */ | R36A(dst_r) | (imm & 0xffffffff)); - } - - if (count16 >= 2) { - if ((imm & 0x00000000ffffffffull) == 0) - return push_inst(compiler, 0xc00c00000000 /* oihf */ | R36A(dst_r) | (imm >> 32)); - if ((imm & 0xffffffff00000000ull) == 0) - return push_inst(compiler, 0xc00d00000000 /* oilf */ | R36A(dst_r) | (imm & 0xffffffff)); - } - - if ((imm & 0xffff000000000000ull) != 0) - FAIL_IF(push_inst(compiler, 0xa5080000 /* oihh */ | R20A(dst_r) | (imm >> 48))); - if ((imm & 0x0000ffff00000000ull) != 0) - FAIL_IF(push_inst(compiler, 0xa5090000 /* oihl */ | R20A(dst_r) | ((imm >> 32) & 0xffff))); - if ((imm & 0x00000000ffff0000ull) != 0) - FAIL_IF(push_inst(compiler, 0xa50a0000 /* oilh */ | R20A(dst_r) | ((imm >> 16) & 0xffff))); - if ((imm & 0x000000000000ffffull) != 0 || imm == 0) - return push_inst(compiler, 0xa50b0000 /* oill */ | R20A(dst_r) | (imm & 0xffff)); - return SLJIT_SUCCESS; - } - - if ((imm & 0xffffffff00000000ull) != 0) - FAIL_IF(push_inst(compiler, 0xc00600000000 /* xihf */ | R36A(dst_r) | (imm >> 32))); - if ((imm & 0x00000000ffffffffull) != 0 || imm == 0) - return push_inst(compiler, 0xc00700000000 /* xilf */ | R36A(dst_r) | (imm & 0xffffffff)); - return SLJIT_SUCCESS; -} - -static const struct ins_forms bitwise_and_forms = { - 0x1400, /* nr */ - 0xb9800000, /* ngr */ - 0xb9f40000, /* nrk */ - 0xb9e40000, /* ngrk */ - 0x54000000, /* n */ - 0xe30000000054, /* ny */ - 0xe30000000080, /* ng */ -}; - -static const struct ins_forms bitwise_or_forms = { - 0x1600, /* or */ - 0xb9810000, /* ogr */ - 0xb9f60000, /* ork */ - 0xb9e60000, /* ogrk */ - 0x56000000, /* o */ - 0xe30000000056, /* oy */ - 0xe30000000081, /* og */ -}; - -static const struct ins_forms bitwise_xor_forms = { - 0x1700, /* xr */ - 0xb9820000, /* xgr */ - 0xb9f70000, /* xrk */ - 0xb9e70000, /* xgrk */ - 0x57000000, /* x */ - 0xe30000000057, /* xy */ - 0xe30000000082, /* xg */ -}; - -static sljit_s32 sljit_emit_bitwise(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - 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))) { - sljit_s32 count16 = 0; - sljit_uw imm = (sljit_uw)src2w; - - if (op & SLJIT_32) - imm &= 0xffffffffull; - - if ((imm & 0x000000000000ffffull) != 0 || imm == 0) - count16++; - if ((imm & 0x00000000ffff0000ull) != 0) - count16++; - if ((imm & 0x0000ffff00000000ull) != 0) - count16++; - if ((imm & 0xffff000000000000ull) != 0) - count16++; - - if (type == SLJIT_AND && dst == (sljit_s32)tmp0 && count16 == 1) { - sljit_gpr src_r = tmp0; - - if (FAST_IS_REG(src1)) - src_r = gpr(src1 & REG_MASK); - else - FAIL_IF(emit_move(compiler, tmp0, src1, src1w)); - - if ((imm & 0x000000000000ffffull) != 0 || imm == 0) - return push_inst(compiler, 0xa7010000 | R20A(src_r) | imm); - if ((imm & 0x00000000ffff0000ull) != 0) - return push_inst(compiler, 0xa7000000 | R20A(src_r) | (imm >> 16)); - if ((imm & 0x0000ffff00000000ull) != 0) - return push_inst(compiler, 0xa7030000 | R20A(src_r) | (imm >> 32)); - return push_inst(compiler, 0xa7020000 | R20A(src_r) | (imm >> 48)); - } - - if (!(op & SLJIT_SET_Z)) - return sljit_emit_bitwise_imm(compiler, type, dst, src1, src1w, imm, count16); - } - - if (type == SLJIT_AND) - forms = &bitwise_and_forms; - else if (type == SLJIT_OR) - forms = &bitwise_or_forms; - else - forms = &bitwise_xor_forms; - - return emit_commutative(compiler, forms, dst, src1, src1w, src2, src2w); -} - -static sljit_s32 sljit_emit_shift(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - sljit_s32 type = GET_OPCODE(op); - sljit_gpr dst_r = FAST_IS_REG(dst) ? gpr(dst & REG_MASK) : tmp0; - sljit_gpr src_r = tmp0; - sljit_gpr base_r = tmp0; - sljit_ins imm = 0; - sljit_ins ins; - - if (FAST_IS_REG(src1)) - src_r = gpr(src1); - else - FAIL_IF(emit_move(compiler, tmp0, src1, src1w)); - - if (!(src2 & SLJIT_IMM)) { - if (FAST_IS_REG(src2)) - base_r = gpr(src2); - else { - FAIL_IF(emit_move(compiler, tmp1, src2, src2w)); - base_r = tmp1; - } - - if ((op & SLJIT_32) && (type == SLJIT_MSHL || type == SLJIT_MLSHR || type == SLJIT_MASHR)) { - if (base_r != tmp1) { - FAIL_IF(push_inst(compiler, 0xec0000000055 /* risbg */ | R36A(tmp1) | R32A(base_r) | (59 << 24) | (1 << 23) | (63 << 16))); - base_r = tmp1; - } else - FAIL_IF(push_inst(compiler, 0xa5070000 /* nill */ | R20A(tmp1) | 0x1f)); - } - } else - imm = (sljit_ins)(src2w & ((op & SLJIT_32) ? 0x1f : 0x3f)); - - if ((op & SLJIT_32) && dst_r == src_r) { - if (type == SLJIT_SHL || type == SLJIT_MSHL) - ins = 0x89000000 /* sll */; - else if (type == SLJIT_LSHR || type == SLJIT_MLSHR) - ins = 0x88000000 /* srl */; - else - ins = 0x8a000000 /* sra */; - - FAIL_IF(push_inst(compiler, ins | R20A(dst_r) | R12A(base_r) | imm)); - } else { - if (type == SLJIT_SHL || type == SLJIT_MSHL) - ins = (op & SLJIT_32) ? 0xeb00000000df /* sllk */ : 0xeb000000000d /* sllg */; - else if (type == SLJIT_LSHR || type == SLJIT_MLSHR) - ins = (op & SLJIT_32) ? 0xeb00000000de /* srlk */ : 0xeb000000000c /* srlg */; - else - ins = (op & SLJIT_32) ? 0xeb00000000dc /* srak */ : 0xeb000000000a /* srag */; - - FAIL_IF(push_inst(compiler, ins | R36A(dst_r) | R32A(src_r) | R28A(base_r) | (imm << 16))); - } - - if ((op & SLJIT_SET_Z) && type != SLJIT_ASHR) - return push_inst(compiler, (op & SLJIT_32) ? or(dst_r, dst_r) : ogr(dst_r, dst_r)); - - return SLJIT_SUCCESS; -} - -static sljit_s32 sljit_emit_rotate(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - sljit_gpr dst_r = FAST_IS_REG(dst) ? gpr(dst & REG_MASK) : tmp0; - sljit_gpr src_r = tmp0; - sljit_gpr base_r = tmp0; - sljit_ins imm = 0; - sljit_ins ins; - - if (FAST_IS_REG(src1)) - src_r = gpr(src1); - else - FAIL_IF(emit_move(compiler, tmp0, src1, src1w)); - - if (!(src2 & SLJIT_IMM)) { - if (FAST_IS_REG(src2)) - base_r = gpr(src2); - else { - FAIL_IF(emit_move(compiler, tmp1, src2, src2w)); - base_r = tmp1; - } - } - - if (GET_OPCODE(op) == SLJIT_ROTR) { - if (!(src2 & SLJIT_IMM)) { - ins = (op & SLJIT_32) ? 0x1300 /* lcr */ : 0xb9030000 /* lcgr */; - FAIL_IF(push_inst(compiler, ins | R4A(tmp1) | R0A(base_r))); - base_r = tmp1; - } else - src2w = -src2w; - } - - if (src2 & SLJIT_IMM) - imm = (sljit_ins)(src2w & ((op & SLJIT_32) ? 0x1f : 0x3f)); - - ins = (op & SLJIT_32) ? 0xeb000000001d /* rll */ : 0xeb000000001c /* rllg */; - return push_inst(compiler, ins | R36A(dst_r) | R32A(src_r) | R28A(base_r) | (imm << 16)); -} - -static const struct ins_forms addc_forms = { - 0xb9980000, /* alcr */ - 0xb9880000, /* alcgr */ - 0, - 0, - 0, - 0xe30000000098, /* alc */ - 0xe30000000088, /* alcg */ -}; - -static const struct ins_forms subc_forms = { - 0xb9990000, /* slbr */ - 0xb9890000, /* slbgr */ - 0, - 0, - 0, - 0xe30000000099, /* slb */ - 0xe30000000089, /* slbg */ -}; - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - CHECK_ERROR(); - CHECK(check_sljit_emit_op2(compiler, op, 0, dst, dstw, src1, src1w, src2, src2w)); - ADJUST_LOCAL_OFFSET(dst, dstw); - ADJUST_LOCAL_OFFSET(src1, src1w); - ADJUST_LOCAL_OFFSET(src2, src2w); - - compiler->mode = op & SLJIT_32; - compiler->status_flags_state = op & (VARIABLE_FLAG_MASK | SLJIT_SET_Z); - - if (is_commutative(op) && (src1 & SLJIT_IMM) && !(src2 & SLJIT_IMM)) { - src1 ^= src2; - src2 ^= src1; - src1 ^= src2; - - src1w ^= src2w; - src2w ^= src1w; - src1w ^= src2w; - } - - switch (GET_OPCODE(op)) { - case SLJIT_ADD: - compiler->status_flags_state |= SLJIT_CURRENT_FLAGS_ADD; - return sljit_emit_add(compiler, op, dst, dstw, src1, src1w, src2, src2w); - case SLJIT_ADDC: - compiler->status_flags_state |= SLJIT_CURRENT_FLAGS_ADD; - FAIL_IF(emit_commutative(compiler, &addc_forms, dst, src1, src1w, src2, src2w)); - if (dst & SLJIT_MEM) - return store_word(compiler, tmp0, dst, dstw, op & SLJIT_32); - return SLJIT_SUCCESS; - case SLJIT_SUB: - compiler->status_flags_state |= SLJIT_CURRENT_FLAGS_SUB; - return sljit_emit_sub(compiler, op, dst, dstw, src1, src1w, src2, src2w); - case SLJIT_SUBC: - compiler->status_flags_state |= SLJIT_CURRENT_FLAGS_SUB; - FAIL_IF(emit_non_commutative(compiler, &subc_forms, dst, src1, src1w, src2, src2w)); - if (dst & SLJIT_MEM) - return store_word(compiler, tmp0, dst, dstw, op & SLJIT_32); - return SLJIT_SUCCESS; - case SLJIT_MUL: - FAIL_IF(sljit_emit_multiply(compiler, op, dst, src1, src1w, src2, src2w)); - break; - case SLJIT_AND: - case SLJIT_OR: - case SLJIT_XOR: - FAIL_IF(sljit_emit_bitwise(compiler, op, dst, src1, src1w, src2, src2w)); - break; - case SLJIT_SHL: - case SLJIT_MSHL: - case SLJIT_LSHR: - case SLJIT_MLSHR: - case SLJIT_ASHR: - case SLJIT_MASHR: - FAIL_IF(sljit_emit_shift(compiler, op, dst, src1, src1w, src2, src2w)); - break; - case SLJIT_ROTL: - case SLJIT_ROTR: - FAIL_IF(sljit_emit_rotate(compiler, op, dst, src1, src1w, src2, src2w)); - break; - } - - if (dst & SLJIT_MEM) - return store_word(compiler, tmp0, dst, dstw, op & SLJIT_32); - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - 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); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 src_dst, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - sljit_s32 is_right; - sljit_sw bit_length = (op & SLJIT_32) ? 32 : 64; - sljit_gpr src_dst_r = gpr(src_dst); - sljit_gpr src1_r = tmp0; - sljit_gpr src2_r = tmp1; - sljit_ins ins; - - CHECK_ERROR(); - CHECK(check_sljit_emit_shift_into(compiler, op, src_dst, src1, src1w, src2, src2w)); - - is_right = (GET_OPCODE(op) == SLJIT_LSHR || GET_OPCODE(op) == SLJIT_MLSHR); - - if (src_dst == src1) { - SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_op2(compiler, (is_right ? SLJIT_ROTR : SLJIT_ROTL) | (op & SLJIT_32), src_dst, 0, src_dst, 0, src2, src2w); - } - - ADJUST_LOCAL_OFFSET(src1, src1w); - ADJUST_LOCAL_OFFSET(src2, src2w); - - if (src1 & SLJIT_MEM) - FAIL_IF(load_word(compiler, tmp0, src1, src1w, op & SLJIT_32)); - else if (src1 & SLJIT_IMM) - FAIL_IF(push_load_imm_inst(compiler, tmp0, src1w)); - else - src1_r = gpr(src1); - - if (src2 & SLJIT_IMM) { - src2w &= bit_length - 1; - - if (src2w == 0) - return SLJIT_SUCCESS; - } else if (!(src2 & SLJIT_MEM)) - src2_r = gpr(src2); - else - FAIL_IF(load_word(compiler, tmp1, src2, src2w, op & SLJIT_32)); - - if (src2 & SLJIT_IMM) { - if (op & SLJIT_32) { - ins = is_right ? 0x88000000 /* srl */ : 0x89000000 /* sll */; - FAIL_IF(push_inst(compiler, ins | R20A(src_dst_r) | (sljit_ins)src2w)); - } else { - ins = is_right ? 0xeb000000000c /* srlg */ : 0xeb000000000d /* sllg */; - FAIL_IF(push_inst(compiler, ins | R36A(src_dst_r) | R32A(src_dst_r) | ((sljit_ins)src2w << 16))); - } - - ins = 0xec0000000055 /* risbg */; - - if (is_right) { - src2w = bit_length - src2w; - ins |= ((sljit_ins)(64 - bit_length) << 24) | ((sljit_ins)(63 - src2w) << 16) | ((sljit_ins)src2w << 8); - } else - ins |= ((sljit_ins)(64 - src2w) << 24) | ((sljit_ins)63 << 16) | ((sljit_ins)src2w << 8); - - return push_inst(compiler, ins | R36A(src_dst_r) | R32A(src1_r)); - } - - if (op & SLJIT_32) { - if (GET_OPCODE(op) == SLJIT_MSHL || GET_OPCODE(op) == SLJIT_MLSHR) { - if (src2_r != tmp1) { - FAIL_IF(push_inst(compiler, 0xec0000000055 /* risbg */ | R36A(tmp1) | R32A(src2_r) | (59 << 24) | (1 << 23) | (63 << 16))); - src2_r = tmp1; - } else - FAIL_IF(push_inst(compiler, 0xa5070000 /* nill */ | R20A(tmp1) | 0x1f)); - } - - ins = is_right ? 0x88000000 /* srl */ : 0x89000000 /* sll */; - FAIL_IF(push_inst(compiler, ins | R20A(src_dst_r) | R12A(src2_r))); - - if (src2_r != tmp1) { - FAIL_IF(push_inst(compiler, 0xa50f0000 /* llill */ | R20A(tmp1) | 0x1f)); - FAIL_IF(push_inst(compiler, 0x1700 /* xr */ | R4A(tmp1) | R0A(src2_r))); - } else - FAIL_IF(push_inst(compiler, 0xc00700000000 /* xilf */ | R36A(tmp1) | 0x1f)); - - if (src1_r == tmp0) { - ins = is_right ? 0x89000000 /* sll */ : 0x88000000 /* srl */; - FAIL_IF(push_inst(compiler, ins | R20A(tmp0) | R12A(tmp1) | 0x1)); - } else { - ins = is_right ? 0xeb00000000df /* sllk */ : 0xeb00000000de /* srlk */; - FAIL_IF(push_inst(compiler, ins | R36A(tmp0) | R32A(src1_r) | R28A(tmp1) | (0x1 << 16))); - } - - return push_inst(compiler, 0x1600 /* or */ | R4A(src_dst_r) | R0A(tmp0)); - } - - ins = is_right ? 0xeb000000000c /* srlg */ : 0xeb000000000d /* sllg */; - FAIL_IF(push_inst(compiler, ins | R36A(src_dst_r) | R32A(src_dst_r) | R28A(src2_r))); - - ins = is_right ? 0xeb000000000d /* sllg */ : 0xeb000000000c /* srlg */; - - if (!(op & SLJIT_SHIFT_INTO_NON_ZERO)) { - if (src2_r != tmp1) - FAIL_IF(push_inst(compiler, 0xa50f0000 /* llill */ | R20A(tmp1) | 0x3f)); - - FAIL_IF(push_inst(compiler, ins | R36A(tmp0) | R32A(src1_r) | (0x1 << 16))); - src1_r = tmp0; - - if (src2_r != tmp1) - FAIL_IF(push_inst(compiler, 0xb9820000 /* xgr */ | R4A(tmp1) | R0A(src2_r))); - else - FAIL_IF(push_inst(compiler, 0xc00700000000 /* xilf */ | R36A(tmp1) | 0x3f)); - } else - FAIL_IF(push_inst(compiler, 0xb9030000 /* lcgr */ | R4A(tmp1) | R0A(src2_r))); - - FAIL_IF(push_inst(compiler, ins | R36A(tmp0) | R32A(src1_r) | R28A(tmp1))); - return push_inst(compiler, 0xb9810000 /* ogr */ | R4A(src_dst_r) | R0A(tmp0)); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src( - struct sljit_compiler *compiler, - sljit_s32 op, sljit_s32 src, sljit_sw srcw) -{ - sljit_gpr src_r; - struct addr addr; - - CHECK_ERROR(); - CHECK(check_sljit_emit_op_src(compiler, op, src, srcw)); - ADJUST_LOCAL_OFFSET(src, srcw); - - switch (op) { - case SLJIT_FAST_RETURN: - src_r = FAST_IS_REG(src) ? gpr(src) : tmp1; - if (src & SLJIT_MEM) - FAIL_IF(load_word(compiler, tmp1, src, srcw, 0)); - - return push_inst(compiler, br(src_r)); - case SLJIT_SKIP_FRAMES_BEFORE_FAST_RETURN: - return SLJIT_SUCCESS; - case SLJIT_PREFETCH_L1: - case SLJIT_PREFETCH_L2: - case SLJIT_PREFETCH_L3: - case SLJIT_PREFETCH_ONCE: - FAIL_IF(make_addr_bxy(compiler, &addr, src, srcw, tmp1)); - return push_inst(compiler, 0xe31000000036 /* pfd */ | R32A(addr.index) | R28A(addr.base) | disp_s20(addr.offset)); - default: - return SLJIT_SUCCESS; - } - - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 reg) -{ - CHECK_REG_INDEX(check_sljit_get_register_index(reg)); - return (sljit_s32)gpr(reg); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_float_register_index(sljit_s32 reg) -{ - CHECK_REG_INDEX(check_sljit_get_float_register_index(reg)); - return (sljit_s32)fgpr(reg); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler, - void *instruction, sljit_u32 size) -{ - sljit_ins ins = 0; - - CHECK_ERROR(); - CHECK(check_sljit_emit_op_custom(compiler, instruction, size)); - - memcpy((sljit_u8 *)&ins + sizeof(ins) - size, instruction, size); - return push_inst(compiler, ins); -} - -/* --------------------------------------------------------------------- */ -/* Floating point operators */ -/* --------------------------------------------------------------------- */ - -#define FLOAT_LOAD 0 -#define FLOAT_STORE 1 - -static sljit_s32 float_mem(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 reg, - sljit_s32 mem, sljit_sw memw) -{ - struct addr addr; - sljit_ins ins; - - SLJIT_ASSERT(mem & SLJIT_MEM); - - if ((mem & OFFS_REG_MASK) || is_u12(memw) || !is_s20(memw)) { - FAIL_IF(make_addr_bx(compiler, &addr, mem, memw, tmp1)); - - if (op & FLOAT_STORE) - ins = (op & SLJIT_32) ? 0x70000000 /* ste */ : 0x60000000 /* std */; - else - ins = (op & SLJIT_32) ? 0x78000000 /* le */ : 0x68000000 /* ld */; - - return push_inst(compiler, ins | F20(reg) | R16A(addr.index) | R12A(addr.base) | (sljit_ins)addr.offset); - } - - FAIL_IF(make_addr_bxy(compiler, &addr, mem, memw, tmp1)); - - if (op & FLOAT_STORE) - ins = (op & SLJIT_32) ? 0xed0000000066 /* stey */ : 0xed0000000067 /* stdy */; - else - ins = (op & SLJIT_32) ? 0xed0000000064 /* ley */ : 0xed0000000065 /* ldy */; - - return push_inst(compiler, ins | F36(reg) | R32A(addr.index) | R28A(addr.base) | disp_s20(addr.offset)); -} - -static sljit_s32 emit_float(struct sljit_compiler *compiler, sljit_ins ins_r, sljit_ins ins, - sljit_s32 reg, - sljit_s32 src, sljit_sw srcw) -{ - struct addr addr; - - if (!(src & SLJIT_MEM)) - return push_inst(compiler, ins_r | F4(reg) | F0(src)); - - FAIL_IF(make_addr_bx(compiler, &addr, src, srcw, tmp1)); - return push_inst(compiler, ins | F36(reg) | R32A(addr.index) | R28A(addr.base) | ((sljit_ins)addr.offset << 16)); -} - -static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src, sljit_sw srcw) -{ - sljit_ins dst_r = FAST_IS_REG(dst) ? gpr(dst) : tmp0; - sljit_ins ins; - - if (src & SLJIT_MEM) { - FAIL_IF(float_mem(compiler, FLOAT_LOAD | (op & SLJIT_32), TMP_FREG1, src, srcw)); - src = TMP_FREG1; - } - - /* M3 is set to 5 */ - if (GET_OPCODE(op) == SLJIT_CONV_SW_FROM_F64) - ins = (op & SLJIT_32) ? 0xb3a85000 /* cgebr */ : 0xb3a95000 /* cgdbr */; - else - ins = (op & SLJIT_32) ? 0xb3985000 /* cfebr */ : 0xb3995000 /* cfdbr */; - - FAIL_IF(push_inst(compiler, ins | R4A(dst_r) | F0(src))); - - if (dst & SLJIT_MEM) - return store_word(compiler, dst_r, dst, dstw, GET_OPCODE(op) >= SLJIT_CONV_S32_FROM_F64); - - return SLJIT_SUCCESS; -} - -static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src, sljit_sw srcw) -{ - sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1; - sljit_ins ins; - - if (src & SLJIT_IMM) { - FAIL_IF(push_load_imm_inst(compiler, tmp0, srcw)); - src = (sljit_s32)tmp0; - } - else if (src & SLJIT_MEM) { - FAIL_IF(load_word(compiler, tmp0, src, srcw, GET_OPCODE(op) >= SLJIT_CONV_F64_FROM_S32)); - src = (sljit_s32)tmp0; - } - - if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_SW) - ins = (op & SLJIT_32) ? 0xb3a40000 /* cegbr */ : 0xb3a50000 /* cdgbr */; - else - ins = (op & SLJIT_32) ? 0xb3940000 /* cefbr */ : 0xb3950000 /* cdfbr */; - - FAIL_IF(push_inst(compiler, ins | F4(dst_r) | R0(src))); - - if (dst & SLJIT_MEM) - return float_mem(compiler, FLOAT_STORE | (op & SLJIT_32), TMP_FREG1, dst, dstw); - - return SLJIT_SUCCESS; -} - -static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - sljit_ins ins_r, ins; - - if (src1 & SLJIT_MEM) { - FAIL_IF(float_mem(compiler, FLOAT_LOAD | (op & SLJIT_32), TMP_FREG1, src1, src1w)); - src1 = TMP_FREG1; - } - - if (op & SLJIT_32) { - ins_r = 0xb3090000 /* cebr */; - ins = 0xed0000000009 /* ceb */; - } else { - ins_r = 0xb3190000 /* cdbr */; - ins = 0xed0000000019 /* cdb */; - } - - return emit_float(compiler, ins_r, ins, src1, src2, src2w); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src, sljit_sw srcw) -{ - sljit_s32 dst_r; - sljit_ins ins; - - CHECK_ERROR(); - - SELECT_FOP1_OPERATION_WITH_CHECKS(compiler, op, dst, dstw, src, srcw); - - dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1; - - if (op == SLJIT_CONV_F64_FROM_F32) - FAIL_IF(emit_float(compiler, 0xb3040000 /* ldebr */, 0xed0000000004 /* ldeb */, dst_r, src, srcw)); - else { - if (src & SLJIT_MEM) { - FAIL_IF(float_mem(compiler, FLOAT_LOAD | (op == SLJIT_CONV_F32_FROM_F64 ? 0 : (op & SLJIT_32)), dst_r, src, srcw)); - src = dst_r; - } - - switch (GET_OPCODE(op)) { - case SLJIT_MOV_F64: - if (FAST_IS_REG(dst)) { - if (dst == src) - return SLJIT_SUCCESS; - - ins = (op & SLJIT_32) ? 0x3800 /* ler */ : 0x2800 /* ldr */; - break; - } - return float_mem(compiler, FLOAT_STORE | (op & SLJIT_32), src, dst, dstw); - case SLJIT_CONV_F64_FROM_F32: - /* Only SLJIT_CONV_F32_FROM_F64. */ - ins = 0xb3440000 /* ledbr */; - break; - case SLJIT_NEG_F64: - ins = (op & SLJIT_32) ? 0xb3030000 /* lcebr */ : 0xb3130000 /* lcdbr */; - break; - default: - SLJIT_ASSERT(GET_OPCODE(op) == SLJIT_ABS_F64); - ins = (op & SLJIT_32) ? 0xb3000000 /* lpebr */ : 0xb3100000 /* lpdbr */; - break; - } - - FAIL_IF(push_inst(compiler, ins | F4(dst_r) | F0(src))); - } - - if (!(dst & SLJIT_MEM)) - return SLJIT_SUCCESS; - - SLJIT_ASSERT(dst_r == TMP_FREG1); - - return float_mem(compiler, FLOAT_STORE | (op & SLJIT_32), TMP_FREG1, dst, dstw); -} - -#define FLOAT_MOV(op, dst_r, src_r) \ - (((op & SLJIT_32) ? 0x3800 /* ler */ : 0x2800 /* ldr */) | F4(dst_r) | F0(src_r)) - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - sljit_s32 dst_r = TMP_FREG1; - sljit_ins ins_r, ins; - - CHECK_ERROR(); - CHECK(check_sljit_emit_fop2(compiler, op, dst, dstw, src1, src1w, src2, src2w)); - ADJUST_LOCAL_OFFSET(dst, dstw); - ADJUST_LOCAL_OFFSET(src1, src1w); - ADJUST_LOCAL_OFFSET(src2, src2w); - - do { - if (FAST_IS_REG(dst)) { - dst_r = dst; - - if (dst == src1) - break; - - if (dst == src2) { - if (GET_OPCODE(op) == SLJIT_ADD_F64 || GET_OPCODE(op) == SLJIT_MUL_F64) { - src2 = src1; - src2w = src1w; - src1 = dst; - break; - } - - FAIL_IF(push_inst(compiler, FLOAT_MOV(op, TMP_FREG1, src2))); - src2 = TMP_FREG1; - } - } - - if (src1 & SLJIT_MEM) - FAIL_IF(float_mem(compiler, FLOAT_LOAD | (op & SLJIT_32), dst_r, src1, src1w)); - else - FAIL_IF(push_inst(compiler, FLOAT_MOV(op, dst_r, src1))); - } while (0); - - switch (GET_OPCODE(op)) { - case SLJIT_ADD_F64: - ins_r = (op & SLJIT_32) ? 0xb30a0000 /* aebr */ : 0xb31a0000 /* adbr */; - ins = (op & SLJIT_32) ? 0xed000000000a /* aeb */ : 0xed000000001a /* adb */; - break; - case SLJIT_SUB_F64: - ins_r = (op & SLJIT_32) ? 0xb30b0000 /* sebr */ : 0xb31b0000 /* sdbr */; - ins = (op & SLJIT_32) ? 0xed000000000b /* seb */ : 0xed000000001b /* sdb */; - break; - case SLJIT_MUL_F64: - ins_r = (op & SLJIT_32) ? 0xb3170000 /* meebr */ : 0xb31c0000 /* mdbr */; - ins = (op & SLJIT_32) ? 0xed0000000017 /* meeb */ : 0xed000000001c /* mdb */; - break; - default: - SLJIT_ASSERT(GET_OPCODE(op) == SLJIT_DIV_F64); - ins_r = (op & SLJIT_32) ? 0xb30d0000 /* debr */ : 0xb31d0000 /* ddbr */; - ins = (op & SLJIT_32) ? 0xed000000000d /* deb */ : 0xed000000001d /* ddb */; - break; - } - - FAIL_IF(emit_float(compiler, ins_r, ins, dst_r, src2, src2w)); - - 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; -} - -/* --------------------------------------------------------------------- */ -/* Other instructions */ -/* --------------------------------------------------------------------- */ - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw) -{ - CHECK_ERROR(); - CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw)); - ADJUST_LOCAL_OFFSET(dst, dstw); - - if (FAST_IS_REG(dst)) - return push_inst(compiler, lgr(gpr(dst), link_r)); - - /* memory */ - return store_word(compiler, link_r, dst, dstw, 0); -} - -/* --------------------------------------------------------------------- */ -/* Conditional instructions */ -/* --------------------------------------------------------------------- */ - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compiler *compiler) -{ - struct sljit_label *label; - - CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_label(compiler)); - - if (compiler->last_label && compiler->last_label->size == compiler->size) - return compiler->last_label; - - label = (struct sljit_label*)ensure_abuf(compiler, sizeof(struct sljit_label)); - PTR_FAIL_IF(!label); - set_label(label, compiler); - return label; -} - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type) -{ - sljit_u8 mask = ((type & 0xff) < SLJIT_JUMP) ? get_cc(compiler, type & 0xff) : 0xf; - - CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_jump(compiler, type)); - - /* record jump */ - struct sljit_jump *jump = (struct sljit_jump *) - ensure_abuf(compiler, sizeof(struct sljit_jump)); - PTR_FAIL_IF(!jump); - set_jump(jump, compiler, type & SLJIT_REWRITABLE_JUMP); - jump->addr = compiler->size; - - /* emit jump instruction */ - type &= 0xff; - if (type >= SLJIT_FAST_CALL) - PTR_FAIL_IF(push_inst(compiler, brasl(link_r, 0))); - else - PTR_FAIL_IF(push_inst(compiler, brcl(mask, 0))); - - return jump; -} - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_call(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 arg_types) -{ - SLJIT_UNUSED_ARG(arg_types); - CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_call(compiler, type, arg_types)); - - if (type & SLJIT_CALL_RETURN) { - PTR_FAIL_IF(emit_stack_frame_release(compiler, r14)); - type = SLJIT_JUMP | (type & SLJIT_REWRITABLE_JUMP); - } - - SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_jump(compiler, type); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 src, sljit_sw srcw) -{ - sljit_gpr src_r = FAST_IS_REG(src) ? gpr(src) : tmp1; - - CHECK_ERROR(); - CHECK(check_sljit_emit_ijump(compiler, type, src, srcw)); - - if (src & SLJIT_IMM) { - SLJIT_ASSERT(!(srcw & 1)); /* target address must be even */ - FAIL_IF(push_load_imm_inst(compiler, src_r, srcw)); - } - else if (src & SLJIT_MEM) { - ADJUST_LOCAL_OFFSET(src, srcw); - FAIL_IF(load_word(compiler, src_r, src, srcw, 0 /* 64-bit */)); - } - - /* emit jump instruction */ - if (type >= SLJIT_FAST_CALL) - return push_inst(compiler, basr(link_r, src_r)); - - return push_inst(compiler, br(src_r)); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 arg_types, - sljit_s32 src, sljit_sw srcw) -{ - CHECK_ERROR(); - CHECK(check_sljit_emit_icall(compiler, type, arg_types, src, srcw)); - - SLJIT_ASSERT(gpr(TMP_REG2) == tmp1); - - if (src & SLJIT_MEM) { - ADJUST_LOCAL_OFFSET(src, srcw); - FAIL_IF(load_word(compiler, tmp1, src, srcw, 0 /* 64-bit */)); - src = TMP_REG2; - srcw = 0; - } - - if (type & SLJIT_CALL_RETURN) { - if (src >= SLJIT_FIRST_SAVED_REG && src <= (SLJIT_S0 - SLJIT_KEPT_SAVEDS_COUNT(compiler->options))) { - FAIL_IF(push_inst(compiler, lgr(tmp1, gpr(src)))); - src = TMP_REG2; - srcw = 0; - } - - FAIL_IF(emit_stack_frame_release(compiler, r14)); - type = SLJIT_JUMP; - } - - SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_ijump(compiler, type, src, srcw); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 type) -{ - sljit_u8 mask = get_cc(compiler, type); - - CHECK_ERROR(); - CHECK(check_sljit_emit_op_flags(compiler, op, dst, dstw, type)); - - sljit_gpr dst_r = FAST_IS_REG(dst) ? gpr(dst & REG_MASK) : tmp0; - sljit_gpr loc_r = tmp1; - switch (GET_OPCODE(op)) { - case SLJIT_AND: - case SLJIT_OR: - case SLJIT_XOR: - compiler->status_flags_state = op & SLJIT_SET_Z; - - /* dst is also source operand */ - if (dst & SLJIT_MEM) - FAIL_IF(load_word(compiler, dst_r, dst, dstw, op & SLJIT_32)); - - break; - case SLJIT_MOV32: - op |= SLJIT_32; - /* fallthrough */ - case SLJIT_MOV: - /* can write straight into destination */ - loc_r = dst_r; - break; - default: - SLJIT_UNREACHABLE(); - } - - /* TODO(mundaym): fold into cmov helper function? */ - #define LEVAL(i) i(loc_r, 1, mask) - if (have_lscond2()) { - FAIL_IF(push_load_imm_inst(compiler, loc_r, 0)); - 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(); - } - #undef LEVAL - - /* apply bitwise op and set condition codes */ - switch (GET_OPCODE(op)) { - #define LEVAL(i) i(dst_r, loc_r) - case SLJIT_AND: - FAIL_IF(push_inst(compiler, - WHEN2(op & SLJIT_32, nr, ngr))); - break; - case SLJIT_OR: - FAIL_IF(push_inst(compiler, - WHEN2(op & SLJIT_32, or, ogr))); - break; - case SLJIT_XOR: - FAIL_IF(push_inst(compiler, - WHEN2(op & SLJIT_32, xr, xgr))); - break; - #undef LEVAL - } - - /* store result to memory if required */ - if (dst & SLJIT_MEM) - return store_word(compiler, dst_r, dst, dstw, (op & SLJIT_32)); - - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 dst_reg, - sljit_s32 src, sljit_sw srcw) -{ - sljit_ins mask = get_cc(compiler, type & ~SLJIT_32); - sljit_gpr src_r; - sljit_ins ins; - - CHECK_ERROR(); - CHECK(check_sljit_emit_cmov(compiler, type, dst_reg, src, srcw)); - - if (type & SLJIT_32) - srcw = (sljit_s32)srcw; - - if (have_lscond2() && (src & SLJIT_IMM) && is_s16(srcw)) { - ins = (type & SLJIT_32) ? 0xec0000000042 /* lochi */ : 0xec0000000046 /* locghi */; - return push_inst(compiler, ins | R36A(gpr(dst_reg)) | (mask << 32) | (sljit_ins)(srcw & 0xffff) << 16); - } - - if (src & SLJIT_IMM) { - FAIL_IF(push_load_imm_inst(compiler, tmp0, srcw)); - src_r = tmp0; - } else - src_r = gpr(src); - - if (have_lscond1()) { - ins = (type & SLJIT_32) ? 0xb9f20000 /* locr */ : 0xb9e20000 /* locgr */; - return push_inst(compiler, ins | (mask << 12) | R4A(gpr(dst_reg)) | R0A(src_r)); - } - - return sljit_emit_cmov_generic(compiler, type, dst_reg, src, srcw); -} - -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) -{ - sljit_ins ins, reg1, reg2, base, offs = 0; - - CHECK_ERROR(); - CHECK(check_sljit_emit_mem(compiler, type, reg, mem, memw)); - - if (!(reg & REG_PAIR_MASK)) - return sljit_emit_mem_unaligned(compiler, type, reg, mem, memw); - - ADJUST_LOCAL_OFFSET(mem, memw); - - base = gpr(mem & REG_MASK); - reg1 = gpr(REG_PAIR_FIRST(reg)); - reg2 = gpr(REG_PAIR_SECOND(reg)); - - if (mem & OFFS_REG_MASK) { - memw &= 0x3; - offs = gpr(OFFS_REG(mem)); - - if (memw != 0) { - FAIL_IF(push_inst(compiler, 0xeb000000000d /* sllg */ | R36A(tmp1) | R32A(offs) | ((sljit_ins)memw << 16))); - offs = tmp1; - } else if (!(type & SLJIT_MEM_STORE) && (base == reg1 || base == reg2) && (offs == reg1 || offs == reg2)) { - FAIL_IF(push_inst(compiler, 0xb9f80000 | R12A(tmp1) | R4A(base) | R0A(offs))); - base = tmp1; - offs = 0; - } - - memw = 0; - } else if (memw < -0x80000 || memw > 0x7ffff - ((reg2 == reg1 + 1) ? 0 : SSIZE_OF(sw))) { - FAIL_IF(push_load_imm_inst(compiler, tmp1, memw)); - - if (base == 0) - base = tmp1; - else - offs = tmp1; - - memw = 0; - } - - if (offs == 0 && reg2 == (reg1 + 1)) { - ins = (type & SLJIT_MEM_STORE) ? 0xeb0000000024 /* stmg */ : 0xeb0000000004 /* lmg */; - return push_inst(compiler, ins | R36A(reg1) | R32A(reg2) | R28A(base) | disp_s20((sljit_s32)memw)); - } - - ins = ((type & SLJIT_MEM_STORE) ? 0xe30000000024 /* stg */ : 0xe30000000004 /* lg */) | R32A(offs) | R28A(base); - - if (!(type & SLJIT_MEM_STORE) && base == reg1) { - FAIL_IF(push_inst(compiler, ins | R36A(reg2) | disp_s20((sljit_s32)memw + SSIZE_OF(sw)))); - return push_inst(compiler, ins | R36A(reg1) | disp_s20((sljit_s32)memw)); - } - - FAIL_IF(push_inst(compiler, ins | R36A(reg1) | disp_s20((sljit_s32)memw))); - return push_inst(compiler, ins | R36A(reg2) | disp_s20((sljit_s32)memw + SSIZE_OF(sw))); -} - -/* --------------------------------------------------------------------- */ -/* Other instructions */ -/* --------------------------------------------------------------------- */ - -/* On s390x we build a literal pool to hold constants. This has two main - advantages: - - 1. we only need one instruction in the instruction stream (LGRL) - 2. we can store 64 bit addresses and use 32 bit offsets - - To retrofit the extra information needed to build the literal pool we - add a new sljit_s390x_const struct that contains the initial value but - can still be cast to a sljit_const. */ - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value) -{ - struct sljit_s390x_const *const_; - sljit_gpr dst_r; - - CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_const(compiler, dst, dstw, init_value)); - - const_ = (struct sljit_s390x_const*)ensure_abuf(compiler, - sizeof(struct sljit_s390x_const)); - PTR_FAIL_IF(!const_); - set_const((struct sljit_const*)const_, compiler); - const_->init_value = init_value; - - 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))); - else { - PTR_FAIL_IF(push_inst(compiler, sljit_ins_const | larl(tmp1, 0))); - PTR_FAIL_IF(push_inst(compiler, lg(dst_r, 0, r0, tmp1))); - } - - if (dst & SLJIT_MEM) - PTR_FAIL_IF(store_word(compiler, dst_r, dst, dstw, 0 /* always 64-bit */)); - - return (struct sljit_const*)const_; -} - -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset) -{ - /* Update the constant pool. */ - sljit_uw *ptr = (sljit_uw *)addr; - SLJIT_UNUSED_ARG(executable_offset); - - SLJIT_UPDATE_WX_FLAGS(ptr, ptr + 1, 0); - *ptr = new_target; - SLJIT_UPDATE_WX_FLAGS(ptr, ptr + 1, 1); - SLJIT_CACHE_FLUSH(ptr, ptr + 1); -} - -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset) -{ - 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) -{ - struct sljit_put_label *put_label; - sljit_gpr dst_r; - - CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_put_label(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); - - dst_r = FAST_IS_REG(dst) ? gpr(dst & REG_MASK) : tmp0; - - if (have_genext()) - PTR_FAIL_IF(push_inst(compiler, lgrl(dst_r, 0))); - else { - PTR_FAIL_IF(push_inst(compiler, larl(tmp1, 0))); - PTR_FAIL_IF(push_inst(compiler, lg(dst_r, 0, r0, tmp1))); - } - - if (dst & SLJIT_MEM) - PTR_FAIL_IF(store_word(compiler, dst_r, dst, dstw, 0)); - - return put_label; -} - -/* TODO(carenas): EVAL probably should move up or be refactored */ -#undef WHEN2 -#undef EVAL - -#undef tmp1 -#undef tmp0 - -/* TODO(carenas): undef other macros that spill like is_u12? */ diff --git a/modules/regex/pcre2/src/sljit/sljitNativeX86_32.c b/modules/regex/pcre2/src/sljit/sljitNativeX86_32.c deleted file mode 100644 index 08da030..0000000 --- a/modules/regex/pcre2/src/sljit/sljitNativeX86_32.c +++ /dev/null @@ -1,1298 +0,0 @@ -/* - * 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. - */ - -/* x86 32-bit arch dependent functions. */ - -/* --------------------------------------------------------------------- */ -/* Operators */ -/* --------------------------------------------------------------------- */ - -static sljit_s32 emit_do_imm(struct sljit_compiler *compiler, sljit_u8 opcode, sljit_sw imm) -{ - sljit_u8 *inst; - - inst = (sljit_u8*)ensure_buf(compiler, 1 + 1 + sizeof(sljit_sw)); - FAIL_IF(!inst); - INC_SIZE(1 + sizeof(sljit_sw)); - *inst++ = opcode; - sljit_unaligned_store_sw(inst, imm); - return SLJIT_SUCCESS; -} - -/* Size contains the flags as well. */ -static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_uw size, - /* The register or immediate operand. */ - sljit_s32 a, sljit_sw imma, - /* The general operand (not immediate). */ - sljit_s32 b, sljit_sw immb) -{ - sljit_u8 *inst; - sljit_u8 *buf_ptr; - sljit_u8 reg_map_b; - sljit_uw flags = size; - sljit_uw inst_size; - - /* Both cannot be switched on. */ - SLJIT_ASSERT((flags & (EX86_BIN_INS | EX86_SHIFT_INS)) != (EX86_BIN_INS | EX86_SHIFT_INS)); - /* Size flags not allowed for typed instructions. */ - SLJIT_ASSERT(!(flags & (EX86_BIN_INS | EX86_SHIFT_INS)) || (flags & (EX86_BYTE_ARG | EX86_HALF_ARG)) == 0); - /* Both size flags cannot be switched on. */ - SLJIT_ASSERT((flags & (EX86_BYTE_ARG | EX86_HALF_ARG)) != (EX86_BYTE_ARG | EX86_HALF_ARG)); - /* SSE2 and immediate is not possible. */ - SLJIT_ASSERT(!(a & SLJIT_IMM) || !(flags & EX86_SSE2)); - SLJIT_ASSERT((flags & (EX86_PREF_F2 | EX86_PREF_F3)) != (EX86_PREF_F2 | EX86_PREF_F3) - && (flags & (EX86_PREF_F2 | EX86_PREF_66)) != (EX86_PREF_F2 | EX86_PREF_66) - && (flags & (EX86_PREF_F3 | EX86_PREF_66)) != (EX86_PREF_F3 | EX86_PREF_66)); - - size &= 0xf; - inst_size = size; - - if (flags & (EX86_PREF_F2 | EX86_PREF_F3)) - inst_size++; - if (flags & EX86_PREF_66) - inst_size++; - - /* Calculate size of b. */ - inst_size += 1; /* mod r/m byte. */ - if (b & SLJIT_MEM) { - if (!(b & REG_MASK)) - inst_size += sizeof(sljit_sw); - else { - if (immb != 0 && !(b & OFFS_REG_MASK)) { - /* Immediate operand. */ - if (immb <= 127 && immb >= -128) - inst_size += sizeof(sljit_s8); - else - inst_size += sizeof(sljit_sw); - } - else if (reg_map[b & REG_MASK] == 5) { - /* Swap registers if possible. */ - if ((b & OFFS_REG_MASK) && (immb & 0x3) == 0 && reg_map[OFFS_REG(b)] != 5) - b = SLJIT_MEM | OFFS_REG(b) | TO_OFFS_REG(b & REG_MASK); - else - inst_size += sizeof(sljit_s8); - } - - if (reg_map[b & REG_MASK] == 4 && !(b & OFFS_REG_MASK)) - b |= TO_OFFS_REG(SLJIT_SP); - - if (b & OFFS_REG_MASK) - inst_size += 1; /* SIB byte. */ - } - } - - /* Calculate size of a. */ - if (a & SLJIT_IMM) { - if (flags & EX86_BIN_INS) { - if (imma <= 127 && imma >= -128) { - inst_size += 1; - flags |= EX86_BYTE_ARG; - } else - inst_size += 4; - } - else if (flags & EX86_SHIFT_INS) { - SLJIT_ASSERT(imma <= 0x1f); - if (imma != 1) { - inst_size++; - flags |= EX86_BYTE_ARG; - } - } else if (flags & EX86_BYTE_ARG) - inst_size++; - else if (flags & EX86_HALF_ARG) - inst_size += sizeof(short); - else - inst_size += sizeof(sljit_sw); - } - else - SLJIT_ASSERT(!(flags & EX86_SHIFT_INS) || a == SLJIT_PREF_SHIFT_REG); - - inst = (sljit_u8*)ensure_buf(compiler, 1 + inst_size); - PTR_FAIL_IF(!inst); - - /* Encoding the byte. */ - INC_SIZE(inst_size); - if (flags & EX86_PREF_F2) - *inst++ = 0xf2; - if (flags & EX86_PREF_F3) - *inst++ = 0xf3; - if (flags & EX86_PREF_66) - *inst++ = 0x66; - - buf_ptr = inst + size; - - /* Encode mod/rm byte. */ - if (!(flags & EX86_SHIFT_INS)) { - if ((flags & EX86_BIN_INS) && (a & SLJIT_IMM)) - *inst = (flags & EX86_BYTE_ARG) ? GROUP_BINARY_83 : GROUP_BINARY_81; - - if (a & SLJIT_IMM) - *buf_ptr = 0; - else if (!(flags & EX86_SSE2_OP1)) - *buf_ptr = U8(reg_map[a] << 3); - else - *buf_ptr = U8(a << 3); - } - else { - if (a & SLJIT_IMM) { - if (imma == 1) - *inst = GROUP_SHIFT_1; - else - *inst = GROUP_SHIFT_N; - } else - *inst = GROUP_SHIFT_CL; - *buf_ptr = 0; - } - - if (!(b & SLJIT_MEM)) { - *buf_ptr = U8(*buf_ptr | MOD_REG | (!(flags & EX86_SSE2_OP2) ? reg_map[b] : b)); - buf_ptr++; - } else if (b & REG_MASK) { - reg_map_b = reg_map[b & REG_MASK]; - - if (!(b & OFFS_REG_MASK) || (b & OFFS_REG_MASK) == TO_OFFS_REG(SLJIT_SP)) { - if (immb != 0 || reg_map_b == 5) { - if (immb <= 127 && immb >= -128) - *buf_ptr |= 0x40; - else - *buf_ptr |= 0x80; - } - - if (!(b & OFFS_REG_MASK)) - *buf_ptr++ |= reg_map_b; - else { - *buf_ptr++ |= 0x04; - *buf_ptr++ = U8(reg_map_b | (reg_map[OFFS_REG(b)] << 3)); - } - - if (immb != 0 || reg_map_b == 5) { - if (immb <= 127 && immb >= -128) - *buf_ptr++ = U8(immb); /* 8 bit displacement. */ - else { - sljit_unaligned_store_sw(buf_ptr, immb); /* 32 bit displacement. */ - buf_ptr += sizeof(sljit_sw); - } - } - } - else { - if (reg_map_b == 5) - *buf_ptr |= 0x40; - - *buf_ptr++ |= 0x04; - *buf_ptr++ = U8(reg_map_b | (reg_map[OFFS_REG(b)] << 3) | (immb << 6)); - - if (reg_map_b == 5) - *buf_ptr++ = 0; - } - } - else { - *buf_ptr++ |= 0x05; - sljit_unaligned_store_sw(buf_ptr, immb); /* 32 bit displacement. */ - buf_ptr += sizeof(sljit_sw); - } - - if (a & SLJIT_IMM) { - if (flags & EX86_BYTE_ARG) - *buf_ptr = U8(imma); - else if (flags & EX86_HALF_ARG) - sljit_unaligned_store_s16(buf_ptr, (sljit_s16)imma); - else if (!(flags & EX86_SHIFT_INS)) - sljit_unaligned_store_sw(buf_ptr, imma); - } - - return !(flags & EX86_SHIFT_INS) ? inst : (inst + 1); -} - -/* --------------------------------------------------------------------- */ -/* Enter / return */ -/* --------------------------------------------------------------------- */ - -static sljit_u8* generate_far_jump_code(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) { - *code_ptr++ = CALL_i32; - jump->addr++; - } - else { - *code_ptr++ = GROUP_0F; - *code_ptr++ = get_jump_code(type); - jump->addr += 2; - } - - if (jump->flags & JUMP_LABEL) - jump->flags |= PATCH_MW; - else - sljit_unaligned_store_sw(code_ptr, (sljit_sw)(jump->u.target - (jump->addr + 4) - (sljit_uw)executable_offset)); - code_ptr += 4; - - return code_ptr; -} - -#define ENTER_TMP_TO_R4 0x00001 -#define ENTER_TMP_TO_S 0x00002 - -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, - sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size) -{ - sljit_s32 word_arg_count, saved_arg_count, float_arg_count; - sljit_s32 size, args_size, types, status; - sljit_s32 kept_saveds_count = SLJIT_KEPT_SAVEDS_COUNT(options); - sljit_u8 *inst; -#ifdef _WIN32 - sljit_s32 r2_offset = -1; -#endif - - CHECK_ERROR(); - CHECK(check_sljit_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size)); - set_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size); - - /* Emit ENDBR32 at function entry if needed. */ - FAIL_IF(emit_endbranch(compiler)); - - SLJIT_COMPILE_ASSERT(SLJIT_FR0 == 1, float_register_index_start); - - arg_types >>= SLJIT_ARG_SHIFT; - word_arg_count = 0; - status = 0; - - if (options & SLJIT_ENTER_REG_ARG) { - args_size = 3 * SSIZE_OF(sw); - - while (arg_types) { - if ((arg_types & SLJIT_ARG_MASK) < SLJIT_ARG_TYPE_F64) { - word_arg_count++; - if (word_arg_count >= 4) - status |= ENTER_TMP_TO_R4; - } - - arg_types >>= SLJIT_ARG_SHIFT; - } - - compiler->args_size = 0; - } else { - types = arg_types; - saved_arg_count = 0; - float_arg_count = 0; - args_size = SSIZE_OF(sw); - while (types) { - switch (types & SLJIT_ARG_MASK) { - case SLJIT_ARG_TYPE_F64: - float_arg_count++; - FAIL_IF(emit_sse2_load(compiler, 0, float_arg_count, SLJIT_MEM1(SLJIT_SP), args_size)); - args_size += SSIZE_OF(f64); - break; - case SLJIT_ARG_TYPE_F32: - float_arg_count++; - FAIL_IF(emit_sse2_load(compiler, 1, float_arg_count, SLJIT_MEM1(SLJIT_SP), args_size)); - args_size += SSIZE_OF(f32); - break; - default: - word_arg_count++; - - if (!(types & SLJIT_ARG_TYPE_SCRATCH_REG)) - saved_arg_count++; - - if (word_arg_count == 4) { - if (types & SLJIT_ARG_TYPE_SCRATCH_REG) { - status |= ENTER_TMP_TO_R4; - arg_types &= ~(SLJIT_ARG_FULL_MASK << 3 * SLJIT_ARG_SHIFT); - } else if (saved_arg_count == 4) { - status |= ENTER_TMP_TO_S; - arg_types &= ~(SLJIT_ARG_FULL_MASK << 3 * SLJIT_ARG_SHIFT); - } - } - - args_size += SSIZE_OF(sw); - break; - } - types >>= SLJIT_ARG_SHIFT; - } - - args_size -= SSIZE_OF(sw); - compiler->args_size = args_size; - } - - size = (scratches > 9 ? (scratches - 9) : 0) + (saveds <= 3 ? saveds : 3) - kept_saveds_count; - if (!(options & SLJIT_ENTER_REG_ARG)) - size++; - - if (size != 0) { - inst = (sljit_u8*)ensure_buf(compiler, (sljit_uw)(size + 1)); - FAIL_IF(!inst); - - INC_SIZE((sljit_uw)size); - - if (!(options & SLJIT_ENTER_REG_ARG)) - PUSH_REG(reg_map[TMP_REG1]); - - if ((saveds > 2 && kept_saveds_count <= 2) || scratches > 9) - PUSH_REG(reg_map[SLJIT_S2]); - if ((saveds > 1 && kept_saveds_count <= 1) || scratches > 10) - PUSH_REG(reg_map[SLJIT_S1]); - if ((saveds > 0 && kept_saveds_count == 0) || scratches > 11) - PUSH_REG(reg_map[SLJIT_S0]); - - size *= SSIZE_OF(sw); - } - - if (status & (ENTER_TMP_TO_R4 | ENTER_TMP_TO_S)) - EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_MEM1(SLJIT_SP), args_size + size); - - size += SSIZE_OF(sw); - - local_size = ((SLJIT_LOCALS_OFFSET_BASE + local_size + size + 0xf) & ~0xf) - size; - compiler->local_size = local_size; - - word_arg_count = 0; - saved_arg_count = 0; - args_size = size; - while (arg_types) { - switch (arg_types & SLJIT_ARG_MASK) { - case SLJIT_ARG_TYPE_F64: - args_size += SSIZE_OF(f64); - break; - case SLJIT_ARG_TYPE_F32: - args_size += SSIZE_OF(f32); - break; - default: - word_arg_count++; - SLJIT_ASSERT(word_arg_count <= 3 || (word_arg_count == 4 && !(status & (ENTER_TMP_TO_R4 | ENTER_TMP_TO_S)))); - - if (arg_types & SLJIT_ARG_TYPE_SCRATCH_REG) { -#ifdef _WIN32 - if (word_arg_count == 3 && local_size > 4 * 4096) - r2_offset = local_size + args_size; - else -#endif - EMIT_MOV(compiler, word_arg_count, 0, SLJIT_MEM1(SLJIT_SP), args_size); - - } else { - EMIT_MOV(compiler, SLJIT_S0 - saved_arg_count, 0, SLJIT_MEM1(SLJIT_SP), args_size); - saved_arg_count++; - } - - args_size += SSIZE_OF(sw); - break; - } - arg_types >>= SLJIT_ARG_SHIFT; - } - - SLJIT_ASSERT(SLJIT_LOCALS_OFFSET > 0); - -#ifdef _WIN32 - SLJIT_ASSERT(r2_offset == -1 || local_size > 4 * 4096); - - if (local_size > 4096) { - if (local_size <= 4 * 4096) { - BINARY_IMM32(OR, 0, SLJIT_MEM1(SLJIT_SP), -4096); - - if (local_size > 2 * 4096) - BINARY_IMM32(OR, 0, SLJIT_MEM1(SLJIT_SP), -4096 * 2); - if (local_size > 3 * 4096) - BINARY_IMM32(OR, 0, SLJIT_MEM1(SLJIT_SP), -4096 * 3); - } - else { - if (options & SLJIT_ENTER_REG_ARG) { - SLJIT_ASSERT(r2_offset == -1); - - inst = (sljit_u8*)ensure_buf(compiler, (sljit_uw)(1 + 1)); - FAIL_IF(!inst); - INC_SIZE(1); - PUSH_REG(reg_map[SLJIT_R2]); - - local_size -= SSIZE_OF(sw); - r2_offset = local_size; - } - - EMIT_MOV(compiler, SLJIT_R2, 0, SLJIT_IMM, local_size >> 12); - - BINARY_IMM32(OR, 0, SLJIT_MEM1(SLJIT_SP), -4096); - BINARY_IMM32(SUB, 4096, SLJIT_SP, 0); - - inst = (sljit_u8*)ensure_buf(compiler, 1 + 2); - FAIL_IF(!inst); - - INC_SIZE(2); - inst[0] = LOOP_i8; - inst[1] = (sljit_u8)-16; - local_size &= 0xfff; - } - } - - if (local_size > 0) { - BINARY_IMM32(OR, 0, SLJIT_MEM1(SLJIT_SP), -local_size); - BINARY_IMM32(SUB, local_size, SLJIT_SP, 0); - } - - if (r2_offset != -1) - EMIT_MOV(compiler, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_SP), r2_offset); - -#else /* !_WIN32 */ - - SLJIT_ASSERT(local_size > 0); - - BINARY_IMM32(SUB, local_size, SLJIT_SP, 0); - -#endif /* _WIN32 */ - - size = SLJIT_LOCALS_OFFSET_BASE - SSIZE_OF(sw); - kept_saveds_count = SLJIT_R3 - kept_saveds_count; - - while (saved_arg_count > 3) { - EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_SP), size, kept_saveds_count, 0); - kept_saveds_count++; - size -= SSIZE_OF(sw); - saved_arg_count--; - } - - if (status & (ENTER_TMP_TO_R4 | ENTER_TMP_TO_S)) { - if (status & ENTER_TMP_TO_R4) - size = 2 * SSIZE_OF(sw); - - EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_SP), size, TMP_REG1, 0); - } - - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(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) -{ - sljit_s32 args_size; - - CHECK_ERROR(); - CHECK(check_sljit_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size)); - set_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size); - - arg_types >>= SLJIT_ARG_SHIFT; - args_size = 0; - - if (!(options & SLJIT_ENTER_REG_ARG)) { - while (arg_types) { - switch (arg_types & SLJIT_ARG_MASK) { - case SLJIT_ARG_TYPE_F64: - args_size += SSIZE_OF(f64); - break; - case SLJIT_ARG_TYPE_F32: - args_size += SSIZE_OF(f32); - break; - default: - args_size += SSIZE_OF(sw); - break; - } - arg_types >>= SLJIT_ARG_SHIFT; - } - } - - compiler->args_size = args_size; - - /* [esp+0] for saving temporaries and for function calls. */ - - saveds = (1 + (scratches > 9 ? (scratches - 9) : 0) + (saveds <= 3 ? saveds : 3) - SLJIT_KEPT_SAVEDS_COUNT(options)) * SSIZE_OF(sw); - - /* Saving ebp. */ - if (!(options & SLJIT_ENTER_REG_ARG)) - saveds += SSIZE_OF(sw); - - compiler->local_size = ((SLJIT_LOCALS_OFFSET_BASE + local_size + saveds + 0xf) & ~0xf) - saveds; - return SLJIT_SUCCESS; -} - -static sljit_s32 emit_stack_frame_release(struct sljit_compiler *compiler, sljit_s32 is_return_to) -{ - sljit_s32 kept_saveds_count = SLJIT_KEPT_SAVEDS_COUNT(compiler->options); - sljit_s32 local_size, saveds; - sljit_uw size; - sljit_u8 *inst; - - size = (sljit_uw)((compiler->scratches > 9 ? (compiler->scratches - 9) : 0) + - (compiler->saveds <= 3 ? compiler->saveds : 3) - kept_saveds_count); - - local_size = compiler->local_size; - - if (!(compiler->options & SLJIT_ENTER_REG_ARG)) - size++; - else if (is_return_to && size == 0) { - local_size += SSIZE_OF(sw); - is_return_to = 0; - } - - if (local_size > 0) - BINARY_IMM32(ADD, local_size, SLJIT_SP, 0); - - if (size == 0) - return SLJIT_SUCCESS; - - inst = (sljit_u8*)ensure_buf(compiler, 1 + size); - FAIL_IF(!inst); - - INC_SIZE(size); - - saveds = compiler->saveds; - - if ((saveds > 0 && kept_saveds_count == 0) || compiler->scratches > 11) - POP_REG(reg_map[SLJIT_S0]); - if ((saveds > 1 && kept_saveds_count <= 1) || compiler->scratches > 10) - POP_REG(reg_map[SLJIT_S1]); - if ((saveds > 2 && kept_saveds_count <= 2) || compiler->scratches > 9) - POP_REG(reg_map[SLJIT_S2]); - - if (!(compiler->options & SLJIT_ENTER_REG_ARG)) - POP_REG(reg_map[TMP_REG1]); - - if (is_return_to) - BINARY_IMM32(ADD, sizeof(sljit_sw), SLJIT_SP, 0); - - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_void(struct sljit_compiler *compiler) -{ - sljit_u8 *inst; - - CHECK_ERROR(); - CHECK(check_sljit_emit_return_void(compiler)); - - SLJIT_ASSERT(compiler->args_size >= 0); - SLJIT_ASSERT(compiler->local_size > 0); - - FAIL_IF(emit_stack_frame_release(compiler, 0)); - - inst = (sljit_u8*)ensure_buf(compiler, 1 + 1); - FAIL_IF(!inst); - INC_SIZE(1); - RET(); - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_to(struct sljit_compiler *compiler, - sljit_s32 src, sljit_sw srcw) -{ - sljit_s32 src_r; - - CHECK_ERROR(); - CHECK(check_sljit_emit_return_to(compiler, src, srcw)); - - if ((src & SLJIT_MEM) || (src > SLJIT_R2 && src <= (SLJIT_S0 - SLJIT_KEPT_SAVEDS_COUNT(compiler->options)))) { - ADJUST_LOCAL_OFFSET(src, srcw); - CHECK_EXTRA_REGS(src, srcw, (void)0); - - src_r = (compiler->options & SLJIT_ENTER_REG_ARG) ? TMP_REG1 : SLJIT_R1; - - EMIT_MOV(compiler, src_r, 0, src, srcw); - src = src_r; - srcw = 0; - } - - FAIL_IF(emit_stack_frame_release(compiler, 1)); - - SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_ijump(compiler, SLJIT_JUMP, src, srcw); -} - -/* --------------------------------------------------------------------- */ -/* Call / return instructions */ -/* --------------------------------------------------------------------- */ - -static sljit_s32 call_get_stack_size(sljit_s32 arg_types, sljit_s32 *word_arg_count_ptr) -{ - sljit_sw stack_size = 0; - sljit_s32 word_arg_count = 0; - - arg_types >>= SLJIT_ARG_SHIFT; - - while (arg_types) { - switch (arg_types & SLJIT_ARG_MASK) { - case SLJIT_ARG_TYPE_F64: - stack_size += SSIZE_OF(f64); - break; - case SLJIT_ARG_TYPE_F32: - stack_size += SSIZE_OF(f32); - break; - default: - word_arg_count++; - stack_size += SSIZE_OF(sw); - break; - } - - arg_types >>= SLJIT_ARG_SHIFT; - } - - if (word_arg_count_ptr) - *word_arg_count_ptr = word_arg_count; - - if (stack_size <= 4 * SSIZE_OF(sw)) - return 0; - - return ((stack_size - (4 * SSIZE_OF(sw)) + 0xf) & ~0xf); -} - -static sljit_s32 call_with_args(struct sljit_compiler *compiler, - sljit_s32 arg_types, sljit_sw stack_size, sljit_s32 word_arg_count, sljit_s32 keep_tmp1) -{ - sljit_s32 float_arg_count = 0, arg4_reg = 0, arg_offset; - sljit_u8 *inst; - - if (word_arg_count >= 4) { - arg4_reg = SLJIT_R0; - - if (!keep_tmp1) { - EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_MEM1(SLJIT_SP), 2 * SSIZE_OF(sw)); - arg4_reg = TMP_REG1; - } - } - - if (stack_size > 0) - BINARY_IMM32(SUB, stack_size, SLJIT_SP, 0); - - arg_offset = 0; - word_arg_count = 0; - arg_types >>= SLJIT_ARG_SHIFT; - - while (arg_types) { - switch (arg_types & SLJIT_ARG_MASK) { - case SLJIT_ARG_TYPE_F64: - float_arg_count++; - FAIL_IF(emit_sse2_store(compiler, 0, SLJIT_MEM1(SLJIT_SP), arg_offset, float_arg_count)); - arg_offset += SSIZE_OF(f64); - break; - case SLJIT_ARG_TYPE_F32: - float_arg_count++; - FAIL_IF(emit_sse2_store(compiler, 1, SLJIT_MEM1(SLJIT_SP), arg_offset, float_arg_count)); - arg_offset += SSIZE_OF(f32); - break; - default: - word_arg_count++; - EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_SP), arg_offset, (word_arg_count >= 4) ? arg4_reg : word_arg_count, 0); - - if (word_arg_count == 1 && arg4_reg == SLJIT_R0) - EMIT_MOV(compiler, SLJIT_R0, 0, SLJIT_MEM1(SLJIT_SP), 2 * SSIZE_OF(sw) + stack_size); - - arg_offset += SSIZE_OF(sw); - break; - } - - arg_types >>= SLJIT_ARG_SHIFT; - } - - return SLJIT_SUCCESS; -} - -static sljit_s32 post_call_with_args(struct sljit_compiler *compiler, - sljit_s32 arg_types, sljit_s32 stack_size) -{ - sljit_u8 *inst; - sljit_s32 single; - - if (stack_size > 0) - BINARY_IMM32(ADD, stack_size, SLJIT_SP, 0); - - if ((arg_types & SLJIT_ARG_MASK) < SLJIT_ARG_TYPE_F64) - return SLJIT_SUCCESS; - - single = ((arg_types & SLJIT_ARG_MASK) == SLJIT_ARG_TYPE_F32); - - inst = (sljit_u8*)ensure_buf(compiler, 1 + 3); - FAIL_IF(!inst); - INC_SIZE(3); - inst[0] = single ? FSTPS : FSTPD; - inst[1] = (0x03 << 3) | 0x04; - inst[2] = (0x04 << 3) | reg_map[SLJIT_SP]; - - return emit_sse2_load(compiler, single, SLJIT_FR0, SLJIT_MEM1(SLJIT_SP), 0); -} - -static sljit_s32 tail_call_with_args(struct sljit_compiler *compiler, - sljit_s32 *extra_space, sljit_s32 arg_types, - sljit_s32 src, sljit_sw srcw) -{ - sljit_sw args_size, saved_regs_size; - sljit_sw types, word_arg_count, float_arg_count; - sljit_sw stack_size, prev_stack_size, min_size, offset; - sljit_sw word_arg4_offset; - sljit_u8 r2_offset = 0; - sljit_s32 kept_saveds_count = SLJIT_KEPT_SAVEDS_COUNT(compiler->options); - sljit_u8* inst; - - ADJUST_LOCAL_OFFSET(src, srcw); - CHECK_EXTRA_REGS(src, srcw, (void)0); - - saved_regs_size = (1 + (compiler->scratches > 9 ? (compiler->scratches - 9) : 0) - + (compiler->saveds <= 3 ? compiler->saveds : 3) - kept_saveds_count) * SSIZE_OF(sw); - - word_arg_count = 0; - float_arg_count = 0; - arg_types >>= SLJIT_ARG_SHIFT; - types = 0; - args_size = 0; - - while (arg_types != 0) { - types = (types << SLJIT_ARG_SHIFT) | (arg_types & SLJIT_ARG_MASK); - - switch (arg_types & SLJIT_ARG_MASK) { - case SLJIT_ARG_TYPE_F64: - args_size += SSIZE_OF(f64); - float_arg_count++; - break; - case SLJIT_ARG_TYPE_F32: - args_size += SSIZE_OF(f32); - float_arg_count++; - break; - default: - word_arg_count++; - args_size += SSIZE_OF(sw); - break; - } - arg_types >>= SLJIT_ARG_SHIFT; - } - - if (args_size <= compiler->args_size) { - *extra_space = 0; - stack_size = args_size + SSIZE_OF(sw) + saved_regs_size; - - offset = stack_size + compiler->local_size; - - if (!(src & SLJIT_IMM) && src != SLJIT_R0) { - if (word_arg_count >= 1) { - EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_SP), 0, SLJIT_R0, 0); - r2_offset = sizeof(sljit_sw); - } - EMIT_MOV(compiler, SLJIT_R0, 0, src, srcw); - } - - while (types != 0) { - switch (types & SLJIT_ARG_MASK) { - case SLJIT_ARG_TYPE_F64: - offset -= SSIZE_OF(f64); - FAIL_IF(emit_sse2_store(compiler, 0, SLJIT_MEM1(SLJIT_SP), offset, float_arg_count)); - float_arg_count--; - break; - case SLJIT_ARG_TYPE_F32: - offset -= SSIZE_OF(f32); - FAIL_IF(emit_sse2_store(compiler, 0, SLJIT_MEM1(SLJIT_SP), offset, float_arg_count)); - float_arg_count--; - break; - default: - switch (word_arg_count) { - case 1: - offset -= SSIZE_OF(sw); - if (r2_offset != 0) { - EMIT_MOV(compiler, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_SP), 0); - EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_SP), offset, SLJIT_R2, 0); - } else - EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_SP), offset, SLJIT_R0, 0); - break; - case 2: - offset -= SSIZE_OF(sw); - EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_SP), offset, SLJIT_R1, 0); - break; - case 3: - offset -= SSIZE_OF(sw); - break; - case 4: - offset -= SSIZE_OF(sw); - EMIT_MOV(compiler, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_SP), 2 * SSIZE_OF(sw)); - EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_SP), offset, SLJIT_R2, 0); - break; - } - word_arg_count--; - break; - } - types >>= SLJIT_ARG_SHIFT; - } - - return emit_stack_frame_release(compiler, 0); - } - - stack_size = args_size + SSIZE_OF(sw); - - if (word_arg_count >= 1 && !(src & SLJIT_IMM) && src != SLJIT_R0) { - r2_offset = SSIZE_OF(sw); - stack_size += SSIZE_OF(sw); - } - - if (word_arg_count >= 3) - stack_size += SSIZE_OF(sw); - - prev_stack_size = SSIZE_OF(sw) + saved_regs_size; - min_size = prev_stack_size + compiler->local_size; - - word_arg4_offset = 2 * SSIZE_OF(sw); - - if (stack_size > min_size) { - BINARY_IMM32(SUB, stack_size - min_size, SLJIT_SP, 0); - if (src == SLJIT_MEM1(SLJIT_SP)) - srcw += stack_size - min_size; - word_arg4_offset += stack_size - min_size; - } - else - stack_size = min_size; - - if (word_arg_count >= 3) { - EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_SP), r2_offset, SLJIT_R2, 0); - - if (word_arg_count >= 4) - EMIT_MOV(compiler, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_SP), word_arg4_offset); - } - - if (!(src & SLJIT_IMM) && src != SLJIT_R0) { - if (word_arg_count >= 1) { - SLJIT_ASSERT(r2_offset == sizeof(sljit_sw)); - EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_SP), 0, SLJIT_R0, 0); - } - EMIT_MOV(compiler, SLJIT_R0, 0, src, srcw); - } - - /* Restore saved registers. */ - offset = stack_size - 2 * SSIZE_OF(sw); - EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_MEM1(SLJIT_SP), offset); - - if (compiler->saveds > 2 || compiler->scratches > 9) { - offset -= SSIZE_OF(sw); - EMIT_MOV(compiler, SLJIT_S2, 0, SLJIT_MEM1(SLJIT_SP), offset); - } - if ((compiler->saveds > 1 && kept_saveds_count <= 1) || compiler->scratches > 10) { - offset -= SSIZE_OF(sw); - EMIT_MOV(compiler, SLJIT_S1, 0, SLJIT_MEM1(SLJIT_SP), offset); - } - if ((compiler->saveds > 0 && kept_saveds_count == 0) || compiler->scratches > 11) { - offset -= SSIZE_OF(sw); - EMIT_MOV(compiler, SLJIT_S0, 0, SLJIT_MEM1(SLJIT_SP), offset); - } - - /* Copy fourth argument and return address. */ - offset = stack_size - SSIZE_OF(sw); - *extra_space = args_size; - - if (word_arg_count >= 4) { - offset -= SSIZE_OF(sw); - EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_SP), offset, SLJIT_R2, 0); - } - - while (types != 0) { - switch (types & SLJIT_ARG_MASK) { - case SLJIT_ARG_TYPE_F64: - offset -= SSIZE_OF(f64); - FAIL_IF(emit_sse2_store(compiler, 0, SLJIT_MEM1(SLJIT_SP), offset, float_arg_count)); - float_arg_count--; - break; - case SLJIT_ARG_TYPE_F32: - offset -= SSIZE_OF(f32); - FAIL_IF(emit_sse2_store(compiler, 0, SLJIT_MEM1(SLJIT_SP), offset, float_arg_count)); - float_arg_count--; - break; - default: - switch (word_arg_count) { - case 1: - offset -= SSIZE_OF(sw); - if (r2_offset != 0) { - EMIT_MOV(compiler, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_SP), 0); - EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_SP), offset, SLJIT_R2, 0); - } else - EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_SP), offset, SLJIT_R0, 0); - break; - case 2: - offset -= SSIZE_OF(sw); - EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_SP), offset, SLJIT_R1, 0); - break; - case 3: - offset -= SSIZE_OF(sw); - EMIT_MOV(compiler, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_SP), r2_offset); - EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_SP), offset, SLJIT_R2, 0); - break; - } - word_arg_count--; - break; - } - types >>= SLJIT_ARG_SHIFT; - } - - SLJIT_ASSERT(offset >= 0); - - if (offset == 0) - return SLJIT_SUCCESS; - - BINARY_IMM32(ADD, offset, SLJIT_SP, 0); - return SLJIT_SUCCESS; -} - -static sljit_s32 emit_tail_call_end(struct sljit_compiler *compiler, sljit_s32 extra_space) -{ - /* Called when stack consumption cannot be reduced to 0. */ - sljit_u8 *inst; - - BINARY_IMM32(ADD, extra_space, SLJIT_SP, 0); - - inst = (sljit_u8*)ensure_buf(compiler, 1 + 1); - FAIL_IF(!inst); - INC_SIZE(1); - RET(); - - return SLJIT_SUCCESS; -} - -static sljit_s32 tail_call_reg_arg_with_args(struct sljit_compiler *compiler, sljit_s32 arg_types) -{ - sljit_s32 word_arg_count = 0; - sljit_s32 kept_saveds_count, offset; - - arg_types >>= SLJIT_ARG_SHIFT; - - while (arg_types) { - if ((arg_types & SLJIT_ARG_MASK) < SLJIT_ARG_TYPE_F64) - word_arg_count++; - - arg_types >>= SLJIT_ARG_SHIFT; - } - - if (word_arg_count < 4) - return SLJIT_SUCCESS; - - EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_MEM1(SLJIT_SP), 2 * SSIZE_OF(sw)); - - kept_saveds_count = SLJIT_KEPT_SAVEDS_COUNT(compiler->options); - offset = compiler->local_size + 3 * SSIZE_OF(sw); - - if ((compiler->saveds > 0 && kept_saveds_count == 0) || compiler->scratches > 11) - offset += SSIZE_OF(sw); - if ((compiler->saveds > 1 && kept_saveds_count <= 1) || compiler->scratches > 10) - offset += SSIZE_OF(sw); - if ((compiler->saveds > 2 && kept_saveds_count <= 2) || compiler->scratches > 9) - offset += SSIZE_OF(sw); - - return emit_mov(compiler, SLJIT_MEM1(SLJIT_SP), offset, TMP_REG1, 0); -} - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_call(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 arg_types) -{ - struct sljit_jump *jump; - sljit_sw stack_size = 0; - sljit_s32 word_arg_count; - - CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_call(compiler, type, arg_types)); - - if (type & SLJIT_CALL_RETURN) { - if ((type & 0xff) == SLJIT_CALL_REG_ARG) { - PTR_FAIL_IF(tail_call_reg_arg_with_args(compiler, arg_types)); - PTR_FAIL_IF(emit_stack_frame_release(compiler, 0)); - - SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_jump(compiler, SLJIT_JUMP | (type & SLJIT_REWRITABLE_JUMP)); - } - - stack_size = type; - PTR_FAIL_IF(tail_call_with_args(compiler, &stack_size, arg_types, SLJIT_IMM, 0)); - - SLJIT_SKIP_CHECKS(compiler); - - if (stack_size == 0) - return sljit_emit_jump(compiler, SLJIT_JUMP | (type & SLJIT_REWRITABLE_JUMP)); - - jump = sljit_emit_jump(compiler, type); - PTR_FAIL_IF(jump == NULL); - - PTR_FAIL_IF(emit_tail_call_end(compiler, stack_size)); - return jump; - } - - if ((type & 0xff) == SLJIT_CALL_REG_ARG) { - SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_jump(compiler, type); - } - - stack_size = call_get_stack_size(arg_types, &word_arg_count); - PTR_FAIL_IF(call_with_args(compiler, arg_types, stack_size, word_arg_count, 0)); - - SLJIT_SKIP_CHECKS(compiler); - jump = sljit_emit_jump(compiler, type); - PTR_FAIL_IF(jump == NULL); - - PTR_FAIL_IF(post_call_with_args(compiler, arg_types, stack_size)); - return jump; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 arg_types, - sljit_s32 src, sljit_sw srcw) -{ - sljit_sw stack_size = 0; - sljit_s32 word_arg_count; - - CHECK_ERROR(); - CHECK(check_sljit_emit_icall(compiler, type, arg_types, src, srcw)); - - if (type & SLJIT_CALL_RETURN) { - if ((type & 0xff) == SLJIT_CALL_REG_ARG) { - FAIL_IF(tail_call_reg_arg_with_args(compiler, arg_types)); - - if ((src & SLJIT_MEM) || (src > SLJIT_R2 && src <= (SLJIT_S0 - SLJIT_KEPT_SAVEDS_COUNT(compiler->options)))) { - ADJUST_LOCAL_OFFSET(src, srcw); - CHECK_EXTRA_REGS(src, srcw, (void)0); - - EMIT_MOV(compiler, TMP_REG1, 0, src, srcw); - src = TMP_REG1; - srcw = 0; - } - - FAIL_IF(emit_stack_frame_release(compiler, 0)); - - SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_ijump(compiler, SLJIT_JUMP, src, srcw); - } - - stack_size = type; - FAIL_IF(tail_call_with_args(compiler, &stack_size, arg_types, src, srcw)); - - if (!(src & SLJIT_IMM)) { - src = SLJIT_R0; - srcw = 0; - } - - SLJIT_SKIP_CHECKS(compiler); - - if (stack_size == 0) - return sljit_emit_ijump(compiler, SLJIT_JUMP, src, srcw); - - FAIL_IF(sljit_emit_ijump(compiler, type, src, srcw)); - return emit_tail_call_end(compiler, stack_size); - } - - if ((type & 0xff) == SLJIT_CALL_REG_ARG) { - SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_ijump(compiler, type, src, srcw); - } - - ADJUST_LOCAL_OFFSET(src, srcw); - CHECK_EXTRA_REGS(src, srcw, (void)0); - - if (src & SLJIT_MEM) { - EMIT_MOV(compiler, TMP_REG1, 0, src, srcw); - src = TMP_REG1; - srcw = 0; - } - - stack_size = call_get_stack_size(arg_types, &word_arg_count); - FAIL_IF(call_with_args(compiler, arg_types, stack_size, word_arg_count, src == TMP_REG1)); - - if (stack_size > 0 && src == SLJIT_MEM1(SLJIT_SP)) - srcw += stack_size; - - SLJIT_SKIP_CHECKS(compiler); - FAIL_IF(sljit_emit_ijump(compiler, type, src, srcw)); - - return post_call_with_args(compiler, arg_types, stack_size); -} - -static SLJIT_INLINE sljit_s32 emit_fmov_before_return(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw) -{ - sljit_u8* inst; - - if (compiler->options & SLJIT_ENTER_REG_ARG) { - if (src == SLJIT_FR0) - return SLJIT_SUCCESS; - - SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_fop1(compiler, op, SLJIT_RETURN_FREG, 0, src, srcw); - } - - if (FAST_IS_REG(src)) { - FAIL_IF(emit_sse2_store(compiler, op & SLJIT_32, SLJIT_MEM1(SLJIT_SP), 0, src)); - - src = SLJIT_MEM1(SLJIT_SP); - srcw = 0; - } else { - ADJUST_LOCAL_OFFSET(src, srcw); - } - - inst = emit_x86_instruction(compiler, 1 | EX86_SSE2_OP1, 0, 0, src, srcw); - *inst = (op & SLJIT_32) ? FLDS : FLDL; - - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw) -{ - sljit_u8 *inst; - - CHECK_ERROR(); - CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw)); - ADJUST_LOCAL_OFFSET(dst, dstw); - - CHECK_EXTRA_REGS(dst, dstw, (void)0); - - if (FAST_IS_REG(dst)) { - /* Unused dest is possible here. */ - inst = (sljit_u8*)ensure_buf(compiler, 1 + 1); - FAIL_IF(!inst); - - INC_SIZE(1); - POP_REG(reg_map[dst]); - return SLJIT_SUCCESS; - } - - /* Memory. */ - inst = emit_x86_instruction(compiler, 1, 0, 0, dst, dstw); - FAIL_IF(!inst); - *inst++ = POP_rm; - return SLJIT_SUCCESS; -} - -static sljit_s32 emit_fast_return(struct sljit_compiler *compiler, sljit_s32 src, sljit_sw srcw) -{ - sljit_u8 *inst; - - CHECK_EXTRA_REGS(src, srcw, (void)0); - - if (FAST_IS_REG(src)) { - inst = (sljit_u8*)ensure_buf(compiler, 1 + 1 + 1); - FAIL_IF(!inst); - - INC_SIZE(1 + 1); - PUSH_REG(reg_map[src]); - } - else { - inst = emit_x86_instruction(compiler, 1, 0, 0, src, srcw); - FAIL_IF(!inst); - *inst++ = GROUP_FF; - *inst |= PUSH_rm; - - inst = (sljit_u8*)ensure_buf(compiler, 1 + 1); - FAIL_IF(!inst); - INC_SIZE(1); - } - - RET(); - return SLJIT_SUCCESS; -} - -/* --------------------------------------------------------------------- */ -/* Other operations */ -/* --------------------------------------------------------------------- */ - -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) -{ - sljit_u8* inst; - sljit_s32 i, next, reg_idx, offset; - sljit_u8 regs[2]; - - CHECK_ERROR(); - CHECK(check_sljit_emit_mem(compiler, type, reg, mem, memw)); - - if (!(reg & REG_PAIR_MASK)) - return sljit_emit_mem_unaligned(compiler, type, reg, mem, memw); - - ADJUST_LOCAL_OFFSET(mem, memw); - - regs[0] = U8(REG_PAIR_FIRST(reg)); - regs[1] = U8(REG_PAIR_SECOND(reg)); - - next = SSIZE_OF(sw); - - if (!(type & SLJIT_MEM_STORE) && (regs[0] == (mem & REG_MASK) || regs[0] == OFFS_REG(mem))) { - if (regs[1] == (mem & REG_MASK) || regs[1] == OFFS_REG(mem)) { - /* None of them are virtual register so TMP_REG1 will not be used. */ - EMIT_MOV(compiler, TMP_REG1, 0, OFFS_REG(mem), 0); - - if (regs[1] == OFFS_REG(mem)) - next = -SSIZE_OF(sw); - - mem = (mem & ~OFFS_REG_MASK) | TO_OFFS_REG(TMP_REG1); - } else { - next = -SSIZE_OF(sw); - - if (!(mem & OFFS_REG_MASK)) - memw += SSIZE_OF(sw); - } - } - - for (i = 0; i < 2; i++) { - reg_idx = next > 0 ? i : (i ^ 0x1); - reg = regs[reg_idx]; - - offset = -1; - - if (reg >= SLJIT_R3 && reg <= SLJIT_S3) { - offset = (2 * SSIZE_OF(sw)) + ((reg) - SLJIT_R3) * SSIZE_OF(sw); - reg = TMP_REG1; - - if (type & SLJIT_MEM_STORE) - EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_MEM1(SLJIT_SP), offset); - } - - if ((mem & OFFS_REG_MASK) && (reg_idx == 1)) { - inst = (sljit_u8*)ensure_buf(compiler, (sljit_uw)(1 + 4)); - FAIL_IF(!inst); - - INC_SIZE(4); - - inst[0] = (type & SLJIT_MEM_STORE) ? MOV_rm_r : MOV_r_rm; - inst[1] = 0x44 | U8(reg_map[reg] << 3); - inst[2] = U8(memw << 6) | U8(reg_map[OFFS_REG(mem)] << 3) | reg_map[mem & REG_MASK]; - inst[3] = sizeof(sljit_sw); - } else if (type & SLJIT_MEM_STORE) { - EMIT_MOV(compiler, mem, memw, reg, 0); - } else { - EMIT_MOV(compiler, reg, 0, mem, memw); - } - - if (!(mem & OFFS_REG_MASK)) - memw += next; - - if (!(type & SLJIT_MEM_STORE) && offset != -1) - EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_SP), offset, TMP_REG1, 0); - } - - return SLJIT_SUCCESS; -} - -static sljit_s32 skip_frames_before_return(struct sljit_compiler *compiler) -{ - sljit_sw size; - - /* Don't adjust shadow stack if it isn't enabled. */ - if (!cpu_has_shadow_stack()) - return SLJIT_SUCCESS; - - SLJIT_ASSERT(compiler->args_size >= 0); - SLJIT_ASSERT(compiler->local_size > 0); - - size = compiler->local_size; - size += (1 + (compiler->scratches > 9 ? (compiler->scratches - 9) : 0) - + (compiler->saveds <= 3 ? compiler->saveds : 3)) * SSIZE_OF(sw); - - return adjust_shadow_stack(compiler, SLJIT_MEM1(SLJIT_SP), size); -} diff --git a/modules/regex/pcre2/src/sljit/sljitNativeX86_64.c b/modules/regex/pcre2/src/sljit/sljitNativeX86_64.c deleted file mode 100644 index 4e938ff..0000000 --- a/modules/regex/pcre2/src/sljit/sljitNativeX86_64.c +++ /dev/null @@ -1,1092 +0,0 @@ -/* - * 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. - */ - -/* x86 64-bit arch dependent functions. */ - -/* --------------------------------------------------------------------- */ -/* Operators */ -/* --------------------------------------------------------------------- */ - -static sljit_s32 emit_load_imm64(struct sljit_compiler *compiler, sljit_s32 reg, sljit_sw imm) -{ - sljit_u8 *inst; - - inst = (sljit_u8*)ensure_buf(compiler, 1 + 2 + sizeof(sljit_sw)); - FAIL_IF(!inst); - INC_SIZE(2 + sizeof(sljit_sw)); - *inst++ = REX_W | ((reg_map[reg] <= 7) ? 0 : REX_B); - *inst++ = U8(MOV_r_i32 | (reg_map[reg] & 0x7)); - sljit_unaligned_store_sw(inst, imm); - return SLJIT_SUCCESS; -} - -static sljit_s32 emit_do_imm32(struct sljit_compiler *compiler, sljit_u8 rex, sljit_u8 opcode, sljit_sw imm) -{ - sljit_u8 *inst; - sljit_uw length = (rex ? 2 : 1) + sizeof(sljit_s32); - - inst = (sljit_u8*)ensure_buf(compiler, 1 + length); - FAIL_IF(!inst); - INC_SIZE(length); - if (rex) - *inst++ = rex; - *inst++ = opcode; - sljit_unaligned_store_s32(inst, (sljit_s32)imm); - return SLJIT_SUCCESS; -} - -static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_uw size, - /* The register or immediate operand. */ - sljit_s32 a, sljit_sw imma, - /* The general operand (not immediate). */ - sljit_s32 b, sljit_sw immb) -{ - sljit_u8 *inst; - sljit_u8 *buf_ptr; - sljit_u8 rex = 0; - sljit_u8 reg_lmap_b; - sljit_uw flags = size; - sljit_uw inst_size; - - /* The immediate operand must be 32 bit. */ - SLJIT_ASSERT(!(a & SLJIT_IMM) || compiler->mode32 || IS_HALFWORD(imma)); - /* Both cannot be switched on. */ - SLJIT_ASSERT((flags & (EX86_BIN_INS | EX86_SHIFT_INS)) != (EX86_BIN_INS | EX86_SHIFT_INS)); - /* Size flags not allowed for typed instructions. */ - SLJIT_ASSERT(!(flags & (EX86_BIN_INS | EX86_SHIFT_INS)) || (flags & (EX86_BYTE_ARG | EX86_HALF_ARG)) == 0); - /* Both size flags cannot be switched on. */ - SLJIT_ASSERT((flags & (EX86_BYTE_ARG | EX86_HALF_ARG)) != (EX86_BYTE_ARG | EX86_HALF_ARG)); - /* SSE2 and immediate is not possible. */ - SLJIT_ASSERT(!(a & SLJIT_IMM) || !(flags & EX86_SSE2)); - SLJIT_ASSERT((flags & (EX86_PREF_F2 | EX86_PREF_F3)) != (EX86_PREF_F2 | EX86_PREF_F3) - && (flags & (EX86_PREF_F2 | EX86_PREF_66)) != (EX86_PREF_F2 | EX86_PREF_66) - && (flags & (EX86_PREF_F3 | EX86_PREF_66)) != (EX86_PREF_F3 | EX86_PREF_66)); - - size &= 0xf; - inst_size = size; - - if (!compiler->mode32 && !(flags & EX86_NO_REXW)) - rex |= REX_W; - else if (flags & EX86_REX) - rex |= REX; - - if (flags & (EX86_PREF_F2 | EX86_PREF_F3)) - inst_size++; - if (flags & EX86_PREF_66) - inst_size++; - - /* Calculate size of b. */ - inst_size += 1; /* mod r/m byte. */ - if (b & SLJIT_MEM) { - if (!(b & OFFS_REG_MASK) && NOT_HALFWORD(immb)) { - PTR_FAIL_IF(emit_load_imm64(compiler, TMP_REG2, immb)); - immb = 0; - if (b & REG_MASK) - b |= TO_OFFS_REG(TMP_REG2); - else - b |= TMP_REG2; - } - - if (!(b & REG_MASK)) - inst_size += 1 + sizeof(sljit_s32); /* SIB byte required to avoid RIP based addressing. */ - else { - if (immb != 0 && !(b & OFFS_REG_MASK)) { - /* Immediate operand. */ - if (immb <= 127 && immb >= -128) - inst_size += sizeof(sljit_s8); - else - inst_size += sizeof(sljit_s32); - } - else if (reg_lmap[b & REG_MASK] == 5) { - /* Swap registers if possible. */ - if ((b & OFFS_REG_MASK) && (immb & 0x3) == 0 && reg_lmap[OFFS_REG(b)] != 5) - b = SLJIT_MEM | OFFS_REG(b) | TO_OFFS_REG(b & REG_MASK); - else - inst_size += sizeof(sljit_s8); - } - - if (reg_map[b & REG_MASK] >= 8) - rex |= REX_B; - - if (reg_lmap[b & REG_MASK] == 4 && !(b & OFFS_REG_MASK)) - b |= TO_OFFS_REG(SLJIT_SP); - - if (b & OFFS_REG_MASK) { - inst_size += 1; /* SIB byte. */ - if (reg_map[OFFS_REG(b)] >= 8) - rex |= REX_X; - } - } - } - else if (!(flags & EX86_SSE2_OP2)) { - if (reg_map[b] >= 8) - rex |= REX_B; - } - else if (freg_map[b] >= 8) - rex |= REX_B; - - if (a & SLJIT_IMM) { - if (flags & EX86_BIN_INS) { - if (imma <= 127 && imma >= -128) { - inst_size += 1; - flags |= EX86_BYTE_ARG; - } else - inst_size += 4; - } - else if (flags & EX86_SHIFT_INS) { - SLJIT_ASSERT(imma <= (compiler->mode32 ? 0x1f : 0x3f)); - if (imma != 1) { - inst_size++; - flags |= EX86_BYTE_ARG; - } - } else if (flags & EX86_BYTE_ARG) - inst_size++; - else if (flags & EX86_HALF_ARG) - inst_size += sizeof(short); - else - inst_size += sizeof(sljit_s32); - } - else { - SLJIT_ASSERT(!(flags & EX86_SHIFT_INS) || a == SLJIT_PREF_SHIFT_REG); - /* reg_map[SLJIT_PREF_SHIFT_REG] is less than 8. */ - if (!(flags & EX86_SSE2_OP1)) { - if (reg_map[a] >= 8) - rex |= REX_R; - } - else if (freg_map[a] >= 8) - rex |= REX_R; - } - - if (rex) - inst_size++; - - inst = (sljit_u8*)ensure_buf(compiler, 1 + inst_size); - PTR_FAIL_IF(!inst); - - /* Encoding the byte. */ - INC_SIZE(inst_size); - if (flags & EX86_PREF_F2) - *inst++ = 0xf2; - if (flags & EX86_PREF_F3) - *inst++ = 0xf3; - if (flags & EX86_PREF_66) - *inst++ = 0x66; - if (rex) - *inst++ = rex; - buf_ptr = inst + size; - - /* Encode mod/rm byte. */ - if (!(flags & EX86_SHIFT_INS)) { - if ((flags & EX86_BIN_INS) && (a & SLJIT_IMM)) - *inst = (flags & EX86_BYTE_ARG) ? GROUP_BINARY_83 : GROUP_BINARY_81; - - if (a & SLJIT_IMM) - *buf_ptr = 0; - else if (!(flags & EX86_SSE2_OP1)) - *buf_ptr = U8(reg_lmap[a] << 3); - else - *buf_ptr = U8(freg_lmap[a] << 3); - } - else { - if (a & SLJIT_IMM) { - if (imma == 1) - *inst = GROUP_SHIFT_1; - else - *inst = GROUP_SHIFT_N; - } else - *inst = GROUP_SHIFT_CL; - *buf_ptr = 0; - } - - if (!(b & SLJIT_MEM)) { - *buf_ptr = U8(*buf_ptr | MOD_REG | (!(flags & EX86_SSE2_OP2) ? reg_lmap[b] : freg_lmap[b])); - buf_ptr++; - } else if (b & REG_MASK) { - reg_lmap_b = reg_lmap[b & REG_MASK]; - - if (!(b & OFFS_REG_MASK) || (b & OFFS_REG_MASK) == TO_OFFS_REG(SLJIT_SP)) { - if (immb != 0 || reg_lmap_b == 5) { - if (immb <= 127 && immb >= -128) - *buf_ptr |= 0x40; - else - *buf_ptr |= 0x80; - } - - if (!(b & OFFS_REG_MASK)) - *buf_ptr++ |= reg_lmap_b; - else { - *buf_ptr++ |= 0x04; - *buf_ptr++ = U8(reg_lmap_b | (reg_lmap[OFFS_REG(b)] << 3)); - } - - if (immb != 0 || reg_lmap_b == 5) { - if (immb <= 127 && immb >= -128) - *buf_ptr++ = U8(immb); /* 8 bit displacement. */ - else { - sljit_unaligned_store_s32(buf_ptr, (sljit_s32)immb); /* 32 bit displacement. */ - buf_ptr += sizeof(sljit_s32); - } - } - } - else { - if (reg_lmap_b == 5) - *buf_ptr |= 0x40; - - *buf_ptr++ |= 0x04; - *buf_ptr++ = U8(reg_lmap_b | (reg_lmap[OFFS_REG(b)] << 3) | (immb << 6)); - - if (reg_lmap_b == 5) - *buf_ptr++ = 0; - } - } - else { - *buf_ptr++ |= 0x04; - *buf_ptr++ = 0x25; - sljit_unaligned_store_s32(buf_ptr, (sljit_s32)immb); /* 32 bit displacement. */ - buf_ptr += sizeof(sljit_s32); - } - - if (a & SLJIT_IMM) { - if (flags & EX86_BYTE_ARG) - *buf_ptr = U8(imma); - else if (flags & EX86_HALF_ARG) - sljit_unaligned_store_s16(buf_ptr, (sljit_s16)imma); - else if (!(flags & EX86_SHIFT_INS)) - sljit_unaligned_store_s32(buf_ptr, (sljit_s32)imma); - } - - return !(flags & EX86_SHIFT_INS) ? inst : (inst + 1); -} - -/* --------------------------------------------------------------------- */ -/* Enter / return */ -/* --------------------------------------------------------------------- */ - -static sljit_u8* generate_far_jump_code(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); - - /* The relative jump below specialized for this case. */ - SLJIT_ASSERT(reg_map[TMP_REG2] >= 8); - - 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++ = short_addr ? REX_B : (REX_W | REX_B); - *code_ptr++ = MOV_r_i32 | reg_lmap[TMP_REG2]; - jump->addr = (sljit_uw)code_ptr; - - if (jump->flags & JUMP_LABEL) - jump->flags |= PATCH_MD; - else if (short_addr) - sljit_unaligned_store_s32(code_ptr, (sljit_s32)jump->u.target); - else - sljit_unaligned_store_sw(code_ptr, (sljit_sw)jump->u.target); - - 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]); - - return code_ptr; -} - -static sljit_u8* generate_put_label_code(struct sljit_put_label *put_label, sljit_u8 *code_ptr, sljit_uw max_label) -{ - if (max_label > HALFWORD_MAX) { - put_label->addr -= put_label->flags; - put_label->flags = PATCH_MD; - return code_ptr; - } - - if (put_label->flags == 0) { - /* Destination is register. */ - code_ptr = (sljit_u8*)put_label->addr - 2 - sizeof(sljit_uw); - - SLJIT_ASSERT((code_ptr[0] & 0xf8) == REX_W); - SLJIT_ASSERT((code_ptr[1] & 0xf8) == MOV_r_i32); - - 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); - } - - put_label->addr = (sljit_uw)code_ptr; - 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); - - SLJIT_ASSERT((code_ptr[0] & 0xf8) == REX_W); - - if ((code_ptr[1] & 0xf8) == MOV_r_i32) { - code_ptr += 2 + sizeof(sljit_uw); - SLJIT_ASSERT((code_ptr[0] & 0xf8) == REX_W); - } - - 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; -} - -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, - sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size) -{ - sljit_uw size; - sljit_s32 word_arg_count = 0; - sljit_s32 saved_arg_count = SLJIT_KEPT_SAVEDS_COUNT(options); - sljit_s32 saved_regs_size, tmp, i; -#ifdef _WIN64 - sljit_s32 saved_float_regs_size; - sljit_s32 saved_float_regs_offset = 0; - sljit_s32 float_arg_count = 0; -#endif /* _WIN64 */ - sljit_u8 *inst; - - CHECK_ERROR(); - CHECK(check_sljit_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size)); - set_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size); - - if (options & SLJIT_ENTER_REG_ARG) - arg_types = 0; - - /* Emit ENDBR64 at function entry if needed. */ - FAIL_IF(emit_endbranch(compiler)); - - compiler->mode32 = 0; - - /* Including the return address saved by the call instruction. */ - saved_regs_size = GET_SAVED_REGISTERS_SIZE(scratches, saveds - saved_arg_count, 1); - - tmp = SLJIT_S0 - saveds; - for (i = SLJIT_S0 - saved_arg_count; i > tmp; i--) { - size = reg_map[i] >= 8 ? 2 : 1; - inst = (sljit_u8*)ensure_buf(compiler, 1 + size); - FAIL_IF(!inst); - INC_SIZE(size); - if (reg_map[i] >= 8) - *inst++ = REX_B; - PUSH_REG(reg_lmap[i]); - } - - for (i = scratches; i >= SLJIT_FIRST_SAVED_REG; i--) { - size = reg_map[i] >= 8 ? 2 : 1; - inst = (sljit_u8*)ensure_buf(compiler, 1 + size); - FAIL_IF(!inst); - INC_SIZE(size); - if (reg_map[i] >= 8) - *inst++ = REX_B; - PUSH_REG(reg_lmap[i]); - } - -#ifdef _WIN64 - local_size += SLJIT_LOCALS_OFFSET; - saved_float_regs_size = GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, 16); - - if (saved_float_regs_size > 0) { - saved_float_regs_offset = ((local_size + 0xf) & ~0xf); - local_size = saved_float_regs_offset + saved_float_regs_size; - } -#else /* !_WIN64 */ - SLJIT_ASSERT(SLJIT_LOCALS_OFFSET == 0); -#endif /* _WIN64 */ - - arg_types >>= SLJIT_ARG_SHIFT; - - while (arg_types > 0) { - if ((arg_types & SLJIT_ARG_MASK) < SLJIT_ARG_TYPE_F64) { - tmp = 0; -#ifndef _WIN64 - switch (word_arg_count) { - case 0: - tmp = SLJIT_R2; - break; - case 1: - tmp = SLJIT_R1; - break; - case 2: - tmp = TMP_REG1; - break; - default: - tmp = SLJIT_R3; - break; - } -#else /* !_WIN64 */ - switch (word_arg_count + float_arg_count) { - case 0: - tmp = SLJIT_R3; - break; - case 1: - tmp = SLJIT_R1; - break; - case 2: - tmp = SLJIT_R2; - break; - default: - tmp = TMP_REG1; - break; - } -#endif /* _WIN64 */ - if (arg_types & SLJIT_ARG_TYPE_SCRATCH_REG) { - if (tmp != SLJIT_R0 + word_arg_count) - EMIT_MOV(compiler, SLJIT_R0 + word_arg_count, 0, tmp, 0); - } else { - EMIT_MOV(compiler, SLJIT_S0 - saved_arg_count, 0, tmp, 0); - saved_arg_count++; - } - word_arg_count++; - } else { -#ifdef _WIN64 - SLJIT_COMPILE_ASSERT(SLJIT_FR0 == 1, float_register_index_start); - float_arg_count++; - if (float_arg_count != float_arg_count + word_arg_count) - FAIL_IF(emit_sse2_load(compiler, (arg_types & SLJIT_ARG_MASK) == SLJIT_ARG_TYPE_F32, - float_arg_count, float_arg_count + word_arg_count, 0)); -#endif /* _WIN64 */ - } - arg_types >>= SLJIT_ARG_SHIFT; - } - - local_size = ((local_size + saved_regs_size + 0xf) & ~0xf) - saved_regs_size; - compiler->local_size = local_size; - -#ifdef _WIN64 - if (local_size > 0) { - if (local_size <= 4 * 4096) { - if (local_size > 4096) - EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_MEM1(SLJIT_SP), -4096); - if (local_size > 2 * 4096) - EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_MEM1(SLJIT_SP), -4096 * 2); - if (local_size > 3 * 4096) - EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_MEM1(SLJIT_SP), -4096 * 3); - } - else { - EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_IMM, local_size >> 12); - - EMIT_MOV(compiler, TMP_REG2, 0, SLJIT_MEM1(SLJIT_SP), -4096); - BINARY_IMM32(SUB, 4096, SLJIT_SP, 0); - BINARY_IMM32(SUB, 1, TMP_REG1, 0); - - inst = (sljit_u8*)ensure_buf(compiler, 1 + 2); - FAIL_IF(!inst); - - INC_SIZE(2); - inst[0] = JNE_i8; - inst[1] = (sljit_u8)-21; - local_size &= 0xfff; - } - - if (local_size > 0) - EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_MEM1(SLJIT_SP), -local_size); - } -#endif /* _WIN64 */ - - if (local_size > 0) - BINARY_IMM32(SUB, local_size, SLJIT_SP, 0); - -#ifdef _WIN64 - if (saved_float_regs_size > 0) { - compiler->mode32 = 1; - - tmp = SLJIT_FS0 - fsaveds; - for (i = SLJIT_FS0; i > tmp; i--) { - inst = emit_x86_instruction(compiler, 2 | EX86_SSE2, i, 0, SLJIT_MEM1(SLJIT_SP), saved_float_regs_offset); - *inst++ = GROUP_0F; - *inst = MOVAPS_xm_x; - saved_float_regs_offset += 16; - } - - for (i = fscratches; i >= SLJIT_FIRST_SAVED_FLOAT_REG; i--) { - inst = emit_x86_instruction(compiler, 2 | EX86_SSE2, i, 0, SLJIT_MEM1(SLJIT_SP), saved_float_regs_offset); - *inst++ = GROUP_0F; - *inst = MOVAPS_xm_x; - saved_float_regs_offset += 16; - } - } -#endif /* _WIN64 */ - - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(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) -{ - sljit_s32 saved_regs_size; -#ifdef _WIN64 - sljit_s32 saved_float_regs_size; -#endif /* _WIN64 */ - - CHECK_ERROR(); - CHECK(check_sljit_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size)); - set_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size); - -#ifdef _WIN64 - local_size += SLJIT_LOCALS_OFFSET; - saved_float_regs_size = GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, 16); - - if (saved_float_regs_size > 0) - local_size = ((local_size + 0xf) & ~0xf) + saved_float_regs_size; -#else /* !_WIN64 */ - SLJIT_ASSERT(SLJIT_LOCALS_OFFSET == 0); -#endif /* _WIN64 */ - - /* Including the return address saved by the call instruction. */ - saved_regs_size = GET_SAVED_REGISTERS_SIZE(scratches, saveds - SLJIT_KEPT_SAVEDS_COUNT(options), 1); - compiler->local_size = ((local_size + saved_regs_size + 0xf) & ~0xf) - saved_regs_size; - return SLJIT_SUCCESS; -} - -static sljit_s32 emit_stack_frame_release(struct sljit_compiler *compiler, sljit_s32 is_return_to) -{ - sljit_uw size; - sljit_s32 local_size, i, tmp; - sljit_u8 *inst; -#ifdef _WIN64 - sljit_s32 saved_float_regs_offset; - sljit_s32 fscratches = compiler->fscratches; - sljit_s32 fsaveds = compiler->fsaveds; -#endif /* _WIN64 */ - -#ifdef _WIN64 - saved_float_regs_offset = GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, 16); - - if (saved_float_regs_offset > 0) { - compiler->mode32 = 1; - saved_float_regs_offset = (compiler->local_size - saved_float_regs_offset) & ~0xf; - - tmp = SLJIT_FS0 - fsaveds; - for (i = SLJIT_FS0; i > tmp; i--) { - inst = emit_x86_instruction(compiler, 2 | EX86_SSE2, i, 0, SLJIT_MEM1(SLJIT_SP), saved_float_regs_offset); - *inst++ = GROUP_0F; - *inst = MOVAPS_x_xm; - saved_float_regs_offset += 16; - } - - for (i = fscratches; i >= SLJIT_FIRST_SAVED_FLOAT_REG; i--) { - inst = emit_x86_instruction(compiler, 2 | EX86_SSE2, i, 0, SLJIT_MEM1(SLJIT_SP), saved_float_regs_offset); - *inst++ = GROUP_0F; - *inst = MOVAPS_x_xm; - saved_float_regs_offset += 16; - } - - compiler->mode32 = 0; - } -#endif /* _WIN64 */ - - local_size = compiler->local_size; - - if (is_return_to && compiler->scratches < SLJIT_FIRST_SAVED_REG && (compiler->saveds == SLJIT_KEPT_SAVEDS_COUNT(compiler->options))) { - local_size += SSIZE_OF(sw); - is_return_to = 0; - } - - if (local_size > 0) - BINARY_IMM32(ADD, local_size, SLJIT_SP, 0); - - tmp = compiler->scratches; - for (i = SLJIT_FIRST_SAVED_REG; i <= tmp; i++) { - size = reg_map[i] >= 8 ? 2 : 1; - inst = (sljit_u8*)ensure_buf(compiler, 1 + size); - FAIL_IF(!inst); - INC_SIZE(size); - if (reg_map[i] >= 8) - *inst++ = REX_B; - POP_REG(reg_lmap[i]); - } - - tmp = SLJIT_S0 - SLJIT_KEPT_SAVEDS_COUNT(compiler->options); - for (i = SLJIT_S0 + 1 - compiler->saveds; i <= tmp; i++) { - size = reg_map[i] >= 8 ? 2 : 1; - inst = (sljit_u8*)ensure_buf(compiler, 1 + size); - FAIL_IF(!inst); - INC_SIZE(size); - if (reg_map[i] >= 8) - *inst++ = REX_B; - POP_REG(reg_lmap[i]); - } - - if (is_return_to) - BINARY_IMM32(ADD, sizeof(sljit_sw), SLJIT_SP, 0); - - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_void(struct sljit_compiler *compiler) -{ - sljit_u8 *inst; - - CHECK_ERROR(); - CHECK(check_sljit_emit_return_void(compiler)); - - compiler->mode32 = 0; - - FAIL_IF(emit_stack_frame_release(compiler, 0)); - - inst = (sljit_u8*)ensure_buf(compiler, 1 + 1); - FAIL_IF(!inst); - INC_SIZE(1); - RET(); - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_to(struct sljit_compiler *compiler, - sljit_s32 src, sljit_sw srcw) -{ - CHECK_ERROR(); - CHECK(check_sljit_emit_return_to(compiler, src, srcw)); - - compiler->mode32 = 0; - - if ((src & SLJIT_MEM) || (src >= SLJIT_FIRST_SAVED_REG && src <= (SLJIT_S0 - SLJIT_KEPT_SAVEDS_COUNT(compiler->options)))) { - ADJUST_LOCAL_OFFSET(src, srcw); - - EMIT_MOV(compiler, TMP_REG2, 0, src, srcw); - src = TMP_REG2; - srcw = 0; - } - - FAIL_IF(emit_stack_frame_release(compiler, 1)); - - SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_ijump(compiler, SLJIT_JUMP, src, srcw); -} - -/* --------------------------------------------------------------------- */ -/* Call / return instructions */ -/* --------------------------------------------------------------------- */ - -#ifndef _WIN64 - -static sljit_s32 call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_types, sljit_s32 *src_ptr) -{ - sljit_s32 src = src_ptr ? (*src_ptr) : 0; - sljit_s32 word_arg_count = 0; - - SLJIT_ASSERT(reg_map[SLJIT_R1] == 6 && reg_map[SLJIT_R3] == 1 && reg_map[TMP_REG1] == 2); - SLJIT_ASSERT(!(src & SLJIT_MEM)); - - /* Remove return value. */ - arg_types >>= SLJIT_ARG_SHIFT; - - while (arg_types) { - if ((arg_types & SLJIT_ARG_MASK) < SLJIT_ARG_TYPE_F64) - word_arg_count++; - arg_types >>= SLJIT_ARG_SHIFT; - } - - if (word_arg_count == 0) - return SLJIT_SUCCESS; - - if (word_arg_count >= 3) { - if (src == SLJIT_R2) - *src_ptr = TMP_REG1; - EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_R2, 0); - } - - return emit_mov(compiler, SLJIT_R2, 0, SLJIT_R0, 0); -} - -#else - -static sljit_s32 call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_types, sljit_s32 *src_ptr) -{ - sljit_s32 src = src_ptr ? (*src_ptr) : 0; - sljit_s32 arg_count = 0; - sljit_s32 word_arg_count = 0; - sljit_s32 float_arg_count = 0; - sljit_s32 types = 0; - sljit_s32 data_trandfer = 0; - static sljit_u8 word_arg_regs[5] = { 0, SLJIT_R3, SLJIT_R1, SLJIT_R2, TMP_REG1 }; - - SLJIT_ASSERT(reg_map[SLJIT_R3] == 1 && reg_map[SLJIT_R1] == 2 && reg_map[SLJIT_R2] == 8 && reg_map[TMP_REG1] == 9); - SLJIT_ASSERT(!(src & SLJIT_MEM)); - - arg_types >>= SLJIT_ARG_SHIFT; - - while (arg_types) { - types = (types << SLJIT_ARG_SHIFT) | (arg_types & SLJIT_ARG_MASK); - - switch (arg_types & SLJIT_ARG_MASK) { - case SLJIT_ARG_TYPE_F64: - case SLJIT_ARG_TYPE_F32: - arg_count++; - float_arg_count++; - - if (arg_count != float_arg_count) - data_trandfer = 1; - break; - default: - arg_count++; - word_arg_count++; - - if (arg_count != word_arg_count || arg_count != word_arg_regs[arg_count]) { - data_trandfer = 1; - - if (src == word_arg_regs[arg_count]) { - EMIT_MOV(compiler, TMP_REG2, 0, src, 0); - *src_ptr = TMP_REG2; - } - } - break; - } - - arg_types >>= SLJIT_ARG_SHIFT; - } - - if (!data_trandfer) - return SLJIT_SUCCESS; - - while (types) { - switch (types & SLJIT_ARG_MASK) { - case SLJIT_ARG_TYPE_F64: - if (arg_count != float_arg_count) - FAIL_IF(emit_sse2_load(compiler, 0, arg_count, float_arg_count, 0)); - arg_count--; - float_arg_count--; - break; - case SLJIT_ARG_TYPE_F32: - if (arg_count != float_arg_count) - FAIL_IF(emit_sse2_load(compiler, 1, arg_count, float_arg_count, 0)); - arg_count--; - float_arg_count--; - break; - default: - if (arg_count != word_arg_count || arg_count != word_arg_regs[arg_count]) - EMIT_MOV(compiler, word_arg_regs[arg_count], 0, word_arg_count, 0); - arg_count--; - word_arg_count--; - break; - } - - types >>= SLJIT_ARG_SHIFT; - } - - return SLJIT_SUCCESS; -} - -#endif - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_call(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 arg_types) -{ - CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_call(compiler, type, arg_types)); - - compiler->mode32 = 0; - - if ((type & 0xff) != SLJIT_CALL_REG_ARG) - PTR_FAIL_IF(call_with_args(compiler, arg_types, NULL)); - - if (type & SLJIT_CALL_RETURN) { - PTR_FAIL_IF(emit_stack_frame_release(compiler, 0)); - type = SLJIT_JUMP | (type & SLJIT_REWRITABLE_JUMP); - } - - SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_jump(compiler, type); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 arg_types, - sljit_s32 src, sljit_sw srcw) -{ - CHECK_ERROR(); - CHECK(check_sljit_emit_icall(compiler, type, arg_types, src, srcw)); - - compiler->mode32 = 0; - - if (src & SLJIT_MEM) { - ADJUST_LOCAL_OFFSET(src, srcw); - EMIT_MOV(compiler, TMP_REG2, 0, src, srcw); - src = TMP_REG2; - } - - if (type & SLJIT_CALL_RETURN) { - if (src >= SLJIT_FIRST_SAVED_REG && src <= (SLJIT_S0 - SLJIT_KEPT_SAVEDS_COUNT(compiler->options))) { - EMIT_MOV(compiler, TMP_REG2, 0, src, srcw); - src = TMP_REG2; - } - - FAIL_IF(emit_stack_frame_release(compiler, 0)); - } - - if ((type & 0xff) != SLJIT_CALL_REG_ARG) - FAIL_IF(call_with_args(compiler, arg_types, &src)); - - if (type & SLJIT_CALL_RETURN) - type = SLJIT_JUMP; - - SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_ijump(compiler, type, src, srcw); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw) -{ - sljit_u8 *inst; - - CHECK_ERROR(); - CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw)); - ADJUST_LOCAL_OFFSET(dst, dstw); - - if (FAST_IS_REG(dst)) { - if (reg_map[dst] < 8) { - inst = (sljit_u8*)ensure_buf(compiler, 1 + 1); - FAIL_IF(!inst); - INC_SIZE(1); - POP_REG(reg_lmap[dst]); - return SLJIT_SUCCESS; - } - - inst = (sljit_u8*)ensure_buf(compiler, 1 + 2); - FAIL_IF(!inst); - INC_SIZE(2); - *inst++ = REX_B; - POP_REG(reg_lmap[dst]); - return SLJIT_SUCCESS; - } - - /* REX_W is not necessary (src is not immediate). */ - compiler->mode32 = 1; - inst = emit_x86_instruction(compiler, 1, 0, 0, dst, dstw); - FAIL_IF(!inst); - *inst++ = POP_rm; - return SLJIT_SUCCESS; -} - -static sljit_s32 emit_fast_return(struct sljit_compiler *compiler, sljit_s32 src, sljit_sw srcw) -{ - sljit_u8 *inst; - - if (FAST_IS_REG(src)) { - if (reg_map[src] < 8) { - inst = (sljit_u8*)ensure_buf(compiler, 1 + 1 + 1); - FAIL_IF(!inst); - - INC_SIZE(1 + 1); - PUSH_REG(reg_lmap[src]); - } - else { - inst = (sljit_u8*)ensure_buf(compiler, 1 + 2 + 1); - FAIL_IF(!inst); - - INC_SIZE(2 + 1); - *inst++ = REX_B; - PUSH_REG(reg_lmap[src]); - } - } - else { - /* REX_W is not necessary (src is not immediate). */ - compiler->mode32 = 1; - inst = emit_x86_instruction(compiler, 1, 0, 0, src, srcw); - FAIL_IF(!inst); - *inst++ = GROUP_FF; - *inst |= PUSH_rm; - - inst = (sljit_u8*)ensure_buf(compiler, 1 + 1); - FAIL_IF(!inst); - INC_SIZE(1); - } - - RET(); - return SLJIT_SUCCESS; -} - -/* --------------------------------------------------------------------- */ -/* Other operations */ -/* --------------------------------------------------------------------- */ - -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) -{ - sljit_u8* inst; - sljit_s32 i, next, reg_idx; - sljit_u8 regs[2]; - - CHECK_ERROR(); - CHECK(check_sljit_emit_mem(compiler, type, reg, mem, memw)); - - if (!(reg & REG_PAIR_MASK)) - return sljit_emit_mem_unaligned(compiler, type, reg, mem, memw); - - ADJUST_LOCAL_OFFSET(mem, memw); - - compiler->mode32 = 0; - - if ((mem & REG_MASK) == 0) { - EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_IMM, memw); - - mem = SLJIT_MEM1(TMP_REG1); - memw = 0; - } else if (!(mem & OFFS_REG_MASK) && ((memw < HALFWORD_MIN) || (memw > HALFWORD_MAX - SSIZE_OF(sw)))) { - EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_IMM, memw); - - mem = SLJIT_MEM2(mem & REG_MASK, TMP_REG1); - memw = 0; - } - - regs[0] = U8(REG_PAIR_FIRST(reg)); - regs[1] = U8(REG_PAIR_SECOND(reg)); - - next = SSIZE_OF(sw); - - if (!(type & SLJIT_MEM_STORE) && (regs[0] == (mem & REG_MASK) || regs[0] == OFFS_REG(mem))) { - if (regs[1] == (mem & REG_MASK) || regs[1] == OFFS_REG(mem)) { - /* Base and offset cannot be TMP_REG1. */ - EMIT_MOV(compiler, TMP_REG1, 0, OFFS_REG(mem), 0); - - if (regs[1] == OFFS_REG(mem)) - next = -SSIZE_OF(sw); - - mem = (mem & ~OFFS_REG_MASK) | TO_OFFS_REG(TMP_REG1); - } else { - next = -SSIZE_OF(sw); - - if (!(mem & OFFS_REG_MASK)) - memw += SSIZE_OF(sw); - } - } - - for (i = 0; i < 2; i++) { - reg_idx = next > 0 ? i : (i ^ 0x1); - reg = regs[reg_idx]; - - if ((mem & OFFS_REG_MASK) && (reg_idx == 1)) { - inst = (sljit_u8*)ensure_buf(compiler, (sljit_uw)(1 + 5)); - FAIL_IF(!inst); - - INC_SIZE(5); - - inst[0] = U8(REX_W | ((reg_map[reg] >= 8) ? REX_R : 0) | ((reg_map[mem & REG_MASK] >= 8) ? REX_B : 0) | ((reg_map[OFFS_REG(mem)] >= 8) ? REX_X : 0)); - inst[1] = (type & SLJIT_MEM_STORE) ? MOV_rm_r : MOV_r_rm; - inst[2] = 0x44 | U8(reg_lmap[reg] << 3); - inst[3] = U8(memw << 6) | U8(reg_lmap[OFFS_REG(mem)] << 3) | reg_lmap[mem & REG_MASK]; - inst[4] = sizeof(sljit_sw); - } else if (type & SLJIT_MEM_STORE) { - EMIT_MOV(compiler, mem, memw, reg, 0); - } else { - EMIT_MOV(compiler, reg, 0, mem, memw); - } - - if (!(mem & OFFS_REG_MASK)) - memw += next; - } - - return SLJIT_SUCCESS; -} - -static sljit_s32 emit_mov_int(struct sljit_compiler *compiler, sljit_s32 sign, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src, sljit_sw srcw) -{ - sljit_u8* inst; - sljit_s32 dst_r; - - compiler->mode32 = 0; - - if (src & SLJIT_IMM) { - if (FAST_IS_REG(dst)) { - if (sign || ((sljit_uw)srcw <= 0x7fffffff)) { - inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, (sljit_sw)(sljit_s32)srcw, dst, dstw); - FAIL_IF(!inst); - *inst = MOV_rm_i32; - return SLJIT_SUCCESS; - } - return emit_load_imm64(compiler, dst, srcw); - } - compiler->mode32 = 1; - inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, (sljit_sw)(sljit_s32)srcw, dst, dstw); - FAIL_IF(!inst); - *inst = MOV_rm_i32; - compiler->mode32 = 0; - return SLJIT_SUCCESS; - } - - dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1; - - if ((dst & SLJIT_MEM) && FAST_IS_REG(src)) - dst_r = src; - else { - if (sign) { - inst = emit_x86_instruction(compiler, 1, dst_r, 0, src, srcw); - FAIL_IF(!inst); - *inst++ = MOVSXD_r_rm; - } else { - compiler->mode32 = 1; - FAIL_IF(emit_mov(compiler, dst_r, 0, src, srcw)); - compiler->mode32 = 0; - } - } - - if (dst & SLJIT_MEM) { - compiler->mode32 = 1; - inst = emit_x86_instruction(compiler, 1, dst_r, 0, dst, dstw); - FAIL_IF(!inst); - *inst = MOV_rm_r; - compiler->mode32 = 0; - } - - return SLJIT_SUCCESS; -} - -static sljit_s32 skip_frames_before_return(struct sljit_compiler *compiler) -{ - sljit_s32 tmp, size; - - /* Don't adjust shadow stack if it isn't enabled. */ - if (!cpu_has_shadow_stack()) - return SLJIT_SUCCESS; - - size = compiler->local_size; - tmp = compiler->scratches; - if (tmp >= SLJIT_FIRST_SAVED_REG) - size += (tmp - SLJIT_FIRST_SAVED_REG + 1) * SSIZE_OF(sw); - tmp = compiler->saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? (SLJIT_S0 + 1 - compiler->saveds) : SLJIT_FIRST_SAVED_REG; - if (SLJIT_S0 >= tmp) - size += (SLJIT_S0 - tmp + 1) * SSIZE_OF(sw); - - return adjust_shadow_stack(compiler, SLJIT_MEM1(SLJIT_SP), size); -} diff --git a/modules/regex/pcre2/src/sljit/sljitNativeX86_common.c b/modules/regex/pcre2/src/sljit/sljitNativeX86_common.c deleted file mode 100644 index 651942b..0000000 --- a/modules/regex/pcre2/src/sljit/sljitNativeX86_common.c +++ /dev/null @@ -1,3422 +0,0 @@ -/* - * 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 const char* sljit_get_platform_name(void) -{ - return "x86" SLJIT_CPUINFO; -} - -/* - 32b register indexes: - 0 - EAX - 1 - ECX - 2 - EDX - 3 - EBX - 4 - ESP - 5 - EBP - 6 - ESI - 7 - EDI -*/ - -/* - 64b register indexes: - 0 - RAX - 1 - RCX - 2 - RDX - 3 - RBX - 4 - RSP - 5 - RBP - 6 - RSI - 7 - RDI - 8 - R8 - From now on REX prefix is required - 9 - R9 - 10 - R10 - 11 - R11 - 12 - R12 - 13 - R13 - 14 - R14 - 15 - R15 -*/ - -#define TMP_FREG (0) - -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - -/* Last register + 1. */ -#define TMP_REG1 (SLJIT_NUMBER_OF_REGISTERS + 2) - -static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 3] = { - 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 7, 6, 3, 4, 5 -}; - -#define CHECK_EXTRA_REGS(p, w, do) \ - if (p >= SLJIT_R3 && p <= SLJIT_S3) { \ - w = (2 * SSIZE_OF(sw)) + ((p) - SLJIT_R3) * SSIZE_OF(sw); \ - p = SLJIT_MEM1(SLJIT_SP); \ - do; \ - } - -#else /* SLJIT_CONFIG_X86_32 */ - -/* Last register + 1. */ -#define TMP_REG1 (SLJIT_NUMBER_OF_REGISTERS + 2) -#define TMP_REG2 (SLJIT_NUMBER_OF_REGISTERS + 3) - -/* Note: r12 & 0x7 == 0b100, which decoded as SIB byte present - Note: avoid to use r12 and r13 for memory addessing - therefore r12 is better to be a higher saved register. */ -#ifndef _WIN64 -/* Args: rdi(=7), rsi(=6), rdx(=2), rcx(=1), r8, r9. Scratches: rax(=0), r10, r11 */ -static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 4] = { - 0, 0, 6, 7, 1, 8, 11, 10, 12, 5, 13, 14, 15, 3, 4, 2, 9 -}; -/* low-map. reg_map & 0x7. */ -static const sljit_u8 reg_lmap[SLJIT_NUMBER_OF_REGISTERS + 4] = { - 0, 0, 6, 7, 1, 0, 3, 2, 4, 5, 5, 6, 7, 3, 4, 2, 1 -}; -#else -/* Args: rcx(=1), rdx(=2), r8, r9. Scratches: rax(=0), r10, r11 */ -static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 4] = { - 0, 0, 2, 8, 1, 11, 12, 5, 13, 14, 15, 7, 6, 3, 4, 9, 10 -}; -/* low-map. reg_map & 0x7. */ -static const sljit_u8 reg_lmap[SLJIT_NUMBER_OF_REGISTERS + 4] = { - 0, 0, 2, 0, 1, 3, 4, 5, 5, 6, 7, 7, 6, 3, 4, 1, 2 -}; -#endif - -/* Args: xmm0-xmm3 */ -static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1] = { - 4, 0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 -}; -/* low-map. freg_map & 0x7. */ -static const sljit_u8 freg_lmap[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1] = { - 4, 0, 1, 2, 3, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7 -}; - -#define REX_W 0x48 -#define REX_R 0x44 -#define REX_X 0x42 -#define REX_B 0x41 -#define REX 0x40 - -#ifndef _WIN64 -#define HALFWORD_MAX 0x7fffffffl -#define HALFWORD_MIN -0x80000000l -#else -#define HALFWORD_MAX 0x7fffffffll -#define HALFWORD_MIN -0x80000000ll -#endif - -#define IS_HALFWORD(x) ((x) <= HALFWORD_MAX && (x) >= HALFWORD_MIN) -#define NOT_HALFWORD(x) ((x) > HALFWORD_MAX || (x) < HALFWORD_MIN) - -#define CHECK_EXTRA_REGS(p, w, do) - -#endif /* SLJIT_CONFIG_X86_32 */ - -#define U8(v) ((sljit_u8)(v)) - - -/* Size flags for emit_x86_instruction: */ -#define EX86_BIN_INS 0x0010 -#define EX86_SHIFT_INS 0x0020 -#define EX86_REX 0x0040 -#define EX86_NO_REXW 0x0080 -#define EX86_BYTE_ARG 0x0100 -#define EX86_HALF_ARG 0x0200 -#define EX86_PREF_66 0x0400 -#define EX86_PREF_F2 0x0800 -#define EX86_PREF_F3 0x1000 -#define EX86_SSE2_OP1 0x2000 -#define EX86_SSE2_OP2 0x4000 -#define EX86_SSE2 (EX86_SSE2_OP1 | EX86_SSE2_OP2) - -/* --------------------------------------------------------------------- */ -/* Instrucion forms */ -/* --------------------------------------------------------------------- */ - -#define ADD (/* BINARY */ 0 << 3) -#define ADD_EAX_i32 0x05 -#define ADD_r_rm 0x03 -#define ADD_rm_r 0x01 -#define ADDSD_x_xm 0x58 -#define ADC (/* BINARY */ 2 << 3) -#define ADC_EAX_i32 0x15 -#define ADC_r_rm 0x13 -#define ADC_rm_r 0x11 -#define AND (/* BINARY */ 4 << 3) -#define AND_EAX_i32 0x25 -#define AND_r_rm 0x23 -#define AND_rm_r 0x21 -#define ANDPD_x_xm 0x54 -#define BSR_r_rm (/* GROUP_0F */ 0xbd) -#define BSF_r_rm (/* GROUP_0F */ 0xbc) -#define CALL_i32 0xe8 -#define CALL_rm (/* GROUP_FF */ 2 << 3) -#define CDQ 0x99 -#define CMOVE_r_rm (/* GROUP_0F */ 0x44) -#define CMP (/* BINARY */ 7 << 3) -#define CMP_EAX_i32 0x3d -#define CMP_r_rm 0x3b -#define CMP_rm_r 0x39 -#define CVTPD2PS_x_xm 0x5a -#define CVTSI2SD_x_rm 0x2a -#define CVTTSD2SI_r_xm 0x2c -#define DIV (/* GROUP_F7 */ 6 << 3) -#define DIVSD_x_xm 0x5e -#define FLDS 0xd9 -#define FLDL 0xdd -#define FSTPS 0xd9 -#define FSTPD 0xdd -#define INT3 0xcc -#define IDIV (/* GROUP_F7 */ 7 << 3) -#define IMUL (/* GROUP_F7 */ 5 << 3) -#define IMUL_r_rm (/* GROUP_0F */ 0xaf) -#define IMUL_r_rm_i8 0x6b -#define IMUL_r_rm_i32 0x69 -#define JE_i8 0x74 -#define JNE_i8 0x75 -#define JMP_i8 0xeb -#define JMP_i32 0xe9 -#define JMP_rm (/* GROUP_FF */ 4 << 3) -#define LEA_r_m 0x8d -#define LOOP_i8 0xe2 -#define LZCNT_r_rm (/* GROUP_F3 */ /* GROUP_0F */ 0xbd) -#define MOV_r_rm 0x8b -#define MOV_r_i32 0xb8 -#define MOV_rm_r 0x89 -#define MOV_rm_i32 0xc7 -#define MOV_rm8_i8 0xc6 -#define MOV_rm8_r8 0x88 -#define MOVAPS_x_xm 0x28 -#define MOVAPS_xm_x 0x29 -#define MOVSD_x_xm 0x10 -#define MOVSD_xm_x 0x11 -#define MOVSXD_r_rm 0x63 -#define MOVSX_r_rm8 (/* GROUP_0F */ 0xbe) -#define MOVSX_r_rm16 (/* GROUP_0F */ 0xbf) -#define MOVZX_r_rm8 (/* GROUP_0F */ 0xb6) -#define MOVZX_r_rm16 (/* GROUP_0F */ 0xb7) -#define MUL (/* GROUP_F7 */ 4 << 3) -#define MULSD_x_xm 0x59 -#define NEG_rm (/* GROUP_F7 */ 3 << 3) -#define NOP 0x90 -#define NOT_rm (/* GROUP_F7 */ 2 << 3) -#define OR (/* BINARY */ 1 << 3) -#define OR_r_rm 0x0b -#define OR_EAX_i32 0x0d -#define OR_rm_r 0x09 -#define OR_rm8_r8 0x08 -#define POP_r 0x58 -#define POP_rm 0x8f -#define POPF 0x9d -#define PREFETCH 0x18 -#define PUSH_i32 0x68 -#define PUSH_r 0x50 -#define PUSH_rm (/* GROUP_FF */ 6 << 3) -#define PUSHF 0x9c -#define ROL (/* SHIFT */ 0 << 3) -#define ROR (/* SHIFT */ 1 << 3) -#define RET_near 0xc3 -#define RET_i16 0xc2 -#define SBB (/* BINARY */ 3 << 3) -#define SBB_EAX_i32 0x1d -#define SBB_r_rm 0x1b -#define SBB_rm_r 0x19 -#define SAR (/* SHIFT */ 7 << 3) -#define SHL (/* SHIFT */ 4 << 3) -#define SHLD (/* GROUP_0F */ 0xa5) -#define SHRD (/* GROUP_0F */ 0xad) -#define SHR (/* SHIFT */ 5 << 3) -#define SUB (/* BINARY */ 5 << 3) -#define SUB_EAX_i32 0x2d -#define SUB_r_rm 0x2b -#define SUB_rm_r 0x29 -#define SUBSD_x_xm 0x5c -#define TEST_EAX_i32 0xa9 -#define TEST_rm_r 0x85 -#define TZCNT_r_rm (/* GROUP_F3 */ /* GROUP_0F */ 0xbc) -#define UCOMISD_x_xm 0x2e -#define UNPCKLPD_x_xm 0x14 -#define XCHG_EAX_r 0x90 -#define XCHG_r_rm 0x87 -#define XOR (/* BINARY */ 6 << 3) -#define XOR_EAX_i32 0x35 -#define XOR_r_rm 0x33 -#define XOR_rm_r 0x31 -#define XORPD_x_xm 0x57 - -#define GROUP_0F 0x0f -#define GROUP_F3 0xf3 -#define GROUP_F7 0xf7 -#define GROUP_FF 0xff -#define GROUP_BINARY_81 0x81 -#define GROUP_BINARY_83 0x83 -#define GROUP_SHIFT_1 0xd1 -#define GROUP_SHIFT_N 0xc1 -#define GROUP_SHIFT_CL 0xd3 - -#define MOD_REG 0xc0 -#define MOD_DISP8 0x40 - -#define INC_SIZE(s) (*inst++ = U8(s), compiler->size += (s)) - -#define PUSH_REG(r) (*inst++ = U8(PUSH_r + (r))) -#define POP_REG(r) (*inst++ = U8(POP_r + (r))) -#define RET() (*inst++ = RET_near) -#define RET_I16(n) (*inst++ = RET_i16, *inst++ = U8(n), *inst++ = 0) - -/* 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. */ -#define CPU_FEATURE_DETECTED 0x001 -#if (defined SLJIT_DETECT_SSE2 && SLJIT_DETECT_SSE2) -#define CPU_FEATURE_SSE2 0x002 -#endif -#define CPU_FEATURE_LZCNT 0x004 -#define CPU_FEATURE_TZCNT 0x008 -#define CPU_FEATURE_CMOV 0x010 - -static sljit_u32 cpu_feature_list = 0; - -#ifdef _WIN32_WCE -#include -#elif defined(_MSC_VER) && _MSC_VER >= 1400 -#include -#endif - -/******************************************************/ -/* Unaligned-store functions */ -/******************************************************/ - -static SLJIT_INLINE void sljit_unaligned_store_s16(void *addr, sljit_s16 value) -{ - SLJIT_MEMCPY(addr, &value, sizeof(value)); -} - -static SLJIT_INLINE void sljit_unaligned_store_s32(void *addr, sljit_s32 value) -{ - SLJIT_MEMCPY(addr, &value, sizeof(value)); -} - -static SLJIT_INLINE void sljit_unaligned_store_sw(void *addr, sljit_sw value) -{ - SLJIT_MEMCPY(addr, &value, sizeof(value)); -} - -/******************************************************/ -/* Utility functions */ -/******************************************************/ - -static void get_cpu_features(void) -{ - sljit_u32 feature_list = CPU_FEATURE_DETECTED; - sljit_u32 value; - -#if defined(_MSC_VER) && _MSC_VER >= 1400 - - int CPUInfo[4]; - - __cpuid(CPUInfo, 0); - if (CPUInfo[0] >= 7) { - __cpuidex(CPUInfo, 7, 0); - if (CPUInfo[1] & 0x8) - feature_list |= CPU_FEATURE_TZCNT; - } - - __cpuid(CPUInfo, (int)0x80000001); - if (CPUInfo[2] & 0x20) - feature_list |= CPU_FEATURE_LZCNT; - - __cpuid(CPUInfo, 1); - value = (sljit_u32)CPUInfo[3]; - -#elif defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_C) - - /* AT&T syntax. */ - __asm__ ( - "movl $0x0, %%eax\n" - "lzcnt %%eax, %%eax\n" - "setnz %%al\n" - "movl %%eax, %0\n" - : "=g" (value) - : -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - : "eax" -#else - : "rax" -#endif - ); - - if (value & 0x1) - feature_list |= CPU_FEATURE_LZCNT; - - __asm__ ( - "movl $0x0, %%eax\n" - "tzcnt %%eax, %%eax\n" - "setnz %%al\n" - "movl %%eax, %0\n" - : "=g" (value) - : -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - : "eax" -#else - : "rax" -#endif - ); - - if (value & 0x1) - feature_list |= CPU_FEATURE_TZCNT; - - __asm__ ( - "movl $0x1, %%eax\n" -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - /* On x86-32, there is no red zone, so this - should work (no need for a local variable). */ - "push %%ebx\n" -#endif - "cpuid\n" -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - "pop %%ebx\n" -#endif - "movl %%edx, %0\n" - : "=g" (value) - : -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - : "%eax", "%ecx", "%edx" -#else - : "%rax", "%rbx", "%rcx", "%rdx" -#endif - ); - -#else /* _MSC_VER && _MSC_VER >= 1400 */ - - /* Intel syntax. */ - __asm { - mov eax, 0 - lzcnt eax, eax - setnz al - mov value, eax - } - - if (value & 0x1) - feature_list |= CPU_FEATURE_LZCNT; - - __asm { - mov eax, 0 - tzcnt eax, eax - setnz al - mov value, eax - } - - if (value & 0x1) - feature_list |= CPU_FEATURE_TZCNT; - - __asm { - mov eax, 1 - cpuid - mov value, edx - } - -#endif /* _MSC_VER && _MSC_VER >= 1400 */ - -#if (defined SLJIT_DETECT_SSE2 && SLJIT_DETECT_SSE2) - if (value & 0x4000000) - feature_list |= CPU_FEATURE_SSE2; -#endif - if (value & 0x8000) - feature_list |= CPU_FEATURE_CMOV; - - cpu_feature_list = feature_list; -} - -static sljit_u8 get_jump_code(sljit_uw type) -{ - switch (type) { - case SLJIT_EQUAL: - case SLJIT_F_EQUAL: - case SLJIT_UNORDERED_OR_EQUAL: - case SLJIT_ORDERED_EQUAL: /* Not supported. */ - return 0x84 /* je */; - - case SLJIT_NOT_EQUAL: - case SLJIT_F_NOT_EQUAL: - case SLJIT_ORDERED_NOT_EQUAL: - case SLJIT_UNORDERED_OR_NOT_EQUAL: /* Not supported. */ - return 0x85 /* jne */; - - case SLJIT_LESS: - case SLJIT_CARRY: - case SLJIT_F_LESS: - case SLJIT_UNORDERED_OR_LESS: - case SLJIT_UNORDERED_OR_GREATER: - return 0x82 /* jc */; - - case SLJIT_GREATER_EQUAL: - case SLJIT_NOT_CARRY: - case SLJIT_F_GREATER_EQUAL: - case SLJIT_ORDERED_GREATER_EQUAL: - case SLJIT_ORDERED_LESS_EQUAL: - return 0x83 /* jae */; - - case SLJIT_GREATER: - case SLJIT_F_GREATER: - case SLJIT_ORDERED_LESS: - case SLJIT_ORDERED_GREATER: - return 0x87 /* jnbe */; - - case SLJIT_LESS_EQUAL: - case SLJIT_F_LESS_EQUAL: - case SLJIT_UNORDERED_OR_GREATER_EQUAL: - case SLJIT_UNORDERED_OR_LESS_EQUAL: - return 0x86 /* jbe */; - - case SLJIT_SIG_LESS: - return 0x8c /* jl */; - - case SLJIT_SIG_GREATER_EQUAL: - return 0x8d /* jnl */; - - case SLJIT_SIG_GREATER: - return 0x8f /* jnle */; - - case SLJIT_SIG_LESS_EQUAL: - return 0x8e /* jle */; - - case SLJIT_OVERFLOW: - return 0x80 /* jo */; - - case SLJIT_NOT_OVERFLOW: - return 0x81 /* jno */; - - case SLJIT_UNORDERED: - return 0x8a /* jp */; - - case SLJIT_ORDERED: - return 0x8b /* jpo */; - } - return 0; -} - -#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* generate_near_jump_code(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 - label_addr = jump->u.target - (sljit_uw)executable_offset; - -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - if ((sljit_sw)(label_addr - (jump->addr + 1)) > HALFWORD_MAX || (sljit_sw)(label_addr - (jump->addr + 1)) < HALFWORD_MIN) - return generate_far_jump_code(jump, code_ptr); -#endif - - short_jump = (sljit_sw)(label_addr - (jump->addr + 2)) >= -128 && (sljit_sw)(label_addr - (jump->addr + 2)) <= 127; - - if (type == SLJIT_JUMP) { - if (short_jump) - *code_ptr++ = JMP_i8; - else - *code_ptr++ = JMP_i32; - jump->addr++; - } - else if (type >= SLJIT_FAST_CALL) { - short_jump = 0; - *code_ptr++ = CALL_i32; - jump->addr++; - } - else if (short_jump) { - *code_ptr++ = U8(get_jump_code(type) - 0x10); - jump->addr++; - } - else { - *code_ptr++ = GROUP_0F; - *code_ptr++ = get_jump_code(type); - jump->addr += 2; - } - - if (short_jump) { - jump->flags |= PATCH_MB; - code_ptr += sizeof(sljit_s8); - } else { - jump->flags |= PATCH_MW; - code_ptr += sizeof(sljit_s32); - } - - return code_ptr; -} - -SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler) -{ - struct sljit_memory_fragment *buf; - sljit_u8 *code; - sljit_u8 *code_ptr; - sljit_u8 *buf_ptr; - sljit_u8 *buf_end; - sljit_u8 len; - sljit_sw executable_offset; - sljit_uw jump_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); - - /* Second code generation pass. */ - code = (sljit_u8*)SLJIT_MALLOC_EXEC(compiler->size, compiler->exec_allocator_data); - PTR_FAIL_WITH_EXEC_IF(code); - 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) { - /* 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); - label->size = (sljit_uw)(code_ptr - code); - label = label->next; - break; - case 1: - jump->addr = (sljit_uw)code_ptr; - if (!(jump->flags & SLJIT_REWRITABLE_JUMP)) - code_ptr = generate_near_jump_code(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 - } - jump = jump->next; - break; - case 2: - const_->addr = ((sljit_uw)code_ptr) - sizeof(sljit_sw); - const_ = const_->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; - break; - } - buf_ptr++; - } - } while (buf_ptr < buf_end); - SLJIT_ASSERT(buf_ptr == buf_end); - buf = buf->next; - } while (buf); - - 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 - - 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); - - code = (sljit_u8*)SLJIT_ADD_EXEC_OFFSET(code, executable_offset); - - SLJIT_UPDATE_WX_FLAGS(code, (sljit_u8*)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset), 1); - return (void*)code; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type) -{ - switch (feature_type) { - case SLJIT_HAS_FPU: -#ifdef SLJIT_IS_FPU_AVAILABLE - return SLJIT_IS_FPU_AVAILABLE; -#elif (defined SLJIT_DETECT_SSE2 && SLJIT_DETECT_SSE2) - if (cpu_feature_list == 0) - get_cpu_features(); - return (cpu_feature_list & CPU_FEATURE_SSE2) != 0; -#else /* SLJIT_DETECT_SSE2 */ - return 1; -#endif /* SLJIT_DETECT_SSE2 */ - -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - case SLJIT_HAS_VIRTUAL_REGISTERS: - return 1; -#endif /* SLJIT_CONFIG_X86_32 */ - - case SLJIT_HAS_CLZ: - if (cpu_feature_list == 0) - get_cpu_features(); - - return (cpu_feature_list & CPU_FEATURE_LZCNT) ? 1 : 2; - - case SLJIT_HAS_CTZ: - if (cpu_feature_list == 0) - get_cpu_features(); - - return (cpu_feature_list & CPU_FEATURE_TZCNT) ? 1 : 2; - - case SLJIT_HAS_CMOV: - if (cpu_feature_list == 0) - get_cpu_features(); - return (cpu_feature_list & CPU_FEATURE_CMOV) != 0; - - case SLJIT_HAS_ROT: - case SLJIT_HAS_PREFETCH: - return 1; - - case SLJIT_HAS_SSE2: -#if (defined SLJIT_DETECT_SSE2 && SLJIT_DETECT_SSE2) - if (cpu_feature_list == 0) - get_cpu_features(); - return (cpu_feature_list & CPU_FEATURE_SSE2) != 0; -#else /* !SLJIT_DETECT_SSE2 */ - return 1; -#endif /* SLJIT_DETECT_SSE2 */ - - default: - return 0; - } -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_cmp_info(sljit_s32 type) -{ - if (type < SLJIT_UNORDERED || type > SLJIT_ORDERED_LESS_EQUAL) - return 0; - - switch (type) { - case SLJIT_ORDERED_EQUAL: - case SLJIT_UNORDERED_OR_NOT_EQUAL: - return 0; - } - - return 1; -} - -/* --------------------------------------------------------------------- */ -/* Operators */ -/* --------------------------------------------------------------------- */ - -#define BINARY_OPCODE(opcode) (((opcode ## _EAX_i32) << 24) | ((opcode ## _r_rm) << 16) | ((opcode ## _rm_r) << 8) | (opcode)) - -#define BINARY_IMM32(op_imm, immw, arg, argw) \ - do { \ - inst = emit_x86_instruction(compiler, 1 | EX86_BIN_INS, SLJIT_IMM, immw, arg, argw); \ - FAIL_IF(!inst); \ - *(inst + 1) |= (op_imm); \ - } while (0) - -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - -#define BINARY_IMM(op_imm, op_mr, immw, arg, argw) \ - do { \ - if (IS_HALFWORD(immw) || compiler->mode32) { \ - 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(!inst); \ - *inst = (op_mr); \ - } \ - } while (0) - -#define BINARY_EAX_IMM(op_eax_imm, immw) \ - FAIL_IF(emit_do_imm32(compiler, (!compiler->mode32) ? REX_W : 0, (op_eax_imm), immw)) - -#else /* !SLJIT_CONFIG_X86_64 */ - -#define BINARY_IMM(op_imm, op_mr, immw, arg, argw) \ - BINARY_IMM32(op_imm, immw, arg, argw) - -#define BINARY_EAX_IMM(op_eax_imm, immw) \ - FAIL_IF(emit_do_imm(compiler, (op_eax_imm), immw)) - -#endif /* SLJIT_CONFIG_X86_64 */ - -static sljit_s32 emit_mov(struct sljit_compiler *compiler, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src, sljit_sw srcw); - -#define EMIT_MOV(compiler, dst, dstw, src, srcw) \ - FAIL_IF(emit_mov(compiler, dst, dstw, src, srcw)); - -static SLJIT_INLINE sljit_s32 emit_sse2_store(struct sljit_compiler *compiler, - sljit_s32 single, sljit_s32 dst, sljit_sw dstw, sljit_s32 src); - -static SLJIT_INLINE sljit_s32 emit_sse2_load(struct sljit_compiler *compiler, - sljit_s32 single, sljit_s32 dst, sljit_s32 src, sljit_sw srcw); - -static sljit_s32 emit_cmp_binary(struct sljit_compiler *compiler, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w); - -static SLJIT_INLINE sljit_s32 emit_endbranch(struct sljit_compiler *compiler) -{ -#if (defined SLJIT_CONFIG_X86_CET && SLJIT_CONFIG_X86_CET) - /* Emit endbr32/endbr64 when CET is enabled. */ - sljit_u8 *inst; - inst = (sljit_u8*)ensure_buf(compiler, 1 + 4); - FAIL_IF(!inst); - INC_SIZE(4); - *inst++ = 0xf3; - *inst++ = 0x0f; - *inst++ = 0x1e; -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - *inst = 0xfb; -#else - *inst = 0xfa; -#endif -#else /* !SLJIT_CONFIG_X86_CET */ - SLJIT_UNUSED_ARG(compiler); -#endif /* SLJIT_CONFIG_X86_CET */ - return SLJIT_SUCCESS; -} - -#if (defined SLJIT_CONFIG_X86_CET && SLJIT_CONFIG_X86_CET) && defined (__SHSTK__) - -static SLJIT_INLINE sljit_s32 emit_rdssp(struct sljit_compiler *compiler, sljit_s32 reg) -{ - sljit_u8 *inst; - sljit_s32 size; - -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - size = 5; -#else - size = 4; -#endif - - inst = (sljit_u8*)ensure_buf(compiler, 1 + size); - FAIL_IF(!inst); - INC_SIZE(size); - *inst++ = 0xf3; -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - *inst++ = REX_W | (reg_map[reg] <= 7 ? 0 : REX_B); -#endif - *inst++ = 0x0f; - *inst++ = 0x1e; - *inst = (0x3 << 6) | (0x1 << 3) | (reg_map[reg] & 0x7); - return SLJIT_SUCCESS; -} - -static SLJIT_INLINE sljit_s32 emit_incssp(struct sljit_compiler *compiler, sljit_s32 reg) -{ - sljit_u8 *inst; - sljit_s32 size; - -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - size = 5; -#else - size = 4; -#endif - - inst = (sljit_u8*)ensure_buf(compiler, 1 + size); - FAIL_IF(!inst); - INC_SIZE(size); - *inst++ = 0xf3; -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - *inst++ = REX_W | (reg_map[reg] <= 7 ? 0 : REX_B); -#endif - *inst++ = 0x0f; - *inst++ = 0xae; - *inst = (0x3 << 6) | (0x5 << 3) | (reg_map[reg] & 0x7); - return SLJIT_SUCCESS; -} - -#endif /* SLJIT_CONFIG_X86_CET && __SHSTK__ */ - -static SLJIT_INLINE sljit_s32 cpu_has_shadow_stack(void) -{ -#if (defined SLJIT_CONFIG_X86_CET && SLJIT_CONFIG_X86_CET) && defined (__SHSTK__) - return _get_ssp() != 0; -#else /* !SLJIT_CONFIG_X86_CET || !__SHSTK__ */ - return 0; -#endif /* SLJIT_CONFIG_X86_CET && __SHSTK__ */ -} - -static SLJIT_INLINE sljit_s32 adjust_shadow_stack(struct sljit_compiler *compiler, - sljit_s32 src, sljit_sw srcw) -{ -#if (defined SLJIT_CONFIG_X86_CET && SLJIT_CONFIG_X86_CET) && defined (__SHSTK__) - sljit_u8 *inst, *jz_after_cmp_inst; - sljit_uw size_jz_after_cmp_inst; - - sljit_uw size_before_rdssp_inst = compiler->size; - - /* Generate "RDSSP TMP_REG1". */ - FAIL_IF(emit_rdssp(compiler, TMP_REG1)); - - /* Load return address on shadow stack into TMP_REG1. */ -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - SLJIT_ASSERT(reg_map[TMP_REG1] == 5); - - /* Hand code unsupported "mov 0x0(%ebp),%ebp". */ - inst = (sljit_u8*)ensure_buf(compiler, 1 + 3); - FAIL_IF(!inst); - INC_SIZE(3); - *inst++ = 0x8b; - *inst++ = 0x6d; - *inst = 0; -#else /* !SLJIT_CONFIG_X86_32 */ - EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_MEM1(TMP_REG1), 0); -#endif /* SLJIT_CONFIG_X86_32 */ - - /* Compare return address against TMP_REG1. */ - FAIL_IF(emit_cmp_binary (compiler, TMP_REG1, 0, src, srcw)); - - /* Generate JZ to skip shadow stack ajdustment when shadow - stack matches normal stack. */ - inst = (sljit_u8*)ensure_buf(compiler, 1 + 2); - FAIL_IF(!inst); - INC_SIZE(2); - *inst++ = get_jump_code(SLJIT_EQUAL) - 0x10; - size_jz_after_cmp_inst = compiler->size; - jz_after_cmp_inst = inst; - -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - /* REX_W is not necessary. */ - compiler->mode32 = 1; -#endif - /* Load 1 into TMP_REG1. */ - EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_IMM, 1); - - /* Generate "INCSSP TMP_REG1". */ - FAIL_IF(emit_incssp(compiler, TMP_REG1)); - - /* Jump back to "RDSSP TMP_REG1" to check shadow stack again. */ - inst = (sljit_u8*)ensure_buf(compiler, 1 + 2); - FAIL_IF(!inst); - INC_SIZE(2); - *inst++ = JMP_i8; - *inst = size_before_rdssp_inst - compiler->size; - - *jz_after_cmp_inst = compiler->size - size_jz_after_cmp_inst; -#else /* !SLJIT_CONFIG_X86_CET || !__SHSTK__ */ - SLJIT_UNUSED_ARG(compiler); - SLJIT_UNUSED_ARG(src); - SLJIT_UNUSED_ARG(srcw); -#endif /* SLJIT_CONFIG_X86_CET && __SHSTK__ */ - return SLJIT_SUCCESS; -} - -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) -#include "sljitNativeX86_32.c" -#else -#include "sljitNativeX86_64.c" -#endif - -static sljit_s32 emit_mov(struct sljit_compiler *compiler, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src, sljit_sw srcw) -{ - sljit_u8* inst; - - if (FAST_IS_REG(src)) { - inst = emit_x86_instruction(compiler, 1, src, 0, dst, dstw); - FAIL_IF(!inst); - *inst = MOV_rm_r; - return SLJIT_SUCCESS; - } - if (src & SLJIT_IMM) { - if (FAST_IS_REG(dst)) { -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - return emit_do_imm(compiler, MOV_r_i32 | reg_map[dst], srcw); -#else - if (!compiler->mode32) { - if (NOT_HALFWORD(srcw)) - return emit_load_imm64(compiler, dst, srcw); - } - else - return emit_do_imm32(compiler, (reg_map[dst] >= 8) ? REX_B : 0, U8(MOV_r_i32 | reg_lmap[dst]), srcw); -#endif - } -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - if (!compiler->mode32 && NOT_HALFWORD(srcw)) { - /* Immediate to memory move. Only SLJIT_MOV operation copies - an immediate directly into memory so TMP_REG1 can be used. */ - FAIL_IF(emit_load_imm64(compiler, TMP_REG1, srcw)); - inst = emit_x86_instruction(compiler, 1, TMP_REG1, 0, dst, dstw); - FAIL_IF(!inst); - *inst = MOV_rm_r; - return SLJIT_SUCCESS; - } -#endif - inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, srcw, dst, dstw); - FAIL_IF(!inst); - *inst = MOV_rm_i32; - return SLJIT_SUCCESS; - } - if (FAST_IS_REG(dst)) { - inst = emit_x86_instruction(compiler, 1, dst, 0, src, srcw); - FAIL_IF(!inst); - *inst = MOV_r_rm; - return SLJIT_SUCCESS; - } - - /* Memory to memory move. Only SLJIT_MOV operation copies - data from memory to memory so TMP_REG1 can be used. */ - inst = emit_x86_instruction(compiler, 1, TMP_REG1, 0, src, srcw); - FAIL_IF(!inst); - *inst = MOV_r_rm; - inst = emit_x86_instruction(compiler, 1, TMP_REG1, 0, dst, dstw); - FAIL_IF(!inst); - *inst = MOV_rm_r; - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compiler, sljit_s32 op) -{ - sljit_u8 *inst; -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - sljit_uw size; -#endif - - CHECK_ERROR(); - CHECK(check_sljit_emit_op0(compiler, op)); - - switch (GET_OPCODE(op)) { - case SLJIT_BREAKPOINT: - inst = (sljit_u8*)ensure_buf(compiler, 1 + 1); - FAIL_IF(!inst); - INC_SIZE(1); - *inst = INT3; - break; - case SLJIT_NOP: - inst = (sljit_u8*)ensure_buf(compiler, 1 + 1); - FAIL_IF(!inst); - INC_SIZE(1); - *inst = NOP; - break; - case SLJIT_LMUL_UW: - case SLJIT_LMUL_SW: - case SLJIT_DIVMOD_UW: - case SLJIT_DIVMOD_SW: - case SLJIT_DIV_UW: - case SLJIT_DIV_SW: -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) -#ifdef _WIN64 - SLJIT_ASSERT( - reg_map[SLJIT_R0] == 0 - && reg_map[SLJIT_R1] == 2 - && reg_map[TMP_REG1] > 7); -#else - SLJIT_ASSERT( - reg_map[SLJIT_R0] == 0 - && reg_map[SLJIT_R1] < 7 - && reg_map[TMP_REG1] == 2); -#endif - compiler->mode32 = op & SLJIT_32; -#endif - SLJIT_COMPILE_ASSERT((SLJIT_DIVMOD_UW & 0x2) == 0 && SLJIT_DIV_UW - 0x2 == SLJIT_DIVMOD_UW, bad_div_opcode_assignments); - - op = GET_OPCODE(op); - if ((op | 0x2) == SLJIT_DIV_UW) { -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) || defined(_WIN64) - EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_R1, 0); - inst = emit_x86_instruction(compiler, 1, SLJIT_R1, 0, SLJIT_R1, 0); -#else - inst = emit_x86_instruction(compiler, 1, TMP_REG1, 0, TMP_REG1, 0); -#endif - FAIL_IF(!inst); - *inst = XOR_r_rm; - } - - if ((op | 0x2) == SLJIT_DIV_SW) { -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) || defined(_WIN64) - EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_R1, 0); -#endif - -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - inst = (sljit_u8*)ensure_buf(compiler, 1 + 1); - FAIL_IF(!inst); - INC_SIZE(1); - *inst = CDQ; -#else - if (compiler->mode32) { - inst = (sljit_u8*)ensure_buf(compiler, 1 + 1); - FAIL_IF(!inst); - INC_SIZE(1); - *inst = CDQ; - } else { - inst = (sljit_u8*)ensure_buf(compiler, 1 + 2); - FAIL_IF(!inst); - INC_SIZE(2); - *inst++ = REX_W; - *inst = CDQ; - } -#endif - } - -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - inst = (sljit_u8*)ensure_buf(compiler, 1 + 2); - FAIL_IF(!inst); - INC_SIZE(2); - *inst++ = GROUP_F7; - *inst = MOD_REG | ((op >= SLJIT_DIVMOD_UW) ? reg_map[TMP_REG1] : reg_map[SLJIT_R1]); -#else -#ifdef _WIN64 - size = (!compiler->mode32 || op >= SLJIT_DIVMOD_UW) ? 3 : 2; -#else - size = (!compiler->mode32) ? 3 : 2; -#endif - inst = (sljit_u8*)ensure_buf(compiler, 1 + size); - FAIL_IF(!inst); - INC_SIZE(size); -#ifdef _WIN64 - if (!compiler->mode32) - *inst++ = REX_W | ((op >= SLJIT_DIVMOD_UW) ? REX_B : 0); - else if (op >= SLJIT_DIVMOD_UW) - *inst++ = REX_B; - *inst++ = GROUP_F7; - *inst = MOD_REG | ((op >= SLJIT_DIVMOD_UW) ? reg_lmap[TMP_REG1] : reg_lmap[SLJIT_R1]); -#else - if (!compiler->mode32) - *inst++ = REX_W; - *inst++ = GROUP_F7; - *inst = MOD_REG | reg_map[SLJIT_R1]; -#endif -#endif - switch (op) { - case SLJIT_LMUL_UW: - *inst |= MUL; - break; - case SLJIT_LMUL_SW: - *inst |= IMUL; - break; - case SLJIT_DIVMOD_UW: - case SLJIT_DIV_UW: - *inst |= DIV; - break; - case SLJIT_DIVMOD_SW: - case SLJIT_DIV_SW: - *inst |= IDIV; - break; - } -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) && !defined(_WIN64) - if (op <= SLJIT_DIVMOD_SW) - EMIT_MOV(compiler, SLJIT_R1, 0, TMP_REG1, 0); -#else - if (op >= SLJIT_DIV_UW) - EMIT_MOV(compiler, SLJIT_R1, 0, TMP_REG1, 0); -#endif - break; - case SLJIT_ENDBR: - return emit_endbranch(compiler); - case SLJIT_SKIP_FRAMES_BEFORE_RETURN: - return skip_frames_before_return(compiler); - } - - return SLJIT_SUCCESS; -} - -#define ENCODE_PREFIX(prefix) \ - do { \ - inst = (sljit_u8*)ensure_buf(compiler, 1 + 1); \ - FAIL_IF(!inst); \ - INC_SIZE(1); \ - *inst = U8(prefix); \ - } while (0) - -static sljit_s32 emit_mov_byte(struct sljit_compiler *compiler, sljit_s32 sign, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src, sljit_sw srcw) -{ - sljit_u8* inst; - sljit_s32 dst_r; -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - sljit_s32 work_r; -#endif - -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - compiler->mode32 = 0; -#endif - - if (src & SLJIT_IMM) { - if (FAST_IS_REG(dst)) { -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - return emit_do_imm(compiler, MOV_r_i32 | reg_map[dst], srcw); -#else - inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, srcw, dst, 0); - FAIL_IF(!inst); - *inst = MOV_rm_i32; - return SLJIT_SUCCESS; -#endif - } - inst = emit_x86_instruction(compiler, 1 | EX86_BYTE_ARG | EX86_NO_REXW, SLJIT_IMM, srcw, dst, dstw); - FAIL_IF(!inst); - *inst = MOV_rm8_i8; - return SLJIT_SUCCESS; - } - - dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1; - - if ((dst & SLJIT_MEM) && FAST_IS_REG(src)) { -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - if (reg_map[src] >= 4) { - SLJIT_ASSERT(dst_r == TMP_REG1); - EMIT_MOV(compiler, TMP_REG1, 0, src, 0); - } else - dst_r = src; -#else - dst_r = src; -#endif - } -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - else if (FAST_IS_REG(src) && reg_map[src] >= 4) { - /* src, dst are registers. */ - SLJIT_ASSERT(FAST_IS_REG(dst)); - if (reg_map[dst] < 4) { - if (dst != src) - EMIT_MOV(compiler, dst, 0, src, 0); - inst = emit_x86_instruction(compiler, 2, dst, 0, dst, 0); - FAIL_IF(!inst); - *inst++ = GROUP_0F; - *inst = sign ? MOVSX_r_rm8 : MOVZX_r_rm8; - } - else { - if (dst != src) - EMIT_MOV(compiler, dst, 0, src, 0); - if (sign) { - /* shl reg, 24 */ - inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_IMM, 24, dst, 0); - FAIL_IF(!inst); - *inst |= SHL; - /* sar reg, 24 */ - inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_IMM, 24, dst, 0); - FAIL_IF(!inst); - *inst |= SAR; - } - else { - inst = emit_x86_instruction(compiler, 1 | EX86_BIN_INS, SLJIT_IMM, 0xff, dst, 0); - FAIL_IF(!inst); - *(inst + 1) |= AND; - } - } - return SLJIT_SUCCESS; - } -#endif - else { - /* src can be memory addr or reg_map[src] < 4 on x86_32 architectures. */ - inst = emit_x86_instruction(compiler, 2, dst_r, 0, src, srcw); - FAIL_IF(!inst); - *inst++ = GROUP_0F; - *inst = sign ? MOVSX_r_rm8 : MOVZX_r_rm8; - } - - if (dst & SLJIT_MEM) { -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - if (dst_r == TMP_REG1) { - /* Find a non-used register, whose reg_map[src] < 4. */ - if ((dst & REG_MASK) == SLJIT_R0) { - if ((dst & OFFS_REG_MASK) == TO_OFFS_REG(SLJIT_R1)) - work_r = SLJIT_R2; - else - work_r = SLJIT_R1; - } - else { - if ((dst & OFFS_REG_MASK) != TO_OFFS_REG(SLJIT_R0)) - work_r = SLJIT_R0; - else if ((dst & REG_MASK) == SLJIT_R1) - work_r = SLJIT_R2; - else - work_r = SLJIT_R1; - } - - if (work_r == SLJIT_R0) { - ENCODE_PREFIX(XCHG_EAX_r | reg_map[TMP_REG1]); - } - else { - inst = emit_x86_instruction(compiler, 1, work_r, 0, dst_r, 0); - FAIL_IF(!inst); - *inst = XCHG_r_rm; - } - - inst = emit_x86_instruction(compiler, 1, work_r, 0, dst, dstw); - FAIL_IF(!inst); - *inst = MOV_rm8_r8; - - if (work_r == SLJIT_R0) { - ENCODE_PREFIX(XCHG_EAX_r | reg_map[TMP_REG1]); - } - else { - inst = emit_x86_instruction(compiler, 1, work_r, 0, dst_r, 0); - FAIL_IF(!inst); - *inst = XCHG_r_rm; - } - } - else { - inst = emit_x86_instruction(compiler, 1, dst_r, 0, dst, dstw); - FAIL_IF(!inst); - *inst = MOV_rm8_r8; - } -#else - inst = emit_x86_instruction(compiler, 1 | EX86_REX | EX86_NO_REXW, dst_r, 0, dst, dstw); - FAIL_IF(!inst); - *inst = MOV_rm8_r8; -#endif - } - - return SLJIT_SUCCESS; -} - -static sljit_s32 emit_prefetch(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 src, sljit_sw srcw) -{ - sljit_u8* inst; - -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - compiler->mode32 = 1; -#endif - - inst = emit_x86_instruction(compiler, 2, 0, 0, src, srcw); - FAIL_IF(!inst); - *inst++ = GROUP_0F; - *inst++ = PREFETCH; - - if (op == SLJIT_PREFETCH_L1) - *inst |= (1 << 3); - else if (op == SLJIT_PREFETCH_L2) - *inst |= (2 << 3); - else if (op == SLJIT_PREFETCH_L3) - *inst |= (3 << 3); - - return SLJIT_SUCCESS; -} - -static sljit_s32 emit_mov_half(struct sljit_compiler *compiler, sljit_s32 sign, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src, sljit_sw srcw) -{ - sljit_u8* inst; - sljit_s32 dst_r; - -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - compiler->mode32 = 0; -#endif - - if (src & SLJIT_IMM) { - if (FAST_IS_REG(dst)) { -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - return emit_do_imm(compiler, MOV_r_i32 | reg_map[dst], srcw); -#else - inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, srcw, dst, 0); - FAIL_IF(!inst); - *inst = MOV_rm_i32; - return SLJIT_SUCCESS; -#endif - } - inst = emit_x86_instruction(compiler, 1 | EX86_HALF_ARG | EX86_NO_REXW | EX86_PREF_66, SLJIT_IMM, srcw, dst, dstw); - FAIL_IF(!inst); - *inst = MOV_rm_i32; - return SLJIT_SUCCESS; - } - - dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1; - - if ((dst & SLJIT_MEM) && FAST_IS_REG(src)) - dst_r = src; - else { - inst = emit_x86_instruction(compiler, 2, dst_r, 0, src, srcw); - FAIL_IF(!inst); - *inst++ = GROUP_0F; - *inst = sign ? MOVSX_r_rm16 : MOVZX_r_rm16; - } - - if (dst & SLJIT_MEM) { - inst = emit_x86_instruction(compiler, 1 | EX86_NO_REXW | EX86_PREF_66, dst_r, 0, dst, dstw); - FAIL_IF(!inst); - *inst = MOV_rm_r; - } - - return SLJIT_SUCCESS; -} - -static sljit_s32 emit_unary(struct sljit_compiler *compiler, sljit_u8 opcode, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src, sljit_sw srcw) -{ - sljit_u8* inst; - - if (dst == src && dstw == srcw) { - /* Same input and output */ - inst = emit_x86_instruction(compiler, 1, 0, 0, dst, dstw); - FAIL_IF(!inst); - *inst++ = GROUP_F7; - *inst |= opcode; - return SLJIT_SUCCESS; - } - - if (FAST_IS_REG(dst)) { - EMIT_MOV(compiler, dst, 0, src, srcw); - inst = emit_x86_instruction(compiler, 1, 0, 0, dst, 0); - FAIL_IF(!inst); - *inst++ = GROUP_F7; - *inst |= opcode; - return SLJIT_SUCCESS; - } - - EMIT_MOV(compiler, TMP_REG1, 0, src, srcw); - inst = emit_x86_instruction(compiler, 1, 0, 0, TMP_REG1, 0); - FAIL_IF(!inst); - *inst++ = GROUP_F7; - *inst |= opcode; - EMIT_MOV(compiler, dst, dstw, TMP_REG1, 0); - return SLJIT_SUCCESS; -} - -static sljit_s32 emit_not_with_flags(struct sljit_compiler *compiler, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src, sljit_sw srcw) -{ - sljit_u8* inst; - - if (FAST_IS_REG(dst)) { - EMIT_MOV(compiler, dst, 0, src, srcw); - inst = emit_x86_instruction(compiler, 1, 0, 0, dst, 0); - FAIL_IF(!inst); - *inst++ = GROUP_F7; - *inst |= NOT_rm; - inst = emit_x86_instruction(compiler, 1, dst, 0, dst, 0); - FAIL_IF(!inst); - *inst = OR_r_rm; - return SLJIT_SUCCESS; - } - - EMIT_MOV(compiler, TMP_REG1, 0, src, srcw); - inst = emit_x86_instruction(compiler, 1, 0, 0, TMP_REG1, 0); - FAIL_IF(!inst); - *inst++ = GROUP_F7; - *inst |= NOT_rm; - inst = emit_x86_instruction(compiler, 1, TMP_REG1, 0, TMP_REG1, 0); - FAIL_IF(!inst); - *inst = OR_r_rm; - EMIT_MOV(compiler, dst, dstw, TMP_REG1, 0); - return SLJIT_SUCCESS; -} - -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) -static const sljit_sw emit_clz_arg = 32 + 31; -static const sljit_sw emit_ctz_arg = 32; -#endif - -static sljit_s32 emit_clz_ctz(struct sljit_compiler *compiler, sljit_s32 is_clz, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src, sljit_sw srcw) -{ - sljit_u8* inst; - sljit_s32 dst_r; - sljit_sw max; - - if (cpu_feature_list == 0) - get_cpu_features(); - - dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1; - - if (is_clz ? (cpu_feature_list & CPU_FEATURE_LZCNT) : (cpu_feature_list & CPU_FEATURE_TZCNT)) { - /* Group prefix added separately. */ - inst = (sljit_u8*)ensure_buf(compiler, 1 + 1); - FAIL_IF(!inst); - INC_SIZE(1); - *inst++ = GROUP_F3; - - inst = emit_x86_instruction(compiler, 2, dst_r, 0, src, srcw); - FAIL_IF(!inst); - *inst++ = GROUP_0F; - *inst = is_clz ? LZCNT_r_rm : TZCNT_r_rm; - - if (dst & SLJIT_MEM) - EMIT_MOV(compiler, dst, dstw, TMP_REG1, 0); - return SLJIT_SUCCESS; - } - - inst = emit_x86_instruction(compiler, 2, dst_r, 0, src, srcw); - FAIL_IF(!inst); - *inst++ = GROUP_0F; - *inst = is_clz ? BSR_r_rm : BSF_r_rm; - -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - max = is_clz ? (32 + 31) : 32; - - if (cpu_feature_list & CPU_FEATURE_CMOV) { - if (dst_r != TMP_REG1) { - EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_IMM, max); - inst = emit_x86_instruction(compiler, 2, dst_r, 0, TMP_REG1, 0); - } - else - inst = emit_x86_instruction(compiler, 2, dst_r, 0, SLJIT_MEM0(), is_clz ? (sljit_sw)&emit_clz_arg : (sljit_sw)&emit_ctz_arg); - - FAIL_IF(!inst); - *inst++ = GROUP_0F; - *inst = CMOVE_r_rm; - } - else - FAIL_IF(sljit_emit_cmov_generic(compiler, SLJIT_EQUAL, dst_r, SLJIT_IMM, max)); - - if (is_clz) { - inst = emit_x86_instruction(compiler, 1 | EX86_BIN_INS, SLJIT_IMM, 31, dst_r, 0); - FAIL_IF(!inst); - *(inst + 1) |= XOR; - } -#else - if (is_clz) - max = compiler->mode32 ? (32 + 31) : (64 + 63); - else - max = compiler->mode32 ? 32 : 64; - - if (cpu_feature_list & CPU_FEATURE_CMOV) { - EMIT_MOV(compiler, TMP_REG2, 0, SLJIT_IMM, max); - - inst = emit_x86_instruction(compiler, 2, dst_r, 0, TMP_REG2, 0); - FAIL_IF(!inst); - *inst++ = GROUP_0F; - *inst = CMOVE_r_rm; - } - else - FAIL_IF(sljit_emit_cmov_generic(compiler, SLJIT_EQUAL, dst_r, SLJIT_IMM, max)); - - if (is_clz) { - inst = emit_x86_instruction(compiler, 1 | EX86_BIN_INS, SLJIT_IMM, max >> 1, dst_r, 0); - FAIL_IF(!inst); - *(inst + 1) |= XOR; - } -#endif - - if (dst & SLJIT_MEM) - EMIT_MOV(compiler, dst, dstw, TMP_REG1, 0); - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src, sljit_sw srcw) -{ - sljit_s32 op_flags = GET_ALL_FLAGS(op); -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - sljit_s32 dst_is_ereg = 0; -#endif - - CHECK_ERROR(); - CHECK(check_sljit_emit_op1(compiler, op, dst, dstw, src, srcw)); - ADJUST_LOCAL_OFFSET(dst, dstw); - ADJUST_LOCAL_OFFSET(src, srcw); - - CHECK_EXTRA_REGS(dst, dstw, dst_is_ereg = 1); - CHECK_EXTRA_REGS(src, srcw, (void)0); -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - compiler->mode32 = op_flags & SLJIT_32; -#endif - - op = GET_OPCODE(op); - - if (op >= SLJIT_MOV && op <= SLJIT_MOV_P) { -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - compiler->mode32 = 0; -#endif - - if (FAST_IS_REG(src) && src == dst) { - if (!TYPE_CAST_NEEDED(op)) - return SLJIT_SUCCESS; - } - -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - if (op_flags & SLJIT_32) { - if (src & SLJIT_MEM) { - if (op == SLJIT_MOV_S32) - op = SLJIT_MOV_U32; - } - else if (src & SLJIT_IMM) { - if (op == SLJIT_MOV_U32) - op = SLJIT_MOV_S32; - } - } -#endif - - if (src & SLJIT_IMM) { - switch (op) { - case SLJIT_MOV_U8: - srcw = (sljit_u8)srcw; - break; - case SLJIT_MOV_S8: - srcw = (sljit_s8)srcw; - break; - case SLJIT_MOV_U16: - srcw = (sljit_u16)srcw; - break; - case SLJIT_MOV_S16: - srcw = (sljit_s16)srcw; - break; -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - case SLJIT_MOV_U32: - srcw = (sljit_u32)srcw; - break; - case SLJIT_MOV_S32: - srcw = (sljit_s32)srcw; - break; -#endif - } -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - if (SLJIT_UNLIKELY(dst_is_ereg)) - return emit_mov(compiler, dst, dstw, src, srcw); -#endif - } - -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - if (SLJIT_UNLIKELY(dst_is_ereg) && (!(op == SLJIT_MOV || op == SLJIT_MOV_U32 || op == SLJIT_MOV_S32 || op == SLJIT_MOV_P) || (src & SLJIT_MEM))) { - SLJIT_ASSERT(dst == SLJIT_MEM1(SLJIT_SP)); - dst = TMP_REG1; - } -#endif - - switch (op) { - case SLJIT_MOV: - case SLJIT_MOV_P: -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - case SLJIT_MOV_U32: - case SLJIT_MOV_S32: - case SLJIT_MOV32: -#endif - EMIT_MOV(compiler, dst, dstw, src, srcw); - break; - case SLJIT_MOV_U8: - FAIL_IF(emit_mov_byte(compiler, 0, dst, dstw, src, srcw)); - break; - case SLJIT_MOV_S8: - FAIL_IF(emit_mov_byte(compiler, 1, dst, dstw, src, srcw)); - break; - case SLJIT_MOV_U16: - FAIL_IF(emit_mov_half(compiler, 0, dst, dstw, src, srcw)); - break; - case SLJIT_MOV_S16: - FAIL_IF(emit_mov_half(compiler, 1, dst, dstw, src, srcw)); - break; -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - case SLJIT_MOV_U32: - FAIL_IF(emit_mov_int(compiler, 0, dst, dstw, src, srcw)); - break; - case SLJIT_MOV_S32: - FAIL_IF(emit_mov_int(compiler, 1, dst, dstw, src, srcw)); - break; - case SLJIT_MOV32: - compiler->mode32 = 1; - EMIT_MOV(compiler, dst, dstw, src, srcw); - compiler->mode32 = 0; - break; -#endif - } - -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - if (SLJIT_UNLIKELY(dst_is_ereg) && dst == TMP_REG1) - return emit_mov(compiler, SLJIT_MEM1(SLJIT_SP), dstw, TMP_REG1, 0); -#endif - return SLJIT_SUCCESS; - } - - switch (op) { - case SLJIT_NOT: - if (SLJIT_UNLIKELY(op_flags & SLJIT_SET_Z)) - return emit_not_with_flags(compiler, dst, dstw, src, srcw); - return emit_unary(compiler, NOT_rm, dst, dstw, src, srcw); - - case SLJIT_CLZ: - case SLJIT_CTZ: - return emit_clz_ctz(compiler, (op == SLJIT_CLZ), dst, dstw, src, srcw); - } - - return SLJIT_SUCCESS; -} - -static sljit_s32 emit_cum_binary(struct sljit_compiler *compiler, - sljit_u32 op_types, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - sljit_u8* inst; - sljit_u8 op_eax_imm = U8(op_types >> 24); - sljit_u8 op_rm = U8((op_types >> 16) & 0xff); - sljit_u8 op_mr = U8((op_types >> 8) & 0xff); - sljit_u8 op_imm = U8(op_types & 0xff); - - if (dst == src1 && dstw == src1w) { - if (src2 & SLJIT_IMM) { -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - if ((dst == SLJIT_R0) && (src2w > 127 || src2w < -128) && (compiler->mode32 || IS_HALFWORD(src2w))) { -#else - if ((dst == SLJIT_R0) && (src2w > 127 || src2w < -128)) { -#endif - BINARY_EAX_IMM(op_eax_imm, src2w); - } - else { - BINARY_IMM(op_imm, op_mr, src2w, dst, dstw); - } - } - else if (FAST_IS_REG(dst)) { - inst = emit_x86_instruction(compiler, 1, dst, dstw, src2, src2w); - FAIL_IF(!inst); - *inst = op_rm; - } - else if (FAST_IS_REG(src2)) { - /* Special exception for sljit_emit_op_flags. */ - inst = emit_x86_instruction(compiler, 1, src2, src2w, dst, dstw); - FAIL_IF(!inst); - *inst = op_mr; - } - else { - EMIT_MOV(compiler, TMP_REG1, 0, src2, src2w); - inst = emit_x86_instruction(compiler, 1, TMP_REG1, 0, dst, dstw); - FAIL_IF(!inst); - *inst = op_mr; - } - return SLJIT_SUCCESS; - } - - /* Only for cumulative operations. */ - if (dst == src2 && dstw == src2w) { - if (src1 & SLJIT_IMM) { -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - if ((dst == SLJIT_R0) && (src1w > 127 || src1w < -128) && (compiler->mode32 || IS_HALFWORD(src1w))) { -#else - if ((dst == SLJIT_R0) && (src1w > 127 || src1w < -128)) { -#endif - BINARY_EAX_IMM(op_eax_imm, src1w); - } - else { - BINARY_IMM(op_imm, op_mr, src1w, dst, dstw); - } - } - else if (FAST_IS_REG(dst)) { - inst = emit_x86_instruction(compiler, 1, dst, dstw, src1, src1w); - FAIL_IF(!inst); - *inst = op_rm; - } - else if (FAST_IS_REG(src1)) { - inst = emit_x86_instruction(compiler, 1, src1, src1w, dst, dstw); - FAIL_IF(!inst); - *inst = op_mr; - } - else { - EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w); - inst = emit_x86_instruction(compiler, 1, TMP_REG1, 0, dst, dstw); - FAIL_IF(!inst); - *inst = op_mr; - } - return SLJIT_SUCCESS; - } - - /* General version. */ - if (FAST_IS_REG(dst)) { - EMIT_MOV(compiler, dst, 0, src1, src1w); - if (src2 & SLJIT_IMM) { - BINARY_IMM(op_imm, op_mr, src2w, dst, 0); - } - else { - inst = emit_x86_instruction(compiler, 1, dst, 0, src2, src2w); - FAIL_IF(!inst); - *inst = op_rm; - } - } - else { - /* This version requires less memory writing. */ - EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w); - if (src2 & SLJIT_IMM) { - BINARY_IMM(op_imm, op_mr, src2w, TMP_REG1, 0); - } - else { - inst = emit_x86_instruction(compiler, 1, TMP_REG1, 0, src2, src2w); - FAIL_IF(!inst); - *inst = op_rm; - } - EMIT_MOV(compiler, dst, dstw, TMP_REG1, 0); - } - - return SLJIT_SUCCESS; -} - -static sljit_s32 emit_non_cum_binary(struct sljit_compiler *compiler, - sljit_u32 op_types, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - sljit_u8* inst; - sljit_u8 op_eax_imm = U8(op_types >> 24); - sljit_u8 op_rm = U8((op_types >> 16) & 0xff); - sljit_u8 op_mr = U8((op_types >> 8) & 0xff); - sljit_u8 op_imm = U8(op_types & 0xff); - - if (dst == src1 && dstw == src1w) { - if (src2 & SLJIT_IMM) { -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - if ((dst == SLJIT_R0) && (src2w > 127 || src2w < -128) && (compiler->mode32 || IS_HALFWORD(src2w))) { -#else - if ((dst == SLJIT_R0) && (src2w > 127 || src2w < -128)) { -#endif - BINARY_EAX_IMM(op_eax_imm, src2w); - } - else { - BINARY_IMM(op_imm, op_mr, src2w, dst, dstw); - } - } - else if (FAST_IS_REG(dst)) { - inst = emit_x86_instruction(compiler, 1, dst, dstw, src2, src2w); - FAIL_IF(!inst); - *inst = op_rm; - } - else if (FAST_IS_REG(src2)) { - inst = emit_x86_instruction(compiler, 1, src2, src2w, dst, dstw); - FAIL_IF(!inst); - *inst = op_mr; - } - else { - EMIT_MOV(compiler, TMP_REG1, 0, src2, src2w); - inst = emit_x86_instruction(compiler, 1, TMP_REG1, 0, dst, dstw); - FAIL_IF(!inst); - *inst = op_mr; - } - return SLJIT_SUCCESS; - } - - /* General version. */ - if (FAST_IS_REG(dst) && dst != src2) { - EMIT_MOV(compiler, dst, 0, src1, src1w); - if (src2 & SLJIT_IMM) { - BINARY_IMM(op_imm, op_mr, src2w, dst, 0); - } - else { - inst = emit_x86_instruction(compiler, 1, dst, 0, src2, src2w); - FAIL_IF(!inst); - *inst = op_rm; - } - } - else { - /* This version requires less memory writing. */ - EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w); - if (src2 & SLJIT_IMM) { - BINARY_IMM(op_imm, op_mr, src2w, TMP_REG1, 0); - } - else { - inst = emit_x86_instruction(compiler, 1, TMP_REG1, 0, src2, src2w); - FAIL_IF(!inst); - *inst = op_rm; - } - EMIT_MOV(compiler, dst, dstw, TMP_REG1, 0); - } - - return SLJIT_SUCCESS; -} - -static sljit_s32 emit_mul(struct sljit_compiler *compiler, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - sljit_u8* inst; - sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1; - - /* Register destination. */ - if (dst_r == src1 && !(src2 & SLJIT_IMM)) { - inst = emit_x86_instruction(compiler, 2, dst_r, 0, src2, src2w); - FAIL_IF(!inst); - *inst++ = GROUP_0F; - *inst = IMUL_r_rm; - } - else if (dst_r == src2 && !(src1 & SLJIT_IMM)) { - inst = emit_x86_instruction(compiler, 2, dst_r, 0, src1, src1w); - FAIL_IF(!inst); - *inst++ = GROUP_0F; - *inst = IMUL_r_rm; - } - else if (src1 & SLJIT_IMM) { - if (src2 & SLJIT_IMM) { - EMIT_MOV(compiler, dst_r, 0, SLJIT_IMM, src2w); - src2 = dst_r; - src2w = 0; - } - - if (src1w <= 127 && src1w >= -128) { - inst = emit_x86_instruction(compiler, 1, dst_r, 0, src2, src2w); - FAIL_IF(!inst); - *inst = IMUL_r_rm_i8; - inst = (sljit_u8*)ensure_buf(compiler, 1 + 1); - FAIL_IF(!inst); - INC_SIZE(1); - *inst = U8(src1w); - } -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - else { - inst = emit_x86_instruction(compiler, 1, dst_r, 0, src2, src2w); - FAIL_IF(!inst); - *inst = IMUL_r_rm_i32; - inst = (sljit_u8*)ensure_buf(compiler, 1 + 4); - FAIL_IF(!inst); - INC_SIZE(4); - sljit_unaligned_store_sw(inst, src1w); - } -#else - else if (IS_HALFWORD(src1w)) { - inst = emit_x86_instruction(compiler, 1, dst_r, 0, src2, src2w); - FAIL_IF(!inst); - *inst = IMUL_r_rm_i32; - inst = (sljit_u8*)ensure_buf(compiler, 1 + 4); - FAIL_IF(!inst); - INC_SIZE(4); - sljit_unaligned_store_s32(inst, (sljit_s32)src1w); - } - else { - if (dst_r != src2) - EMIT_MOV(compiler, dst_r, 0, src2, src2w); - FAIL_IF(emit_load_imm64(compiler, TMP_REG2, src1w)); - inst = emit_x86_instruction(compiler, 2, dst_r, 0, TMP_REG2, 0); - FAIL_IF(!inst); - *inst++ = GROUP_0F; - *inst = IMUL_r_rm; - } -#endif - } - else if (src2 & SLJIT_IMM) { - /* Note: src1 is NOT immediate. */ - - if (src2w <= 127 && src2w >= -128) { - inst = emit_x86_instruction(compiler, 1, dst_r, 0, src1, src1w); - FAIL_IF(!inst); - *inst = IMUL_r_rm_i8; - inst = (sljit_u8*)ensure_buf(compiler, 1 + 1); - FAIL_IF(!inst); - INC_SIZE(1); - *inst = U8(src2w); - } -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - else { - inst = emit_x86_instruction(compiler, 1, dst_r, 0, src1, src1w); - FAIL_IF(!inst); - *inst = IMUL_r_rm_i32; - inst = (sljit_u8*)ensure_buf(compiler, 1 + 4); - FAIL_IF(!inst); - INC_SIZE(4); - sljit_unaligned_store_sw(inst, src2w); - } -#else - else if (IS_HALFWORD(src2w)) { - inst = emit_x86_instruction(compiler, 1, dst_r, 0, src1, src1w); - FAIL_IF(!inst); - *inst = IMUL_r_rm_i32; - inst = (sljit_u8*)ensure_buf(compiler, 1 + 4); - FAIL_IF(!inst); - INC_SIZE(4); - sljit_unaligned_store_s32(inst, (sljit_s32)src2w); - } - else { - if (dst_r != src1) - EMIT_MOV(compiler, dst_r, 0, src1, src1w); - FAIL_IF(emit_load_imm64(compiler, TMP_REG2, src2w)); - inst = emit_x86_instruction(compiler, 2, dst_r, 0, TMP_REG2, 0); - FAIL_IF(!inst); - *inst++ = GROUP_0F; - *inst = IMUL_r_rm; - } -#endif - } - else { - /* Neither argument is immediate. */ - if (ADDRESSING_DEPENDS_ON(src2, dst_r)) - dst_r = TMP_REG1; - EMIT_MOV(compiler, dst_r, 0, src1, src1w); - inst = emit_x86_instruction(compiler, 2, dst_r, 0, src2, src2w); - FAIL_IF(!inst); - *inst++ = GROUP_0F; - *inst = IMUL_r_rm; - } - - if (dst & SLJIT_MEM) - EMIT_MOV(compiler, dst, dstw, TMP_REG1, 0); - - return SLJIT_SUCCESS; -} - -static sljit_s32 emit_lea_binary(struct sljit_compiler *compiler, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - sljit_u8* inst; - sljit_s32 dst_r, done = 0; - - /* These cases better be left to handled by normal way. */ - if (dst == src1 && dstw == src1w) - return SLJIT_ERR_UNSUPPORTED; - if (dst == src2 && dstw == src2w) - return SLJIT_ERR_UNSUPPORTED; - - dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1; - - if (FAST_IS_REG(src1)) { - if (FAST_IS_REG(src2)) { - inst = emit_x86_instruction(compiler, 1, dst_r, 0, SLJIT_MEM2(src1, src2), 0); - FAIL_IF(!inst); - *inst = LEA_r_m; - done = 1; - } -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - if ((src2 & SLJIT_IMM) && (compiler->mode32 || IS_HALFWORD(src2w))) { - inst = emit_x86_instruction(compiler, 1, dst_r, 0, SLJIT_MEM1(src1), (sljit_s32)src2w); -#else - if (src2 & SLJIT_IMM) { - inst = emit_x86_instruction(compiler, 1, dst_r, 0, SLJIT_MEM1(src1), src2w); -#endif - FAIL_IF(!inst); - *inst = LEA_r_m; - done = 1; - } - } - else if (FAST_IS_REG(src2)) { -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - if ((src1 & SLJIT_IMM) && (compiler->mode32 || IS_HALFWORD(src1w))) { - inst = emit_x86_instruction(compiler, 1, dst_r, 0, SLJIT_MEM1(src2), (sljit_s32)src1w); -#else - if (src1 & SLJIT_IMM) { - inst = emit_x86_instruction(compiler, 1, dst_r, 0, SLJIT_MEM1(src2), src1w); -#endif - FAIL_IF(!inst); - *inst = LEA_r_m; - done = 1; - } - } - - if (done) { - if (dst_r == TMP_REG1) - return emit_mov(compiler, dst, dstw, TMP_REG1, 0); - return SLJIT_SUCCESS; - } - return SLJIT_ERR_UNSUPPORTED; -} - -static sljit_s32 emit_cmp_binary(struct sljit_compiler *compiler, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - sljit_u8* inst; - -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - if (src1 == SLJIT_R0 && (src2 & SLJIT_IMM) && (src2w > 127 || src2w < -128) && (compiler->mode32 || IS_HALFWORD(src2w))) { -#else - if (src1 == SLJIT_R0 && (src2 & SLJIT_IMM) && (src2w > 127 || src2w < -128)) { -#endif - BINARY_EAX_IMM(CMP_EAX_i32, src2w); - return SLJIT_SUCCESS; - } - - if (FAST_IS_REG(src1)) { - if (src2 & SLJIT_IMM) { - BINARY_IMM(CMP, CMP_rm_r, src2w, src1, 0); - } - else { - inst = emit_x86_instruction(compiler, 1, src1, 0, src2, src2w); - FAIL_IF(!inst); - *inst = CMP_r_rm; - } - return SLJIT_SUCCESS; - } - - if (FAST_IS_REG(src2) && !(src1 & SLJIT_IMM)) { - inst = emit_x86_instruction(compiler, 1, src2, 0, src1, src1w); - FAIL_IF(!inst); - *inst = CMP_rm_r; - return SLJIT_SUCCESS; - } - - if (src2 & SLJIT_IMM) { - if (src1 & SLJIT_IMM) { - EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w); - src1 = TMP_REG1; - src1w = 0; - } - BINARY_IMM(CMP, CMP_rm_r, src2w, src1, src1w); - } - else { - EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w); - inst = emit_x86_instruction(compiler, 1, TMP_REG1, 0, src2, src2w); - FAIL_IF(!inst); - *inst = CMP_r_rm; - } - return SLJIT_SUCCESS; -} - -static sljit_s32 emit_test_binary(struct sljit_compiler *compiler, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - sljit_u8* inst; - -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - if (src1 == SLJIT_R0 && (src2 & SLJIT_IMM) && (src2w > 127 || src2w < -128) && (compiler->mode32 || IS_HALFWORD(src2w))) { -#else - if (src1 == SLJIT_R0 && (src2 & SLJIT_IMM) && (src2w > 127 || src2w < -128)) { -#endif - BINARY_EAX_IMM(TEST_EAX_i32, src2w); - return SLJIT_SUCCESS; - } - -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - if (src2 == SLJIT_R0 && (src1 & SLJIT_IMM) && (src1w > 127 || src1w < -128) && (compiler->mode32 || IS_HALFWORD(src1w))) { -#else - if (src2 == SLJIT_R0 && (src1 & SLJIT_IMM) && (src1w > 127 || src1w < -128)) { -#endif - BINARY_EAX_IMM(TEST_EAX_i32, src1w); - return SLJIT_SUCCESS; - } - - if (!(src1 & SLJIT_IMM)) { - if (src2 & SLJIT_IMM) { -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - if (IS_HALFWORD(src2w) || compiler->mode32) { - inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, src2w, src1, 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); - FAIL_IF(!inst); - *inst = TEST_rm_r; - } -#else - inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, src2w, src1, src1w); - FAIL_IF(!inst); - *inst = GROUP_F7; -#endif - return SLJIT_SUCCESS; - } - else if (FAST_IS_REG(src1)) { - inst = emit_x86_instruction(compiler, 1, src1, 0, src2, src2w); - FAIL_IF(!inst); - *inst = TEST_rm_r; - return SLJIT_SUCCESS; - } - } - - if (!(src2 & SLJIT_IMM)) { - if (src1 & SLJIT_IMM) { -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - if (IS_HALFWORD(src1w) || compiler->mode32) { - inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, src1w, src2, src2w); - FAIL_IF(!inst); - *inst = GROUP_F7; - } - else { - FAIL_IF(emit_load_imm64(compiler, TMP_REG1, src1w)); - inst = emit_x86_instruction(compiler, 1, TMP_REG1, 0, src2, src2w); - FAIL_IF(!inst); - *inst = TEST_rm_r; - } -#else - inst = emit_x86_instruction(compiler, 1, src1, src1w, src2, src2w); - FAIL_IF(!inst); - *inst = GROUP_F7; -#endif - return SLJIT_SUCCESS; - } - else if (FAST_IS_REG(src2)) { - inst = emit_x86_instruction(compiler, 1, src2, 0, src1, src1w); - FAIL_IF(!inst); - *inst = TEST_rm_r; - return SLJIT_SUCCESS; - } - } - - EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w); - if (src2 & SLJIT_IMM) { -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - if (IS_HALFWORD(src2w) || compiler->mode32) { - inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, src2w, TMP_REG1, 0); - FAIL_IF(!inst); - *inst = GROUP_F7; - } - else { - FAIL_IF(emit_load_imm64(compiler, TMP_REG2, src2w)); - inst = emit_x86_instruction(compiler, 1, TMP_REG2, 0, TMP_REG1, 0); - FAIL_IF(!inst); - *inst = TEST_rm_r; - } -#else - inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, src2w, TMP_REG1, 0); - FAIL_IF(!inst); - *inst = GROUP_F7; -#endif - } - else { - inst = emit_x86_instruction(compiler, 1, TMP_REG1, 0, src2, src2w); - FAIL_IF(!inst); - *inst = TEST_rm_r; - } - return SLJIT_SUCCESS; -} - -static sljit_s32 emit_shift(struct sljit_compiler *compiler, - sljit_u8 mode, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - sljit_s32 mode32; -#endif - sljit_u8* inst; - - if ((src2 & SLJIT_IMM) || (src2 == SLJIT_PREF_SHIFT_REG)) { - if (dst == src1 && dstw == src1w) { - inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, src2, src2w, dst, dstw); - FAIL_IF(!inst); - *inst |= mode; - return SLJIT_SUCCESS; - } - if (dst == SLJIT_PREF_SHIFT_REG && src2 == SLJIT_PREF_SHIFT_REG) { - EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w); - inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_PREF_SHIFT_REG, 0, TMP_REG1, 0); - FAIL_IF(!inst); - *inst |= mode; - EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, TMP_REG1, 0); - return SLJIT_SUCCESS; - } - if (FAST_IS_REG(dst)) { - EMIT_MOV(compiler, dst, 0, src1, src1w); - inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, src2, src2w, dst, 0); - FAIL_IF(!inst); - *inst |= mode; - return SLJIT_SUCCESS; - } - - EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w); - inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, src2, src2w, TMP_REG1, 0); - FAIL_IF(!inst); - *inst |= mode; - EMIT_MOV(compiler, dst, dstw, TMP_REG1, 0); - return SLJIT_SUCCESS; - } - - if (dst == SLJIT_PREF_SHIFT_REG) { - EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w); - EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, src2, src2w); - inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_PREF_SHIFT_REG, 0, TMP_REG1, 0); - FAIL_IF(!inst); - *inst |= mode; - return emit_mov(compiler, SLJIT_PREF_SHIFT_REG, 0, TMP_REG1, 0); - } - - if (FAST_IS_REG(dst) && dst != src2 && dst != TMP_REG1 && !ADDRESSING_DEPENDS_ON(src2, dst)) { - if (src1 != dst) - EMIT_MOV(compiler, dst, 0, src1, src1w); -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - mode32 = compiler->mode32; - compiler->mode32 = 0; -#endif - EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_PREF_SHIFT_REG, 0); -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - compiler->mode32 = mode32; -#endif - EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, src2, src2w); - inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_PREF_SHIFT_REG, 0, dst, 0); - FAIL_IF(!inst); - *inst |= mode; -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - compiler->mode32 = 0; -#endif - EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, TMP_REG1, 0); -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - compiler->mode32 = mode32; -#endif - return SLJIT_SUCCESS; - } - - /* This case is complex since ecx itself may be used for - addressing, and this case must be supported as well. */ - EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w); -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_SP), 0, SLJIT_PREF_SHIFT_REG, 0); -#else /* !SLJIT_CONFIG_X86_32 */ - mode32 = compiler->mode32; - compiler->mode32 = 0; - EMIT_MOV(compiler, TMP_REG2, 0, SLJIT_PREF_SHIFT_REG, 0); - compiler->mode32 = mode32; -#endif /* SLJIT_CONFIG_X86_32 */ - - EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, src2, src2w); - inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_PREF_SHIFT_REG, 0, TMP_REG1, 0); - FAIL_IF(!inst); - *inst |= mode; - -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, SLJIT_MEM1(SLJIT_SP), 0); -#else - compiler->mode32 = 0; - EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, TMP_REG2, 0); - compiler->mode32 = mode32; -#endif /* SLJIT_CONFIG_X86_32 */ - - if (dst != TMP_REG1) - return emit_mov(compiler, dst, dstw, TMP_REG1, 0); - - return SLJIT_SUCCESS; -} - -static sljit_s32 emit_shift_with_flags(struct sljit_compiler *compiler, - sljit_u8 mode, sljit_s32 set_flags, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - /* The CPU does not set flags if the shift count is 0. */ - if (src2 & SLJIT_IMM) { -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - src2w &= compiler->mode32 ? 0x1f : 0x3f; -#else /* !SLJIT_CONFIG_X86_64 */ - src2w &= 0x1f; -#endif /* SLJIT_CONFIG_X86_64 */ - if (src2w != 0) - return emit_shift(compiler, mode, dst, dstw, src1, src1w, src2, src2w); - - if (!set_flags) - return emit_mov(compiler, dst, dstw, src1, src1w); - /* OR dst, src, 0 */ - return emit_cum_binary(compiler, BINARY_OPCODE(OR), - dst, dstw, src1, src1w, SLJIT_IMM, 0); - } - - if (!set_flags) - return emit_shift(compiler, mode, dst, dstw, src1, src1w, src2, src2w); - - if (!FAST_IS_REG(dst)) - FAIL_IF(emit_cmp_binary(compiler, src1, src1w, SLJIT_IMM, 0)); - - FAIL_IF(emit_shift(compiler, mode, dst, dstw, src1, src1w, src2, src2w)); - - if (FAST_IS_REG(dst)) - return emit_cmp_binary(compiler, dst, dstw, SLJIT_IMM, 0); - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - CHECK_ERROR(); - CHECK(check_sljit_emit_op2(compiler, op, 0, dst, dstw, src1, src1w, src2, src2w)); - ADJUST_LOCAL_OFFSET(dst, dstw); - ADJUST_LOCAL_OFFSET(src1, src1w); - ADJUST_LOCAL_OFFSET(src2, src2w); - - CHECK_EXTRA_REGS(dst, 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 - - SLJIT_ASSERT(dst != TMP_REG1 || HAS_FLAGS(op)); - - switch (GET_OPCODE(op)) { - case SLJIT_ADD: - if (!HAS_FLAGS(op)) { - if (emit_lea_binary(compiler, dst, dstw, src1, src1w, src2, src2w) != SLJIT_ERR_UNSUPPORTED) - return compiler->error; - } - return emit_cum_binary(compiler, BINARY_OPCODE(ADD), - dst, dstw, src1, src1w, src2, src2w); - case SLJIT_ADDC: - return emit_cum_binary(compiler, BINARY_OPCODE(ADC), - dst, dstw, src1, src1w, src2, src2w); - case SLJIT_SUB: - if (src1 == SLJIT_IMM && src1w == 0) - return emit_unary(compiler, NEG_rm, dst, dstw, src2, src2w); - - if (!HAS_FLAGS(op)) { - if ((src2 & SLJIT_IMM) && emit_lea_binary(compiler, dst, dstw, src1, src1w, SLJIT_IMM, -src2w) != SLJIT_ERR_UNSUPPORTED) - return compiler->error; - if (FAST_IS_REG(dst) && src2 == dst) { - FAIL_IF(emit_non_cum_binary(compiler, BINARY_OPCODE(SUB), dst, 0, dst, 0, src1, src1w)); - return emit_unary(compiler, NEG_rm, dst, 0, dst, 0); - } - } - - return emit_non_cum_binary(compiler, BINARY_OPCODE(SUB), - dst, dstw, src1, src1w, src2, src2w); - case SLJIT_SUBC: - return emit_non_cum_binary(compiler, BINARY_OPCODE(SBB), - dst, dstw, src1, src1w, src2, src2w); - case SLJIT_MUL: - return emit_mul(compiler, dst, dstw, src1, src1w, src2, src2w); - case SLJIT_AND: - return emit_cum_binary(compiler, BINARY_OPCODE(AND), - dst, dstw, src1, src1w, src2, src2w); - case SLJIT_OR: - return emit_cum_binary(compiler, BINARY_OPCODE(OR), - dst, dstw, src1, src1w, src2, src2w); - case SLJIT_XOR: - return emit_cum_binary(compiler, BINARY_OPCODE(XOR), - dst, dstw, src1, src1w, src2, src2w); - case SLJIT_SHL: - case SLJIT_MSHL: - return emit_shift_with_flags(compiler, SHL, HAS_FLAGS(op), - dst, dstw, src1, src1w, src2, src2w); - case SLJIT_LSHR: - case SLJIT_MLSHR: - return emit_shift_with_flags(compiler, SHR, HAS_FLAGS(op), - dst, dstw, src1, src1w, src2, src2w); - case SLJIT_ASHR: - case SLJIT_MASHR: - return emit_shift_with_flags(compiler, SAR, HAS_FLAGS(op), - dst, dstw, src1, src1w, src2, src2w); - case SLJIT_ROTL: - return emit_shift_with_flags(compiler, ROL, 0, - dst, dstw, src1, src1w, src2, src2w); - case SLJIT_ROTR: - return emit_shift_with_flags(compiler, ROR, 0, - dst, dstw, src1, src1w, src2, src2w); - } - - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - sljit_s32 opcode = GET_OPCODE(op); - - CHECK_ERROR(); - CHECK(check_sljit_emit_op2(compiler, op, 1, 0, 0, src1, src1w, src2, src2w)); - - if (opcode != SLJIT_SUB && opcode != SLJIT_AND) { - SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_op2(compiler, op, TMP_REG1, 0, src1, src1w, src2, src2w); - } - - ADJUST_LOCAL_OFFSET(src1, src1w); - ADJUST_LOCAL_OFFSET(src2, src2w); - - 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 - - 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_shift_into(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 src_dst, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - sljit_s32 restore_ecx = 0; - sljit_s32 is_rotate, is_left; - sljit_u8* inst; - sljit_sw dstw = 0; -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - sljit_s32 tmp2 = SLJIT_MEM1(SLJIT_SP); -#else /* !SLJIT_CONFIG_X86_32 */ - sljit_s32 tmp2 = TMP_REG2; -#endif /* SLJIT_CONFIG_X86_32 */ - - CHECK_ERROR(); - CHECK(check_sljit_emit_shift_into(compiler, op, src_dst, src1, src1w, src2, src2w)); - ADJUST_LOCAL_OFFSET(src1, src1w); - ADJUST_LOCAL_OFFSET(src2, src2w); - - 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 - - if (src2 & SLJIT_IMM) { -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - src2w &= 0x1f; -#else /* !SLJIT_CONFIG_X86_32 */ - src2w &= (op & SLJIT_32) ? 0x1f : 0x3f; -#endif /* SLJIT_CONFIG_X86_32 */ - - if (src2w == 0) - return SLJIT_SUCCESS; - } - - is_left = (GET_OPCODE(op) == SLJIT_SHL || GET_OPCODE(op) == SLJIT_MSHL); - - is_rotate = (src_dst == src1); - CHECK_EXTRA_REGS(src_dst, dstw, (void)0); - - if (is_rotate) - return emit_shift(compiler, is_left ? ROL : ROR, src_dst, dstw, src1, src1w, src2, src2w); - - if ((src2 & SLJIT_IMM) || src2 == SLJIT_PREF_SHIFT_REG) { - if (!FAST_IS_REG(src1)) { - EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w); - src1 = TMP_REG1; - } - } else if (FAST_IS_REG(src1)) { -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - compiler->mode32 = 0; -#endif - EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_PREF_SHIFT_REG, 0); -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - compiler->mode32 = op & SLJIT_32; -#endif - EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, src2, src2w); - - if (src1 == SLJIT_PREF_SHIFT_REG) - src1 = TMP_REG1; - - if (src_dst == SLJIT_PREF_SHIFT_REG) - src_dst = TMP_REG1; - - restore_ecx = 1; - } else { - EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w); -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - compiler->mode32 = 0; -#endif - EMIT_MOV(compiler, tmp2, 0, SLJIT_PREF_SHIFT_REG, 0); -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - compiler->mode32 = op & SLJIT_32; -#endif - EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, src2, src2w); - - src1 = TMP_REG1; - - if (src_dst == SLJIT_PREF_SHIFT_REG) { - src_dst = tmp2; - SLJIT_ASSERT(dstw == 0); - } - - restore_ecx = 2; - } - - inst = emit_x86_instruction(compiler, 2, src1, 0, src_dst, dstw); - FAIL_IF(!inst); - inst[0] = GROUP_0F; - - if (src2 & SLJIT_IMM) { - inst[1] = U8((is_left ? SHLD : SHRD) - 1); - - /* Immedate argument is added separately. */ - inst = (sljit_u8*)ensure_buf(compiler, 1 + 1); - FAIL_IF(!inst); - INC_SIZE(1); - *inst = U8(src2w); - } else - inst[1] = U8(is_left ? SHLD : SHRD); - -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - compiler->mode32 = 0; -#endif - - if (restore_ecx == 1) - return emit_mov(compiler, SLJIT_PREF_SHIFT_REG, 0, TMP_REG1, 0); - if (restore_ecx == 2) - return emit_mov(compiler, SLJIT_PREF_SHIFT_REG, 0, tmp2, 0); - - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 src, sljit_sw srcw) -{ - CHECK_ERROR(); - CHECK(check_sljit_emit_op_src(compiler, op, src, srcw)); - ADJUST_LOCAL_OFFSET(src, srcw); - - CHECK_EXTRA_REGS(src, srcw, (void)0); - - switch (op) { - case SLJIT_FAST_RETURN: - return emit_fast_return(compiler, src, srcw); - case SLJIT_SKIP_FRAMES_BEFORE_FAST_RETURN: - /* Don't adjust shadow stack if it isn't enabled. */ - if (!cpu_has_shadow_stack ()) - return SLJIT_SUCCESS; - return adjust_shadow_stack(compiler, src, srcw); - case SLJIT_PREFETCH_L1: - case SLJIT_PREFETCH_L2: - case SLJIT_PREFETCH_L3: - case SLJIT_PREFETCH_ONCE: - return emit_prefetch(compiler, op, src, srcw); - } - - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 reg) -{ - CHECK_REG_INDEX(check_sljit_get_register_index(reg)); -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - if (reg >= SLJIT_R3 && reg <= SLJIT_R8) - return -1; -#endif - return reg_map[reg]; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_float_register_index(sljit_s32 reg) -{ - CHECK_REG_INDEX(check_sljit_get_float_register_index(reg)); -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - return reg; -#else - return freg_map[reg]; -#endif -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler, - void *instruction, sljit_u32 size) -{ - sljit_u8 *inst; - - CHECK_ERROR(); - CHECK(check_sljit_emit_op_custom(compiler, instruction, size)); - - inst = (sljit_u8*)ensure_buf(compiler, 1 + size); - FAIL_IF(!inst); - INC_SIZE(size); - SLJIT_MEMCPY(inst, instruction, size); - return SLJIT_SUCCESS; -} - -/* --------------------------------------------------------------------- */ -/* Floating point operators */ -/* --------------------------------------------------------------------- */ - -/* Alignment(3) + 4 * 16 bytes. */ -static sljit_u32 sse2_data[3 + (4 * 4)]; -static sljit_u32 *sse2_buffer; - -static void init_compiler(void) -{ - /* Align to 16 bytes. */ - sse2_buffer = (sljit_u32*)(((sljit_uw)sse2_data + 15) & ~(sljit_uw)0xf); - - /* Single precision constants (each constant is 16 byte long). */ - sse2_buffer[0] = 0x80000000; - sse2_buffer[4] = 0x7fffffff; - /* Double precision constants (each constant is 16 byte long). */ - sse2_buffer[8] = 0; - sse2_buffer[9] = 0x80000000; - sse2_buffer[12] = 0xffffffff; - sse2_buffer[13] = 0x7fffffff; -} - -static sljit_s32 emit_sse2(struct sljit_compiler *compiler, sljit_u8 opcode, - sljit_s32 single, sljit_s32 xmm1, sljit_s32 xmm2, sljit_sw xmm2w) -{ - sljit_u8 *inst; - - inst = emit_x86_instruction(compiler, 2 | (single ? EX86_PREF_F3 : EX86_PREF_F2) | EX86_SSE2, xmm1, 0, xmm2, xmm2w); - FAIL_IF(!inst); - *inst++ = GROUP_0F; - *inst = opcode; - return SLJIT_SUCCESS; -} - -static sljit_s32 emit_sse2_logic(struct sljit_compiler *compiler, sljit_u8 opcode, - sljit_s32 pref66, sljit_s32 xmm1, sljit_s32 xmm2, sljit_sw xmm2w) -{ - sljit_u8 *inst; - - inst = emit_x86_instruction(compiler, 2 | (pref66 ? EX86_PREF_66 : 0) | EX86_SSE2, xmm1, 0, xmm2, xmm2w); - FAIL_IF(!inst); - *inst++ = GROUP_0F; - *inst = opcode; - return SLJIT_SUCCESS; -} - -static SLJIT_INLINE sljit_s32 emit_sse2_load(struct sljit_compiler *compiler, - sljit_s32 single, sljit_s32 dst, sljit_s32 src, sljit_sw srcw) -{ - return emit_sse2(compiler, MOVSD_x_xm, single, dst, src, srcw); -} - -static SLJIT_INLINE sljit_s32 emit_sse2_store(struct sljit_compiler *compiler, - sljit_s32 single, sljit_s32 dst, sljit_sw dstw, sljit_s32 src) -{ - return emit_sse2(compiler, MOVSD_xm_x, single, src, dst, dstw); -} - -static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src, sljit_sw srcw) -{ - sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1; - sljit_u8 *inst; - -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - if (GET_OPCODE(op) == SLJIT_CONV_SW_FROM_F64) - compiler->mode32 = 0; -#endif - - inst = emit_x86_instruction(compiler, 2 | ((op & SLJIT_32) ? EX86_PREF_F3 : EX86_PREF_F2) | EX86_SSE2_OP2, dst_r, 0, src, srcw); - FAIL_IF(!inst); - *inst++ = GROUP_0F; - *inst = CVTTSD2SI_r_xm; - - if (dst & SLJIT_MEM) - return emit_mov(compiler, dst, dstw, TMP_REG1, 0); - return SLJIT_SUCCESS; -} - -static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src, sljit_sw srcw) -{ - sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG; - sljit_u8 *inst; - -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_SW) - compiler->mode32 = 0; -#endif - - if (src & SLJIT_IMM) { -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32) - srcw = (sljit_s32)srcw; -#endif - EMIT_MOV(compiler, TMP_REG1, 0, src, srcw); - src = TMP_REG1; - srcw = 0; - } - - inst = emit_x86_instruction(compiler, 2 | ((op & SLJIT_32) ? EX86_PREF_F3 : EX86_PREF_F2) | EX86_SSE2_OP1, dst_r, 0, src, srcw); - FAIL_IF(!inst); - *inst++ = GROUP_0F; - *inst = CVTSI2SD_x_rm; - -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - compiler->mode32 = 1; -#endif - if (dst_r == TMP_FREG) - return emit_sse2_store(compiler, op & SLJIT_32, dst, dstw, TMP_FREG); - return SLJIT_SUCCESS; -} - -static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - switch (GET_FLAG_TYPE(op)) { - case SLJIT_ORDERED_LESS: - case SLJIT_UNORDERED_OR_GREATER_EQUAL: - case SLJIT_UNORDERED_OR_GREATER: - case SLJIT_ORDERED_LESS_EQUAL: - if (!FAST_IS_REG(src2)) { - FAIL_IF(emit_sse2_load(compiler, op & SLJIT_32, TMP_FREG, src2, src2w)); - src2 = TMP_FREG; - } - - return emit_sse2_logic(compiler, UCOMISD_x_xm, !(op & SLJIT_32), src2, src1, src1w); - } - - if (!FAST_IS_REG(src1)) { - FAIL_IF(emit_sse2_load(compiler, op & SLJIT_32, TMP_FREG, src1, src1w)); - src1 = TMP_FREG; - } - - return emit_sse2_logic(compiler, UCOMISD_x_xm, !(op & SLJIT_32), src1, src2, src2w); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src, sljit_sw srcw) -{ - sljit_s32 dst_r; - -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - compiler->mode32 = 1; -#endif - - CHECK_ERROR(); - SELECT_FOP1_OPERATION_WITH_CHECKS(compiler, op, dst, dstw, src, srcw); - - if (GET_OPCODE(op) == SLJIT_MOV_F64) { - if (FAST_IS_REG(dst)) - return emit_sse2_load(compiler, op & SLJIT_32, dst, src, srcw); - if (FAST_IS_REG(src)) - return emit_sse2_store(compiler, op & SLJIT_32, dst, dstw, src); - FAIL_IF(emit_sse2_load(compiler, op & SLJIT_32, TMP_FREG, src, srcw)); - return emit_sse2_store(compiler, op & SLJIT_32, dst, dstw, TMP_FREG); - } - - if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_F32) { - dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG; - if (FAST_IS_REG(src)) { - /* We overwrite the high bits of source. From SLJIT point of view, - this is not an issue. - Note: In SSE3, we could also use MOVDDUP and MOVSLDUP. */ - FAIL_IF(emit_sse2_logic(compiler, UNPCKLPD_x_xm, op & SLJIT_32, src, src, 0)); - } - else { - FAIL_IF(emit_sse2_load(compiler, !(op & SLJIT_32), TMP_FREG, src, srcw)); - src = TMP_FREG; - } - - FAIL_IF(emit_sse2_logic(compiler, CVTPD2PS_x_xm, op & SLJIT_32, dst_r, src, 0)); - if (dst_r == TMP_FREG) - return emit_sse2_store(compiler, op & SLJIT_32, dst, dstw, TMP_FREG); - return SLJIT_SUCCESS; - } - - if (FAST_IS_REG(dst)) { - dst_r = dst; - if (dst != src) - FAIL_IF(emit_sse2_load(compiler, op & SLJIT_32, dst_r, src, srcw)); - } - else { - dst_r = TMP_FREG; - FAIL_IF(emit_sse2_load(compiler, op & SLJIT_32, dst_r, src, srcw)); - } - - switch (GET_OPCODE(op)) { - case SLJIT_NEG_F64: - FAIL_IF(emit_sse2_logic(compiler, XORPD_x_xm, 1, dst_r, SLJIT_MEM0(), (sljit_sw)(op & SLJIT_32 ? sse2_buffer : sse2_buffer + 8))); - break; - - case SLJIT_ABS_F64: - FAIL_IF(emit_sse2_logic(compiler, ANDPD_x_xm, 1, dst_r, SLJIT_MEM0(), (sljit_sw)(op & SLJIT_32 ? sse2_buffer + 4 : sse2_buffer + 12))); - break; - } - - if (dst_r == TMP_FREG) - return emit_sse2_store(compiler, op & SLJIT_32, dst, dstw, TMP_FREG); - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 src1, sljit_sw src1w, - sljit_s32 src2, sljit_sw src2w) -{ - sljit_s32 dst_r; - - CHECK_ERROR(); - CHECK(check_sljit_emit_fop2(compiler, op, dst, dstw, src1, src1w, src2, src2w)); - ADJUST_LOCAL_OFFSET(dst, dstw); - ADJUST_LOCAL_OFFSET(src1, src1w); - ADJUST_LOCAL_OFFSET(src2, src2w); - -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - compiler->mode32 = 1; -#endif - - if (FAST_IS_REG(dst)) { - dst_r = dst; - if (dst == src1) - ; /* Do nothing here. */ - else if (dst == src2 && (op == SLJIT_ADD_F64 || op == SLJIT_MUL_F64)) { - /* Swap arguments. */ - src2 = src1; - src2w = src1w; - } - 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 { - dst_r = TMP_FREG; - FAIL_IF(emit_sse2_load(compiler, op & SLJIT_32, TMP_FREG, src1, src1w)); - } - - switch (GET_OPCODE(op)) { - case SLJIT_ADD_F64: - FAIL_IF(emit_sse2(compiler, ADDSD_x_xm, op & SLJIT_32, dst_r, src2, src2w)); - break; - - case SLJIT_SUB_F64: - FAIL_IF(emit_sse2(compiler, SUBSD_x_xm, op & SLJIT_32, dst_r, src2, src2w)); - break; - - case SLJIT_MUL_F64: - FAIL_IF(emit_sse2(compiler, MULSD_x_xm, op & SLJIT_32, dst_r, src2, src2w)); - break; - - case SLJIT_DIV_F64: - FAIL_IF(emit_sse2(compiler, DIVSD_x_xm, op & SLJIT_32, dst_r, src2, src2w)); - break; - } - - if (dst_r == TMP_FREG) - return emit_sse2_store(compiler, op & SLJIT_32, dst, dstw, TMP_FREG); - return SLJIT_SUCCESS; -} - -/* --------------------------------------------------------------------- */ -/* Conditional instructions */ -/* --------------------------------------------------------------------- */ - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compiler *compiler) -{ - sljit_u8 *inst; - struct sljit_label *label; - - CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_label(compiler)); - - if (compiler->last_label && compiler->last_label->size == compiler->size) - return compiler->last_label; - - label = (struct sljit_label*)ensure_abuf(compiler, sizeof(struct sljit_label)); - PTR_FAIL_IF(!label); - set_label(label, compiler); - - inst = (sljit_u8*)ensure_buf(compiler, 2); - PTR_FAIL_IF(!inst); - - *inst++ = 0; - *inst++ = 0; - - return label; -} - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type) -{ - sljit_u8 *inst; - struct sljit_jump *jump; - - CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_jump(compiler, type)); - - jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump)); - PTR_FAIL_IF_NULL(jump); - set_jump(jump, compiler, (sljit_u32)((type & SLJIT_REWRITABLE_JUMP) | ((type & 0xff) << TYPE_SHIFT))); - type &= 0xff; - - /* 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); - PTR_FAIL_IF_NULL(inst); - - *inst++ = 0; - *inst++ = 1; - return jump; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 src, sljit_sw srcw) -{ - sljit_u8 *inst; - struct sljit_jump *jump; - - CHECK_ERROR(); - CHECK(check_sljit_emit_ijump(compiler, type, src, srcw)); - ADJUST_LOCAL_OFFSET(src, srcw); - - CHECK_EXTRA_REGS(src, srcw, (void)0); - - if (src == SLJIT_IMM) { - jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump)); - FAIL_IF_NULL(jump); - set_jump(jump, compiler, (sljit_u32)(JUMP_ADDR | (type << TYPE_SHIFT))); - jump->u.target = (sljit_uw)srcw; - - /* 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); - FAIL_IF_NULL(inst); - - *inst++ = 0; - *inst++ = 1; - } - else { -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - /* REX_W is not necessary (src is not immediate). */ - compiler->mode32 = 1; -#endif - inst = emit_x86_instruction(compiler, 1, 0, 0, src, srcw); - FAIL_IF(!inst); - *inst++ = GROUP_FF; - *inst = U8(*inst | ((type >= SLJIT_FAST_CALL) ? CALL_rm : JMP_rm)); - } - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_s32 op, - sljit_s32 dst, sljit_sw dstw, - sljit_s32 type) -{ - sljit_u8 *inst; - sljit_u8 cond_set = 0; -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - sljit_s32 reg; -#endif - /* ADJUST_LOCAL_OFFSET and CHECK_EXTRA_REGS might overwrite these values. */ - sljit_s32 dst_save = dst; - sljit_sw dstw_save = dstw; - - CHECK_ERROR(); - CHECK(check_sljit_emit_op_flags(compiler, op, dst, dstw, type)); - - ADJUST_LOCAL_OFFSET(dst, dstw); - CHECK_EXTRA_REGS(dst, dstw, (void)0); - - /* setcc = jcc + 0x10. */ - cond_set = U8(get_jump_code((sljit_uw)type) + 0x10); - -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - if (GET_OPCODE(op) == SLJIT_OR && !GET_ALL_FLAGS(op) && FAST_IS_REG(dst)) { - inst = (sljit_u8*)ensure_buf(compiler, 1 + 4 + 3); - FAIL_IF(!inst); - INC_SIZE(4 + 3); - /* Set low register to conditional flag. */ - *inst++ = (reg_map[TMP_REG1] <= 7) ? REX : REX_B; - *inst++ = GROUP_0F; - *inst++ = cond_set; - *inst++ = MOD_REG | reg_lmap[TMP_REG1]; - *inst++ = U8(REX | (reg_map[TMP_REG1] <= 7 ? 0 : REX_R) | (reg_map[dst] <= 7 ? 0 : REX_B)); - *inst++ = OR_rm8_r8; - *inst++ = U8(MOD_REG | (reg_lmap[TMP_REG1] << 3) | reg_lmap[dst]); - return SLJIT_SUCCESS; - } - - reg = (GET_OPCODE(op) < SLJIT_ADD && FAST_IS_REG(dst)) ? dst : TMP_REG1; - - inst = (sljit_u8*)ensure_buf(compiler, 1 + 4 + 4); - FAIL_IF(!inst); - INC_SIZE(4 + 4); - /* Set low register to conditional flag. */ - *inst++ = (reg_map[reg] <= 7) ? REX : REX_B; - *inst++ = GROUP_0F; - *inst++ = cond_set; - *inst++ = MOD_REG | reg_lmap[reg]; - *inst++ = REX_W | (reg_map[reg] <= 7 ? 0 : (REX_B | REX_R)); - /* The movzx instruction does not affect flags. */ - *inst++ = GROUP_0F; - *inst++ = MOVZX_r_rm8; - *inst = U8(MOD_REG | (reg_lmap[reg] << 3) | reg_lmap[reg]); - - if (reg != TMP_REG1) - return SLJIT_SUCCESS; - - if (GET_OPCODE(op) < SLJIT_ADD) { - compiler->mode32 = GET_OPCODE(op) != SLJIT_MOV; - return emit_mov(compiler, dst, dstw, TMP_REG1, 0); - } - - SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_op2(compiler, op, dst_save, dstw_save, dst_save, dstw_save, TMP_REG1, 0); - -#else - /* The SLJIT_CONFIG_X86_32 code path starts here. */ - if (GET_OPCODE(op) < SLJIT_ADD && FAST_IS_REG(dst)) { - if (reg_map[dst] <= 4) { - /* Low byte is accessible. */ - inst = (sljit_u8*)ensure_buf(compiler, 1 + 3 + 3); - FAIL_IF(!inst); - INC_SIZE(3 + 3); - /* Set low byte to conditional flag. */ - *inst++ = GROUP_0F; - *inst++ = cond_set; - *inst++ = U8(MOD_REG | reg_map[dst]); - - *inst++ = GROUP_0F; - *inst++ = MOVZX_r_rm8; - *inst = U8(MOD_REG | (reg_map[dst] << 3) | reg_map[dst]); - return SLJIT_SUCCESS; - } - - /* Low byte is not accessible. */ - if (cpu_feature_list == 0) - get_cpu_features(); - - if (cpu_feature_list & CPU_FEATURE_CMOV) { - EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_IMM, 1); - /* a xor reg, reg operation would overwrite the flags. */ - EMIT_MOV(compiler, dst, 0, SLJIT_IMM, 0); - - inst = (sljit_u8*)ensure_buf(compiler, 1 + 3); - FAIL_IF(!inst); - INC_SIZE(3); - - *inst++ = GROUP_0F; - /* cmovcc = setcc - 0x50. */ - *inst++ = U8(cond_set - 0x50); - *inst++ = U8(MOD_REG | (reg_map[dst] << 3) | reg_map[TMP_REG1]); - return SLJIT_SUCCESS; - } - - inst = (sljit_u8*)ensure_buf(compiler, 1 + 1 + 3 + 3 + 1); - FAIL_IF(!inst); - INC_SIZE(1 + 3 + 3 + 1); - *inst++ = U8(XCHG_EAX_r | reg_map[TMP_REG1]); - /* Set al to conditional flag. */ - *inst++ = GROUP_0F; - *inst++ = cond_set; - *inst++ = MOD_REG | 0 /* eax */; - - *inst++ = GROUP_0F; - *inst++ = MOVZX_r_rm8; - *inst++ = U8(MOD_REG | (reg_map[dst] << 3) | 0 /* eax */); - *inst++ = U8(XCHG_EAX_r | reg_map[TMP_REG1]); - return SLJIT_SUCCESS; - } - - if (GET_OPCODE(op) == SLJIT_OR && !GET_ALL_FLAGS(op) && FAST_IS_REG(dst) && reg_map[dst] <= 4) { - SLJIT_ASSERT(reg_map[SLJIT_R0] == 0); - - if (dst != SLJIT_R0) { - inst = (sljit_u8*)ensure_buf(compiler, 1 + 1 + 3 + 2 + 1); - FAIL_IF(!inst); - INC_SIZE(1 + 3 + 2 + 1); - /* Set low register to conditional flag. */ - *inst++ = U8(XCHG_EAX_r | reg_map[TMP_REG1]); - *inst++ = GROUP_0F; - *inst++ = cond_set; - *inst++ = MOD_REG | 0 /* eax */; - *inst++ = OR_rm8_r8; - *inst++ = MOD_REG | (0 /* eax */ << 3) | reg_map[dst]; - *inst++ = U8(XCHG_EAX_r | reg_map[TMP_REG1]); - } - else { - inst = (sljit_u8*)ensure_buf(compiler, 1 + 2 + 3 + 2 + 2); - FAIL_IF(!inst); - INC_SIZE(2 + 3 + 2 + 2); - /* Set low register to conditional flag. */ - *inst++ = XCHG_r_rm; - *inst++ = U8(MOD_REG | (1 /* ecx */ << 3) | reg_map[TMP_REG1]); - *inst++ = GROUP_0F; - *inst++ = cond_set; - *inst++ = MOD_REG | 1 /* ecx */; - *inst++ = OR_rm8_r8; - *inst++ = MOD_REG | (1 /* ecx */ << 3) | 0 /* eax */; - *inst++ = XCHG_r_rm; - *inst++ = U8(MOD_REG | (1 /* ecx */ << 3) | reg_map[TMP_REG1]); - } - return SLJIT_SUCCESS; - } - - /* Set TMP_REG1 to the bit. */ - inst = (sljit_u8*)ensure_buf(compiler, 1 + 1 + 3 + 3 + 1); - FAIL_IF(!inst); - INC_SIZE(1 + 3 + 3 + 1); - *inst++ = U8(XCHG_EAX_r | reg_map[TMP_REG1]); - /* Set al to conditional flag. */ - *inst++ = GROUP_0F; - *inst++ = cond_set; - *inst++ = MOD_REG | 0 /* eax */; - - *inst++ = GROUP_0F; - *inst++ = MOVZX_r_rm8; - *inst++ = MOD_REG | (0 << 3) /* eax */ | 0 /* eax */; - - *inst++ = U8(XCHG_EAX_r | reg_map[TMP_REG1]); - - if (GET_OPCODE(op) < SLJIT_ADD) - return emit_mov(compiler, dst, dstw, TMP_REG1, 0); - - SLJIT_SKIP_CHECKS(compiler); - return sljit_emit_op2(compiler, op, dst_save, dstw_save, dst_save, dstw_save, TMP_REG1, 0); -#endif /* SLJIT_CONFIG_X86_64 */ -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compiler, sljit_s32 type, - sljit_s32 dst_reg, - sljit_s32 src, sljit_sw srcw) -{ - sljit_u8* inst; - - CHECK_ERROR(); - CHECK(check_sljit_emit_cmov(compiler, type, dst_reg, src, srcw)); - -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - type &= ~SLJIT_32; - - if (!sljit_has_cpu_feature(SLJIT_HAS_CMOV) || (dst_reg >= SLJIT_R3 && dst_reg <= SLJIT_S3)) - return sljit_emit_cmov_generic(compiler, type, dst_reg, src, srcw); -#else - if (!sljit_has_cpu_feature(SLJIT_HAS_CMOV)) - return sljit_emit_cmov_generic(compiler, type, dst_reg, src, srcw); -#endif - - /* ADJUST_LOCAL_OFFSET is not needed. */ - CHECK_EXTRA_REGS(src, srcw, (void)0); - -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - compiler->mode32 = type & SLJIT_32; - type &= ~SLJIT_32; -#endif - - if (SLJIT_UNLIKELY(src & SLJIT_IMM)) { - EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_IMM, srcw); - src = TMP_REG1; - srcw = 0; - } - - inst = emit_x86_instruction(compiler, 2, dst_reg, 0, src, srcw); - FAIL_IF(!inst); - *inst++ = GROUP_0F; - *inst = U8(get_jump_code((sljit_uw)type) - 0x40); - return SLJIT_SUCCESS; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_local_base(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw offset) -{ - CHECK_ERROR(); - CHECK(check_sljit_get_local_base(compiler, dst, dstw, offset)); - ADJUST_LOCAL_OFFSET(dst, dstw); - - CHECK_EXTRA_REGS(dst, dstw, (void)0); - -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - compiler->mode32 = 0; -#endif - - ADJUST_LOCAL_OFFSET(SLJIT_MEM1(SLJIT_SP), offset); - -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - if (NOT_HALFWORD(offset)) { - FAIL_IF(emit_load_imm64(compiler, TMP_REG1, offset)); -#if (defined SLJIT_DEBUG && SLJIT_DEBUG) - SLJIT_ASSERT(emit_lea_binary(compiler, dst, dstw, SLJIT_SP, 0, TMP_REG1, 0) != SLJIT_ERR_UNSUPPORTED); - return compiler->error; -#else - return emit_lea_binary(compiler, dst, dstw, SLJIT_SP, 0, TMP_REG1, 0); -#endif - } -#endif - - if (offset != 0) - return emit_lea_binary(compiler, dst, dstw, SLJIT_SP, 0, SLJIT_IMM, offset); - return emit_mov(compiler, dst, dstw, SLJIT_SP, 0); -} - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value) -{ - sljit_u8 *inst; - struct sljit_const *const_; -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - sljit_s32 reg; -#endif - - CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_const(compiler, dst, dstw, init_value)); - ADJUST_LOCAL_OFFSET(dst, dstw); - - CHECK_EXTRA_REGS(dst, dstw, (void)0); - - const_ = (struct sljit_const*)ensure_abuf(compiler, sizeof(struct sljit_const)); - PTR_FAIL_IF(!const_); - set_const(const_, compiler); - -#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, init_value)) - return NULL; -#else - if (emit_mov(compiler, dst, dstw, SLJIT_IMM, init_value)) - return NULL; -#endif - - inst = (sljit_u8*)ensure_buf(compiler, 2); - PTR_FAIL_IF(!inst); - - *inst++ = 0; - *inst++ = 2; - -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - if (dst & SLJIT_MEM) - if (emit_mov(compiler, dst, dstw, TMP_REG1, 0)) - return NULL; -#endif - - return const_; -} - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label* sljit_emit_put_label(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw) -{ - struct sljit_put_label *put_label; - sljit_u8 *inst; -#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - sljit_s32 reg; - sljit_uw start_size; -#endif - - CHECK_ERROR_PTR(); - CHECK_PTR(check_sljit_emit_put_label(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); - -#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 - -#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 - - inst = (sljit_u8*)ensure_buf(compiler, 2); - PTR_FAIL_IF(!inst); - - *inst++ = 0; - *inst++ = 3; - - return put_label; -} - -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset) -{ - SLJIT_UNUSED_ARG(executable_offset); - - SLJIT_UPDATE_WX_FLAGS((void*)addr, (void*)(addr + sizeof(sljit_uw)), 0); -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - sljit_unaligned_store_sw((void*)addr, (sljit_sw)(new_target - (addr + 4) - (sljit_uw)executable_offset)); -#else - sljit_unaligned_store_sw((void*)addr, (sljit_sw)new_target); -#endif - SLJIT_UPDATE_WX_FLAGS((void*)addr, (void*)(addr + sizeof(sljit_uw)), 1); -} - -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset) -{ - SLJIT_UNUSED_ARG(executable_offset); - - SLJIT_UPDATE_WX_FLAGS((void*)addr, (void*)(addr + sizeof(sljit_sw)), 0); - sljit_unaligned_store_sw((void*)addr, new_constant); - SLJIT_UPDATE_WX_FLAGS((void*)addr, (void*)(addr + sizeof(sljit_sw)), 1); -} diff --git a/modules/regex/pcre2/src/sljit/sljitProtExecAllocator.c b/modules/regex/pcre2/src/sljit/sljitProtExecAllocator.c deleted file mode 100644 index 915411f..0000000 --- a/modules/regex/pcre2/src/sljit/sljitProtExecAllocator.c +++ /dev/null @@ -1,474 +0,0 @@ -/* - * 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. - */ - -/* - This file contains a simple executable memory allocator - - It is assumed, that executable code blocks are usually medium (or sometimes - large) memory blocks, and the allocator is not too frequently called (less - optimized than other allocators). Thus, using it as a generic allocator is - not suggested. - - How does it work: - Memory is allocated in continuous memory areas called chunks by alloc_chunk() - Chunk format: - [ block ][ block ] ... [ block ][ block terminator ] - - All blocks and the block terminator is started with block_header. The block - header contains the size of the previous and the next block. These sizes - can also contain special values. - Block size: - 0 - The block is a free_block, with a different size member. - 1 - The block is a block terminator. - n - The block is used at the moment, and the value contains its size. - Previous block size: - 0 - This is the first block of the memory chunk. - n - The size of the previous block. - - Using these size values we can go forward or backward on the block chain. - The unused blocks are stored in a chain list pointed by free_blocks. This - list is useful if we need to find a suitable memory area when the allocator - is called. - - When a block is freed, the new free block is connected to its adjacent free - blocks if possible. - - [ free block ][ used block ][ free block ] - and "used block" is freed, the three blocks are connected together: - [ one big free block ] -*/ - -/* --------------------------------------------------------------------- */ -/* System (OS) functions */ -/* --------------------------------------------------------------------- */ - -/* 64 KByte. */ -#define CHUNK_SIZE (sljit_uw)0x10000 - -struct chunk_header { - void *executable; -}; - -/* - alloc_chunk / free_chunk : - * allocate executable system memory chunks - * the size is always divisible by CHUNK_SIZE - SLJIT_ALLOCATOR_LOCK / SLJIT_ALLOCATOR_UNLOCK : - * provided as part of sljitUtils - * only the allocator requires this lock, sljit is fully thread safe - as it only uses local variables -*/ - -#ifndef __NetBSD__ -#include -#include -#include -#include - -#ifndef O_NOATIME -#define O_NOATIME 0 -#endif - -/* this is a linux extension available since kernel 3.11 */ -#ifndef O_TMPFILE -#define O_TMPFILE 020200000 -#endif - -#ifndef _GNU_SOURCE -char *secure_getenv(const char *name); -int mkostemp(char *template, int flags); -#endif - -static SLJIT_INLINE int create_tempfile(void) -{ - int fd; - char tmp_name[256]; - size_t tmp_name_len = 0; - char *dir; - struct stat st; -#if defined(SLJIT_SINGLE_THREADED) && SLJIT_SINGLE_THREADED - mode_t mode; -#endif - -#ifdef HAVE_MEMFD_CREATE - /* this is a GNU extension, make sure to use -D_GNU_SOURCE */ - fd = memfd_create("sljit", MFD_CLOEXEC); - if (fd != -1) { - fchmod(fd, 0); - return fd; - } -#endif - - dir = secure_getenv("TMPDIR"); - - if (dir) { - tmp_name_len = strlen(dir); - if (tmp_name_len > 0 && tmp_name_len < sizeof(tmp_name)) { - if ((stat(dir, &st) == 0) && S_ISDIR(st.st_mode)) - strcpy(tmp_name, dir); - } - } - -#ifdef P_tmpdir - if (!tmp_name_len) { - tmp_name_len = strlen(P_tmpdir); - if (tmp_name_len > 0 && tmp_name_len < sizeof(tmp_name)) - strcpy(tmp_name, P_tmpdir); - } -#endif - if (!tmp_name_len) { - strcpy(tmp_name, "/tmp"); - tmp_name_len = 4; - } - - SLJIT_ASSERT(tmp_name_len > 0 && tmp_name_len < sizeof(tmp_name)); - - if (tmp_name[tmp_name_len - 1] == '/') - tmp_name[--tmp_name_len] = '\0'; - -#ifdef __linux__ - /* - * the previous trimming might had left an empty string if TMPDIR="/" - * so work around the problem below - */ - fd = open(tmp_name_len ? tmp_name : "/", - O_TMPFILE | O_EXCL | O_RDWR | O_NOATIME | O_CLOEXEC, 0); - if (fd != -1) - return fd; -#endif - - if (tmp_name_len + 7 >= sizeof(tmp_name)) - return -1; - - strcpy(tmp_name + tmp_name_len, "/XXXXXX"); -#if defined(SLJIT_SINGLE_THREADED) && SLJIT_SINGLE_THREADED - mode = umask(0777); -#endif - fd = mkostemp(tmp_name, O_CLOEXEC | O_NOATIME); -#if defined(SLJIT_SINGLE_THREADED) && SLJIT_SINGLE_THREADED - umask(mode); -#else - fchmod(fd, 0); -#endif - - if (fd == -1) - return -1; - - if (unlink(tmp_name)) { - close(fd); - return -1; - } - - return fd; -} - -static SLJIT_INLINE struct chunk_header* alloc_chunk(sljit_uw size) -{ - struct chunk_header *retval; - int fd; - - fd = create_tempfile(); - if (fd == -1) - return NULL; - - if (ftruncate(fd, (off_t)size)) { - close(fd); - return NULL; - } - - retval = (struct chunk_header *)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - - if (retval == MAP_FAILED) { - close(fd); - return NULL; - } - - retval->executable = mmap(NULL, size, PROT_READ | PROT_EXEC, MAP_SHARED, fd, 0); - - if (retval->executable == MAP_FAILED) { - munmap((void *)retval, size); - close(fd); - return NULL; - } - - close(fd); - return retval; -} -#else -/* - * MAP_REMAPDUP is a NetBSD extension available sinde 8.0, make sure to - * adjust your feature macros (ex: -D_NETBSD_SOURCE) as needed - */ -static SLJIT_INLINE struct chunk_header* alloc_chunk(sljit_uw size) -{ - struct chunk_header *retval; - - retval = (struct chunk_header *)mmap(NULL, size, - PROT_READ | PROT_WRITE | PROT_MPROTECT(PROT_EXEC), - MAP_ANON | MAP_SHARED, -1, 0); - - if (retval == MAP_FAILED) - return NULL; - - retval->executable = mremap(retval, size, NULL, size, MAP_REMAPDUP); - if (retval->executable == MAP_FAILED) { - munmap((void *)retval, size); - return NULL; - } - - if (mprotect(retval->executable, size, PROT_READ | PROT_EXEC) == -1) { - munmap(retval->executable, size); - munmap((void *)retval, size); - return NULL; - } - - return retval; -} -#endif /* NetBSD */ - -static SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size) -{ - struct chunk_header *header = ((struct chunk_header *)chunk) - 1; - - munmap(header->executable, size); - munmap((void *)header, size); -} - -/* --------------------------------------------------------------------- */ -/* Common functions */ -/* --------------------------------------------------------------------- */ - -#define CHUNK_MASK (~(CHUNK_SIZE - 1)) - -struct block_header { - sljit_uw size; - sljit_uw prev_size; - sljit_sw executable_offset; -}; - -struct free_block { - struct block_header header; - struct free_block *next; - struct free_block *prev; - sljit_uw size; -}; - -#define AS_BLOCK_HEADER(base, offset) \ - ((struct block_header*)(((sljit_u8*)base) + offset)) -#define AS_FREE_BLOCK(base, offset) \ - ((struct free_block*)(((sljit_u8*)base) + offset)) -#define MEM_START(base) ((void*)((base) + 1)) -#define ALIGN_SIZE(size) (((size) + sizeof(struct block_header) + 7u) & ~(sljit_uw)7) - -static struct free_block* free_blocks; -static sljit_uw allocated_size; -static sljit_uw total_size; - -static SLJIT_INLINE void sljit_insert_free_block(struct free_block *free_block, sljit_uw size) -{ - free_block->header.size = 0; - free_block->size = size; - - free_block->next = free_blocks; - free_block->prev = NULL; - if (free_blocks) - free_blocks->prev = free_block; - free_blocks = free_block; -} - -static SLJIT_INLINE void sljit_remove_free_block(struct free_block *free_block) -{ - if (free_block->next) - free_block->next->prev = free_block->prev; - - if (free_block->prev) - free_block->prev->next = free_block->next; - else { - SLJIT_ASSERT(free_blocks == free_block); - free_blocks = free_block->next; - } -} - -SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size) -{ - struct chunk_header *chunk_header; - struct block_header *header; - struct block_header *next_header; - struct free_block *free_block; - sljit_uw chunk_size; - sljit_sw executable_offset; - - SLJIT_ALLOCATOR_LOCK(); - if (size < (64 - sizeof(struct block_header))) - size = (64 - sizeof(struct block_header)); - size = ALIGN_SIZE(size); - - free_block = free_blocks; - while (free_block) { - if (free_block->size >= size) { - chunk_size = free_block->size; - if (chunk_size > size + 64) { - /* We just cut a block from the end of the free block. */ - chunk_size -= size; - free_block->size = chunk_size; - header = AS_BLOCK_HEADER(free_block, chunk_size); - header->prev_size = chunk_size; - header->executable_offset = free_block->header.executable_offset; - AS_BLOCK_HEADER(header, size)->prev_size = size; - } - else { - sljit_remove_free_block(free_block); - header = (struct block_header*)free_block; - size = chunk_size; - } - allocated_size += size; - header->size = size; - SLJIT_ALLOCATOR_UNLOCK(); - return MEM_START(header); - } - free_block = free_block->next; - } - - chunk_size = sizeof(struct chunk_header) + sizeof(struct block_header); - chunk_size = (chunk_size + size + CHUNK_SIZE - 1) & CHUNK_MASK; - - chunk_header = alloc_chunk(chunk_size); - if (!chunk_header) { - SLJIT_ALLOCATOR_UNLOCK(); - return NULL; - } - - executable_offset = (sljit_sw)((sljit_u8*)chunk_header->executable - (sljit_u8*)chunk_header); - - chunk_size -= sizeof(struct chunk_header) + sizeof(struct block_header); - total_size += chunk_size; - - header = (struct block_header *)(chunk_header + 1); - - header->prev_size = 0; - header->executable_offset = executable_offset; - if (chunk_size > size + 64) { - /* Cut the allocated space into a free and a used block. */ - allocated_size += size; - header->size = size; - chunk_size -= size; - - free_block = AS_FREE_BLOCK(header, size); - free_block->header.prev_size = size; - free_block->header.executable_offset = executable_offset; - sljit_insert_free_block(free_block, chunk_size); - next_header = AS_BLOCK_HEADER(free_block, chunk_size); - } - else { - /* All space belongs to this allocation. */ - allocated_size += chunk_size; - header->size = chunk_size; - next_header = AS_BLOCK_HEADER(header, chunk_size); - } - next_header->size = 1; - next_header->prev_size = chunk_size; - next_header->executable_offset = executable_offset; - SLJIT_ALLOCATOR_UNLOCK(); - return MEM_START(header); -} - -SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr) -{ - struct block_header *header; - struct free_block* free_block; - - SLJIT_ALLOCATOR_LOCK(); - header = AS_BLOCK_HEADER(ptr, -(sljit_sw)sizeof(struct block_header)); - header = AS_BLOCK_HEADER(header, -header->executable_offset); - allocated_size -= header->size; - - /* Connecting free blocks together if possible. */ - - /* If header->prev_size == 0, free_block will equal to header. - In this case, free_block->header.size will be > 0. */ - free_block = AS_FREE_BLOCK(header, -(sljit_sw)header->prev_size); - if (SLJIT_UNLIKELY(!free_block->header.size)) { - free_block->size += header->size; - header = AS_BLOCK_HEADER(free_block, free_block->size); - header->prev_size = free_block->size; - } - else { - free_block = (struct free_block*)header; - sljit_insert_free_block(free_block, header->size); - } - - header = AS_BLOCK_HEADER(free_block, free_block->size); - if (SLJIT_UNLIKELY(!header->size)) { - free_block->size += ((struct free_block*)header)->size; - sljit_remove_free_block((struct free_block*)header); - header = AS_BLOCK_HEADER(free_block, free_block->size); - header->prev_size = free_block->size; - } - - /* The whole chunk is free. */ - if (SLJIT_UNLIKELY(!free_block->header.prev_size && header->size == 1)) { - /* If this block is freed, we still have (allocated_size / 2) free space. */ - if (total_size - free_block->size > (allocated_size * 3 / 2)) { - total_size -= free_block->size; - sljit_remove_free_block(free_block); - free_chunk(free_block, free_block->size + - sizeof(struct chunk_header) + - sizeof(struct block_header)); - } - } - - SLJIT_ALLOCATOR_UNLOCK(); -} - -SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void) -{ - struct free_block* free_block; - struct free_block* next_free_block; - - SLJIT_ALLOCATOR_LOCK(); - - free_block = free_blocks; - while (free_block) { - next_free_block = free_block->next; - if (!free_block->header.prev_size && - AS_BLOCK_HEADER(free_block, free_block->size)->size == 1) { - total_size -= free_block->size; - sljit_remove_free_block(free_block); - free_chunk(free_block, free_block->size + - sizeof(struct chunk_header) + - sizeof(struct block_header)); - } - free_block = next_free_block; - } - - SLJIT_ASSERT((total_size && free_blocks) || (!total_size && !free_blocks)); - SLJIT_ALLOCATOR_UNLOCK(); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr) -{ - return ((struct block_header *)(ptr))[-1].executable_offset; -} diff --git a/modules/regex/pcre2/src/sljit/sljitUtils.c b/modules/regex/pcre2/src/sljit/sljitUtils.c deleted file mode 100644 index 967593b..0000000 --- a/modules/regex/pcre2/src/sljit/sljitUtils.c +++ /dev/null @@ -1,344 +0,0 @@ -/* - * 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. - */ - -/* ------------------------------------------------------------------------ */ -/* Locks */ -/* ------------------------------------------------------------------------ */ - -/* Executable Allocator */ - -#if (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR) \ - && !(defined SLJIT_WX_EXECUTABLE_ALLOCATOR && SLJIT_WX_EXECUTABLE_ALLOCATOR) -#if (defined SLJIT_SINGLE_THREADED && SLJIT_SINGLE_THREADED) -#define SLJIT_ALLOCATOR_LOCK() -#define SLJIT_ALLOCATOR_UNLOCK() -#elif !(defined _WIN32) -#include - -static pthread_mutex_t allocator_lock = PTHREAD_MUTEX_INITIALIZER; - -#define SLJIT_ALLOCATOR_LOCK() pthread_mutex_lock(&allocator_lock) -#define SLJIT_ALLOCATOR_UNLOCK() pthread_mutex_unlock(&allocator_lock) -#else /* windows */ -static HANDLE allocator_lock; - -static SLJIT_INLINE void allocator_grab_lock(void) -{ - HANDLE lock; - if (SLJIT_UNLIKELY(!InterlockedCompareExchangePointer(&allocator_lock, NULL, NULL))) { - lock = CreateMutex(NULL, FALSE, NULL); - if (InterlockedCompareExchangePointer(&allocator_lock, lock, NULL)) - CloseHandle(lock); - } - WaitForSingleObject(allocator_lock, INFINITE); -} - -#define SLJIT_ALLOCATOR_LOCK() allocator_grab_lock() -#define SLJIT_ALLOCATOR_UNLOCK() ReleaseMutex(allocator_lock) -#endif /* thread implementation */ -#endif /* SLJIT_EXECUTABLE_ALLOCATOR && !SLJIT_WX_EXECUTABLE_ALLOCATOR */ - -/* ------------------------------------------------------------------------ */ -/* Stack */ -/* ------------------------------------------------------------------------ */ - -#if ((defined SLJIT_UTIL_STACK && SLJIT_UTIL_STACK) \ - && !(defined SLJIT_UTIL_SIMPLE_STACK_ALLOCATION && SLJIT_UTIL_SIMPLE_STACK_ALLOCATION)) \ - || ((defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR) \ - && !((defined SLJIT_PROT_EXECUTABLE_ALLOCATOR && SLJIT_PROT_EXECUTABLE_ALLOCATOR) \ - || (defined SLJIT_WX_EXECUTABLE_ALLOCATOR && SLJIT_WX_EXECUTABLE_ALLOCATOR))) - -#ifndef _WIN32 -/* Provides mmap function. */ -#include -#include - -#ifndef MAP_ANON -#ifdef MAP_ANONYMOUS -#define MAP_ANON MAP_ANONYMOUS -#endif /* MAP_ANONYMOUS */ -#endif /* !MAP_ANON */ - -#ifndef MAP_ANON - -#include - -#ifdef O_CLOEXEC -#define SLJIT_CLOEXEC O_CLOEXEC -#else /* !O_CLOEXEC */ -#define SLJIT_CLOEXEC 0 -#endif /* O_CLOEXEC */ - -/* Some old systems do not have MAP_ANON. */ -static int dev_zero = -1; - -#if (defined SLJIT_SINGLE_THREADED && SLJIT_SINGLE_THREADED) - -static SLJIT_INLINE int open_dev_zero(void) -{ - dev_zero = open("/dev/zero", O_RDWR | SLJIT_CLOEXEC); - - return dev_zero < 0; -} - -#else /* !SLJIT_SINGLE_THREADED */ - -#include - -static pthread_mutex_t dev_zero_mutex = PTHREAD_MUTEX_INITIALIZER; - -static SLJIT_INLINE int open_dev_zero(void) -{ - pthread_mutex_lock(&dev_zero_mutex); - if (SLJIT_UNLIKELY(dev_zero < 0)) - dev_zero = open("/dev/zero", O_RDWR | SLJIT_CLOEXEC); - - pthread_mutex_unlock(&dev_zero_mutex); - return dev_zero < 0; -} - -#endif /* SLJIT_SINGLE_THREADED */ -#undef SLJIT_CLOEXEC -#endif /* !MAP_ANON */ -#endif /* !_WIN32 */ -#endif /* open_dev_zero */ - -#if (defined SLJIT_UTIL_STACK && SLJIT_UTIL_STACK) \ - || (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR) - -#ifdef _WIN32 - -static SLJIT_INLINE sljit_uw get_page_alignment(void) { - SYSTEM_INFO si; - static sljit_uw sljit_page_align = 0; - if (!sljit_page_align) { - GetSystemInfo(&si); - sljit_page_align = (sljit_uw)si.dwPageSize - 1; - } - return sljit_page_align; -} - -#else - -#include - -static SLJIT_INLINE sljit_uw get_page_alignment(void) { - static sljit_uw sljit_page_align = 0; - - sljit_sw align; - - if (!sljit_page_align) { -#ifdef _SC_PAGESIZE - align = sysconf(_SC_PAGESIZE); -#else - align = getpagesize(); -#endif - /* Should never happen. */ - if (align < 0) - align = 4096; - sljit_page_align = (sljit_uw)align - 1; - } - return sljit_page_align; -} - -#endif /* _WIN32 */ - -#endif /* get_page_alignment() */ - -#if (defined SLJIT_UTIL_STACK && SLJIT_UTIL_STACK) - -#if (defined SLJIT_UTIL_SIMPLE_STACK_ALLOCATION && SLJIT_UTIL_SIMPLE_STACK_ALLOCATION) - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_stack* SLJIT_FUNC sljit_allocate_stack(sljit_uw start_size, sljit_uw max_size, void *allocator_data) -{ - struct sljit_stack *stack; - void *ptr; - - SLJIT_UNUSED_ARG(allocator_data); - - if (start_size > max_size || start_size < 1) - return NULL; - - stack = (struct sljit_stack*)SLJIT_MALLOC(sizeof(struct sljit_stack), allocator_data); - if (stack == NULL) - return NULL; - - ptr = SLJIT_MALLOC(max_size, allocator_data); - if (ptr == NULL) { - SLJIT_FREE(stack, allocator_data); - return NULL; - } - - stack->min_start = (sljit_u8 *)ptr; - stack->end = stack->min_start + max_size; - stack->start = stack->end - start_size; - stack->top = stack->end; - return stack; -} - -SLJIT_API_FUNC_ATTRIBUTE void SLJIT_FUNC sljit_free_stack(struct sljit_stack *stack, void *allocator_data) -{ - SLJIT_UNUSED_ARG(allocator_data); - SLJIT_FREE((void*)stack->min_start, allocator_data); - SLJIT_FREE(stack, allocator_data); -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_u8 *SLJIT_FUNC sljit_stack_resize(struct sljit_stack *stack, sljit_u8 *new_start) -{ - if ((new_start < stack->min_start) || (new_start >= stack->end)) - return NULL; - stack->start = new_start; - return new_start; -} - -#else /* !SLJIT_UTIL_SIMPLE_STACK_ALLOCATION */ - -#ifdef _WIN32 - -SLJIT_API_FUNC_ATTRIBUTE void SLJIT_FUNC sljit_free_stack(struct sljit_stack *stack, void *allocator_data) -{ - SLJIT_UNUSED_ARG(allocator_data); - VirtualFree((void*)stack->min_start, 0, MEM_RELEASE); - SLJIT_FREE(stack, allocator_data); -} - -#else /* !_WIN32 */ - -SLJIT_API_FUNC_ATTRIBUTE void SLJIT_FUNC sljit_free_stack(struct sljit_stack *stack, void *allocator_data) -{ - SLJIT_UNUSED_ARG(allocator_data); - munmap((void*)stack->min_start, (size_t)(stack->end - stack->min_start)); - SLJIT_FREE(stack, allocator_data); -} - -#endif /* _WIN32 */ - -SLJIT_API_FUNC_ATTRIBUTE struct sljit_stack* SLJIT_FUNC sljit_allocate_stack(sljit_uw start_size, sljit_uw max_size, void *allocator_data) -{ - struct sljit_stack *stack; - void *ptr; - sljit_uw page_align; - - SLJIT_UNUSED_ARG(allocator_data); - - if (start_size > max_size || start_size < 1) - return NULL; - - stack = (struct sljit_stack*)SLJIT_MALLOC(sizeof(struct sljit_stack), allocator_data); - if (stack == NULL) - return NULL; - - /* Align max_size. */ - page_align = get_page_alignment(); - max_size = (max_size + page_align) & ~page_align; - -#ifdef _WIN32 - ptr = VirtualAlloc(NULL, max_size, MEM_RESERVE, PAGE_READWRITE); - if (!ptr) { - SLJIT_FREE(stack, allocator_data); - return NULL; - } - - stack->min_start = (sljit_u8 *)ptr; - stack->end = stack->min_start + max_size; - stack->start = stack->end; - - if (sljit_stack_resize(stack, stack->end - start_size) == NULL) { - sljit_free_stack(stack, allocator_data); - return NULL; - } -#else /* !_WIN32 */ -#ifdef MAP_ANON - ptr = mmap(NULL, max_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); -#else /* !MAP_ANON */ - if (SLJIT_UNLIKELY((dev_zero < 0) && open_dev_zero())) { - SLJIT_FREE(stack, allocator_data); - return NULL; - } - ptr = mmap(NULL, max_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, dev_zero, 0); -#endif /* MAP_ANON */ - if (ptr == MAP_FAILED) { - SLJIT_FREE(stack, allocator_data); - return NULL; - } - stack->min_start = (sljit_u8 *)ptr; - stack->end = stack->min_start + max_size; - stack->start = stack->end - start_size; -#endif /* _WIN32 */ - - stack->top = stack->end; - return stack; -} - -SLJIT_API_FUNC_ATTRIBUTE sljit_u8 *SLJIT_FUNC sljit_stack_resize(struct sljit_stack *stack, sljit_u8 *new_start) -{ -#if defined _WIN32 || defined(POSIX_MADV_DONTNEED) - sljit_uw aligned_old_start; - sljit_uw aligned_new_start; - sljit_uw page_align; -#endif - - if ((new_start < stack->min_start) || (new_start >= stack->end)) - return NULL; - -#ifdef _WIN32 - page_align = get_page_alignment(); - - aligned_new_start = (sljit_uw)new_start & ~page_align; - aligned_old_start = ((sljit_uw)stack->start) & ~page_align; - if (aligned_new_start != aligned_old_start) { - if (aligned_new_start < aligned_old_start) { - if (!VirtualAlloc((void*)aligned_new_start, aligned_old_start - aligned_new_start, MEM_COMMIT, PAGE_READWRITE)) - return NULL; - } - else { - if (!VirtualFree((void*)aligned_old_start, aligned_new_start - aligned_old_start, MEM_DECOMMIT)) - return NULL; - } - } -#elif defined(POSIX_MADV_DONTNEED) - if (stack->start < new_start) { - page_align = get_page_alignment(); - - aligned_new_start = (sljit_uw)new_start & ~page_align; - aligned_old_start = ((sljit_uw)stack->start) & ~page_align; - - if (aligned_new_start > aligned_old_start) { - posix_madvise((void*)aligned_old_start, aligned_new_start - aligned_old_start, POSIX_MADV_DONTNEED); -#ifdef MADV_FREE - madvise((void*)aligned_old_start, aligned_new_start - aligned_old_start, MADV_FREE); -#endif /* MADV_FREE */ - } - } -#endif /* _WIN32 */ - - stack->start = new_start; - return new_start; -} - -#endif /* SLJIT_UTIL_SIMPLE_STACK_ALLOCATION */ - -#endif /* SLJIT_UTIL_STACK */ diff --git a/modules/regex/pcre2/src/sljit/sljitWXExecAllocator.c b/modules/regex/pcre2/src/sljit/sljitWXExecAllocator.c deleted file mode 100644 index 6893813..0000000 --- a/modules/regex/pcre2/src/sljit/sljitWXExecAllocator.c +++ /dev/null @@ -1,204 +0,0 @@ -/* - * 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. - */ - -/* - This file contains a simple W^X executable memory allocator for POSIX - like systems and Windows - - In *NIX, MAP_ANON is required (that is considered a feature) so make - sure to set the right availability macros for your system or the code - will fail to build. - - If your system doesn't support mapping of anonymous pages (ex: IRIX) it - is also likely that it doesn't need this allocator and should be using - the standard one instead. - - It allocates a separate map for each code block and may waste a lot of - memory, because whatever was requested, will be rounded up to the page - size (minimum 4KB, but could be even bigger). - - It changes the page permissions (RW <-> RX) as needed and therefore, if you - will be updating the code after it has been generated, need to make sure to - block any concurrent execution, or could result in a SIGBUS, that could - even manifest itself at a different address than the one that was being - modified. - - Only use if you are unable to use the regular allocator because of security - restrictions and adding exceptions to your application or the system are - not possible. -*/ - -#define SLJIT_UPDATE_WX_FLAGS(from, to, enable_exec) \ - sljit_update_wx_flags((from), (to), (enable_exec)) - -#ifndef _WIN32 -#include -#include - -#ifdef __NetBSD__ -#define SLJIT_PROT_WX PROT_MPROTECT(PROT_EXEC) -#define check_se_protected(ptr, size) (0) -#else /* POSIX */ -#if !(defined SLJIT_SINGLE_THREADED && SLJIT_SINGLE_THREADED) -#include -#define SLJIT_SE_LOCK() pthread_mutex_lock(&se_lock) -#define SLJIT_SE_UNLOCK() pthread_mutex_unlock(&se_lock) -#endif /* !SLJIT_SINGLE_THREADED */ - -#define check_se_protected(ptr, size) generic_se_protected(ptr, size) - -static SLJIT_INLINE int generic_se_protected(void *ptr, sljit_uw size) -{ - if (SLJIT_LIKELY(!mprotect(ptr, size, PROT_EXEC))) - return mprotect(ptr, size, PROT_READ | PROT_WRITE); - - return -1; -} -#endif /* NetBSD */ - -#ifndef SLJIT_SE_LOCK -#define SLJIT_SE_LOCK() -#endif -#ifndef SLJIT_SE_UNLOCK -#define SLJIT_SE_UNLOCK() -#endif -#ifndef SLJIT_PROT_WX -#define SLJIT_PROT_WX 0 -#endif - -SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size) -{ -#if !(defined SLJIT_SINGLE_THREADED && SLJIT_SINGLE_THREADED) \ - && !defined(__NetBSD__) - static pthread_mutex_t se_lock = PTHREAD_MUTEX_INITIALIZER; -#endif - static int se_protected = !SLJIT_PROT_WX; - int prot = PROT_READ | PROT_WRITE | SLJIT_PROT_WX; - sljit_uw* ptr; - - if (SLJIT_UNLIKELY(se_protected < 0)) - return NULL; - -#ifdef PROT_MAX - prot |= PROT_MAX(PROT_READ | PROT_WRITE | PROT_EXEC); -#endif - - size += sizeof(sljit_uw); - ptr = (sljit_uw*)mmap(NULL, size, prot, MAP_PRIVATE | MAP_ANON, -1, 0); - - if (ptr == MAP_FAILED) - return NULL; - - if (SLJIT_UNLIKELY(se_protected > 0)) { - SLJIT_SE_LOCK(); - se_protected = check_se_protected(ptr, size); - SLJIT_SE_UNLOCK(); - if (SLJIT_UNLIKELY(se_protected < 0)) { - munmap((void *)ptr, size); - return NULL; - } - } - - *ptr++ = size; - return ptr; -} - -#undef SLJIT_PROT_WX -#undef SLJIT_SE_UNLOCK -#undef SLJIT_SE_LOCK - -SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr) -{ - sljit_uw *start_ptr = ((sljit_uw*)ptr) - 1; - munmap((void*)start_ptr, *start_ptr); -} - -static void sljit_update_wx_flags(void *from, void *to, sljit_s32 enable_exec) -{ - sljit_uw page_mask = (sljit_uw)get_page_alignment(); - sljit_uw start = (sljit_uw)from; - sljit_uw end = (sljit_uw)to; - int prot = PROT_READ | (enable_exec ? PROT_EXEC : PROT_WRITE); - - SLJIT_ASSERT(start < end); - - start &= ~page_mask; - end = (end + page_mask) & ~page_mask; - - mprotect((void*)start, end - start, prot); -} - -#else /* windows */ - -SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size) -{ - sljit_uw *ptr; - - size += sizeof(sljit_uw); - ptr = (sljit_uw*)VirtualAlloc(NULL, size, - MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); - - if (!ptr) - return NULL; - - *ptr++ = size; - - return ptr; -} - -SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr) -{ - sljit_uw start = (sljit_uw)ptr - sizeof(sljit_uw); -#if defined(SLJIT_DEBUG) && SLJIT_DEBUG - sljit_uw page_mask = (sljit_uw)get_page_alignment(); - - SLJIT_ASSERT(!(start & page_mask)); -#endif - VirtualFree((void*)start, 0, MEM_RELEASE); -} - -static void sljit_update_wx_flags(void *from, void *to, sljit_s32 enable_exec) -{ - DWORD oldprot; - sljit_uw page_mask = (sljit_uw)get_page_alignment(); - sljit_uw start = (sljit_uw)from; - sljit_uw end = (sljit_uw)to; - DWORD prot = enable_exec ? PAGE_EXECUTE : PAGE_READWRITE; - - SLJIT_ASSERT(start < end); - - start &= ~page_mask; - end = (end + page_mask) & ~page_mask; - - VirtualProtect((void*)start, end - start, prot, &oldprot); -} - -#endif /* !windows */ - -SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void) -{ - /* This allocator does not keep unused memory for future allocations. */ -} diff --git a/modules/regex/regex.cpp b/modules/regex/regex.cpp deleted file mode 100644 index d4f5c2e..0000000 --- a/modules/regex/regex.cpp +++ /dev/null @@ -1,407 +0,0 @@ -/*************************************************************************/ -/* regex.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "regex.h" -#include "core/os/memory.h" - -extern "C" { -#include -} - -static void *_regex_malloc(PCRE2_SIZE size, void *user) { - return memalloc(size); -} - -static void _regex_free(void *ptr, void *user) { - if (ptr) { - memfree(ptr); - } -} - -int RegExMatch::_find(const Variant &p_name) const { - if (p_name.is_num()) { - int i = (int)p_name; - if (i >= data.size()) { - return -1; - } - return i; - - } else if (p_name.get_type() == Variant::STRING) { - const RBMap::Element *found = names.find((String)p_name); - if (found) { - return found->value(); - } - } - - return -1; -} - -String RegExMatch::get_subject() const { - return subject; -} - -int RegExMatch::get_group_count() const { - if (data.size() == 0) { - return 0; - } - return data.size() - 1; -} - -Dictionary RegExMatch::get_names() const { - Dictionary result; - - for (const RBMap::Element *i = names.front(); i != nullptr; i = i->next()) { - result[i->key()] = i->value(); - } - - return result; -} - -Array RegExMatch::get_strings() const { - Array result; - - int size = data.size(); - - for (int i = 0; i < size; i++) { - int start = data[i].start; - - if (start == -1) { - result.append(String()); - continue; - } - - int length = data[i].end - start; - - result.append(subject.substr(start, length)); - } - - return result; -} - -String RegExMatch::get_string(const Variant &p_name) const { - int id = _find(p_name); - - if (id < 0) { - return String(); - } - - int start = data[id].start; - - if (start == -1) { - return String(); - } - - int length = data[id].end - start; - - return subject.substr(start, length); -} - -int RegExMatch::get_start(const Variant &p_name) const { - int id = _find(p_name); - - if (id < 0) { - return -1; - } - - return data[id].start; -} - -int RegExMatch::get_end(const Variant &p_name) const { - int id = _find(p_name); - - if (id < 0) { - return -1; - } - - return data[id].end; -} - -void RegExMatch::_bind_methods() { - ClassDB::bind_method(D_METHOD("get_subject"), &RegExMatch::get_subject); - ClassDB::bind_method(D_METHOD("get_group_count"), &RegExMatch::get_group_count); - ClassDB::bind_method(D_METHOD("get_names"), &RegExMatch::get_names); - ClassDB::bind_method(D_METHOD("get_strings"), &RegExMatch::get_strings); - ClassDB::bind_method(D_METHOD("get_string", "name"), &RegExMatch::get_string, DEFVAL(0)); - ClassDB::bind_method(D_METHOD("get_start", "name"), &RegExMatch::get_start, DEFVAL(0)); - ClassDB::bind_method(D_METHOD("get_end", "name"), &RegExMatch::get_end, DEFVAL(0)); - - ADD_PROPERTY(PropertyInfo(Variant::STRING, "subject"), "", "get_subject"); - ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "names"), "", "get_names"); - ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "strings"), "", "get_strings"); -} - -void RegEx::_pattern_info(uint32_t what, void *where) const { - pcre2_pattern_info_32((pcre2_code_32 *)code, what, where); -} - -void RegEx::clear() { - if (code) { - pcre2_code_free_32((pcre2_code_32 *)code); - code = nullptr; - } -} - -Error RegEx::compile(const String &p_pattern) { - pattern = p_pattern; - clear(); - - int err; - PCRE2_SIZE offset; - uint32_t flags = PCRE2_DUPNAMES; - - pcre2_general_context_32 *gctx = (pcre2_general_context_32 *)general_ctx; - pcre2_compile_context_32 *cctx = pcre2_compile_context_create_32(gctx); - PCRE2_SPTR32 p = (PCRE2_SPTR32)pattern.get_data(); - - code = pcre2_compile_32(p, pattern.length(), flags, &err, &offset, cctx); - - pcre2_compile_context_free_32(cctx); - - if (!code) { - PCRE2_UCHAR32 buf[256]; - pcre2_get_error_message_32(err, buf, 256); - String message = String::num(offset) + ": " + String((const CharType *)buf); - ERR_PRINT(message.utf8()); - return FAILED; - } - - return OK; -} - -Ref RegEx::search(const String &p_subject, int p_offset, int p_end) const { - ERR_FAIL_COND_V(!is_valid(), nullptr); - - Ref result = memnew(RegExMatch); - - int length = p_subject.length(); - if (p_end >= 0 && p_end < length) { - length = p_end; - } - - { - pcre2_code_32 *c = (pcre2_code_32 *)code; - pcre2_general_context_32 *gctx = (pcre2_general_context_32 *)general_ctx; - pcre2_match_context_32 *mctx = pcre2_match_context_create_32(gctx); - PCRE2_SPTR32 s = (PCRE2_SPTR32)p_subject.get_data(); - - pcre2_match_data_32 *match = pcre2_match_data_create_from_pattern_32(c, gctx); - - int res = pcre2_match_32(c, s, length, p_offset, 0, match, mctx); - - if (res < 0) { - pcre2_match_data_free_32(match); - pcre2_match_context_free_32(mctx); - - return nullptr; - } - - uint32_t size = pcre2_get_ovector_count_32(match); - PCRE2_SIZE *ovector = pcre2_get_ovector_pointer_32(match); - - result->data.resize(size); - - for (uint32_t i = 0; i < size; i++) { - result->data.write[i].start = ovector[i * 2]; - result->data.write[i].end = ovector[i * 2 + 1]; - } - - pcre2_match_data_free_32(match); - pcre2_match_context_free_32(mctx); - } - - result->subject = p_subject; - - uint32_t count; - const CharType *table; - uint32_t entry_size; - - _pattern_info(PCRE2_INFO_NAMECOUNT, &count); - _pattern_info(PCRE2_INFO_NAMETABLE, &table); - _pattern_info(PCRE2_INFO_NAMEENTRYSIZE, &entry_size); - - for (uint32_t i = 0; i < count; i++) { - CharType id = table[i * entry_size]; - if (result->data[id].start == -1) { - continue; - } - String name = &table[i * entry_size + 1]; - if (result->names.has(name)) { - continue; - } - - result->names.insert(name, id); - } - - return result; -} - -Array RegEx::search_all(const String &p_subject, int p_offset, int p_end) const { - int last_end = -1; - Array result; - Ref match = search(p_subject, p_offset, p_end); - while (match.is_valid()) { - if (last_end == match->get_end(0)) { - break; - } - result.push_back(match); - last_end = match->get_end(0); - match = search(p_subject, match->get_end(0), p_end); - } - return result; -} - -String RegEx::sub(const String &p_subject, const String &p_replacement, bool p_all, int p_offset, int p_end) const { - ERR_FAIL_COND_V(!is_valid(), String()); - - // safety_zone is the number of chars we allocate in addition to the number of chars expected in order to - // guard against the PCRE API writing one additional \0 at the end. PCRE's API docs are unclear on whether - // PCRE understands outlength in pcre2_substitute() as counting an implicit additional terminating char or - // not. always allocating one char more than telling PCRE has us on the safe side. - const int safety_zone = 1; - - PCRE2_SIZE olength = p_subject.length() + 1; // space for output string and one terminating \0 character - Vector output; - output.resize(olength + safety_zone); - - uint32_t flags = PCRE2_SUBSTITUTE_OVERFLOW_LENGTH; - if (p_all) { - flags |= PCRE2_SUBSTITUTE_GLOBAL; - } - - PCRE2_SIZE length = p_subject.length(); - if (p_end >= 0 && (uint32_t)p_end < length) { - length = p_end; - } - - { - pcre2_code_32 *c = (pcre2_code_32 *)code; - pcre2_general_context_32 *gctx = (pcre2_general_context_32 *)general_ctx; - pcre2_match_context_32 *mctx = pcre2_match_context_create_32(gctx); - PCRE2_SPTR32 s = (PCRE2_SPTR32)p_subject.get_data(); - PCRE2_SPTR32 r = (PCRE2_SPTR32)p_replacement.get_data(); - PCRE2_UCHAR32 *o = (PCRE2_UCHAR32 *)output.ptrw(); - - pcre2_match_data_32 *match = pcre2_match_data_create_from_pattern_32(c, gctx); - - int res = pcre2_substitute_32(c, s, length, p_offset, flags, match, mctx, r, p_replacement.length(), o, &olength); - - if (res == PCRE2_ERROR_NOMEMORY) { - output.resize(olength + safety_zone); - o = (PCRE2_UCHAR32 *)output.ptrw(); - res = pcre2_substitute_32(c, s, length, p_offset, flags, match, mctx, r, p_replacement.length(), o, &olength); - } - - pcre2_match_data_free_32(match); - pcre2_match_context_free_32(mctx); - - if (res < 0) { - return String(); - } - } - - return String(output.ptr(), olength); -} - -bool RegEx::is_valid() const { - return (code != nullptr); -} - -String RegEx::get_pattern() const { - return pattern; -} - -int RegEx::get_group_count() const { - ERR_FAIL_COND_V(!is_valid(), 0); - - uint32_t count; - - _pattern_info(PCRE2_INFO_CAPTURECOUNT, &count); - - return count; -} - -Array RegEx::get_names() const { - Array result; - - ERR_FAIL_COND_V(!is_valid(), result); - - uint32_t count; - const CharType *table; - uint32_t entry_size; - - _pattern_info(PCRE2_INFO_NAMECOUNT, &count); - _pattern_info(PCRE2_INFO_NAMETABLE, &table); - _pattern_info(PCRE2_INFO_NAMEENTRYSIZE, &entry_size); - - for (uint32_t i = 0; i < count; i++) { - String name = &table[i * entry_size + 1]; - if (result.find(name) < 0) { - result.append(name); - } - } - - return result; -} - -RegEx::RegEx() { - { - general_ctx = pcre2_general_context_create_32(&_regex_malloc, &_regex_free, nullptr); - } - code = nullptr; -} - -RegEx::RegEx(const String &p_pattern) { - { - general_ctx = pcre2_general_context_create_32(&_regex_malloc, &_regex_free, nullptr); - } - code = nullptr; - compile(p_pattern); -} - -RegEx::~RegEx() { - { - if (code) { - pcre2_code_free_32((pcre2_code_32 *)code); - } - pcre2_general_context_free_32((pcre2_general_context_32 *)general_ctx); - } -} - -void RegEx::_bind_methods() { - ClassDB::bind_method(D_METHOD("clear"), &RegEx::clear); - ClassDB::bind_method(D_METHOD("compile", "pattern"), &RegEx::compile); - ClassDB::bind_method(D_METHOD("search", "subject", "offset", "end"), &RegEx::search, DEFVAL(0), DEFVAL(-1)); - ClassDB::bind_method(D_METHOD("search_all", "subject", "offset", "end"), &RegEx::search_all, DEFVAL(0), DEFVAL(-1)); - ClassDB::bind_method(D_METHOD("sub", "subject", "replacement", "all", "offset", "end"), &RegEx::sub, DEFVAL(false), DEFVAL(0), DEFVAL(-1)); - ClassDB::bind_method(D_METHOD("is_valid"), &RegEx::is_valid); - ClassDB::bind_method(D_METHOD("get_pattern"), &RegEx::get_pattern); - ClassDB::bind_method(D_METHOD("get_group_count"), &RegEx::get_group_count); - ClassDB::bind_method(D_METHOD("get_names"), &RegEx::get_names); -} diff --git a/modules/regex/regex.h b/modules/regex/regex.h deleted file mode 100644 index 1cfad69..0000000 --- a/modules/regex/regex.h +++ /dev/null @@ -1,100 +0,0 @@ -#ifndef REGEX_H -#define REGEX_H -/*************************************************************************/ -/* regex.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "core/variant/array.h" -#include "core/variant/dictionary.h" -#include "core/containers/rb_map.h" -#include "core/object/reference.h" -#include "core/string/ustring.h" -#include "core/containers/vector.h" - -class RegExMatch : public Reference { - GDCLASS(RegExMatch, Reference); - - struct Range { - int start; - int end; - }; - - String subject; - Vector data; - RBMap names; - - friend class RegEx; - -protected: - static void _bind_methods(); - - int _find(const Variant &p_name) const; - -public: - String get_subject() const; - int get_group_count() const; - Dictionary get_names() const; - - Array get_strings() const; - String get_string(const Variant &p_name) const; - int get_start(const Variant &p_name) const; - int get_end(const Variant &p_name) const; -}; - -class RegEx : public Reference { - GDCLASS(RegEx, Reference); - - void *general_ctx; - void *code; - String pattern; - - void _pattern_info(uint32_t what, void *where) const; - -protected: - static void _bind_methods(); - -public: - void clear(); - Error compile(const String &p_pattern); - - Ref search(const String &p_subject, int p_offset = 0, int p_end = -1) const; - Array search_all(const String &p_subject, int p_offset = 0, int p_end = -1) const; - String sub(const String &p_subject, const String &p_replacement, bool p_all = false, int p_offset = 0, int p_end = -1) const; - - bool is_valid() const; - String get_pattern() const; - int get_group_count() const; - Array get_names() const; - - RegEx(); - RegEx(const String &p_pattern); - ~RegEx(); -}; - -#endif // REGEX_H diff --git a/modules/regex/register_types.cpp b/modules/regex/register_types.cpp deleted file mode 100644 index 34de4ae..0000000 --- a/modules/regex/register_types.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/*************************************************************************/ -/* register_types.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "register_types.h" -#include "core/object/class_db.h" -#include "regex.h" - -void register_regex_types(ModuleRegistrationLevel p_level) { - if (p_level == MODULE_REGISTRATION_LEVEL_SCENE) { - ClassDB::register_class(); - ClassDB::register_class(); - } -} - -void unregister_regex_types(ModuleRegistrationLevel p_level) { -} diff --git a/modules/regex/register_types.h b/modules/regex/register_types.h deleted file mode 100644 index 6555203..0000000 --- a/modules/regex/register_types.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef REGEX_REGISTER_TYPES_H -#define REGEX_REGISTER_TYPES_H -/*************************************************************************/ -/* register_types.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "modules/register_module_types.h" - -void register_regex_types(ModuleRegistrationLevel p_level); -void unregister_regex_types(ModuleRegistrationLevel p_level); - -#endif // REGEX_REGISTER_TYPES_H diff --git a/scu_builders.py b/scu_builders.py index 48a180e..6f31064 100644 --- a/scu_builders.py +++ b/scu_builders.py @@ -324,7 +324,7 @@ def generate_scu_files(verbose, is_release_build, env): process_folder(["modules/mbedtls"]) #process_folder(["modules/regex"]) - #process_folder(["modules/regex/pcre2/src", "sljit" ], [], 0, "c") + #process_folder(["modules/regex", "pcre2/src", "pcre2/src/sljit" ], [], 0, "cpp c") #process_folder(["scene"]) #process_folder(["scene/audio"])