mirror of https://github.com/godotengine/godot
pcre2: Update to 10.47
This commit is contained in:
parent
08e6cd181f
commit
36e7675d6d
|
|
@ -22,6 +22,7 @@ if env["builtin_pcre2"]:
|
|||
"pcre2_chartables.c",
|
||||
"pcre2_chkdint.c",
|
||||
"pcre2_compile.c",
|
||||
"pcre2_compile_cgroup.c",
|
||||
"pcre2_compile_class.c",
|
||||
"pcre2_config.c",
|
||||
"pcre2_context.c",
|
||||
|
|
@ -31,10 +32,10 @@ if env["builtin_pcre2"]:
|
|||
"pcre2_extuni.c",
|
||||
"pcre2_find_bracket.c",
|
||||
"pcre2_jit_compile.c",
|
||||
# "pcre2_jit_match.c", "pcre2_jit_misc.c", # Included in `pcre2_jit_compile.c`.
|
||||
"pcre2_maketables.c",
|
||||
"pcre2_match.c",
|
||||
"pcre2_match_data.c",
|
||||
"pcre2_match_next.c",
|
||||
"pcre2_newline.c",
|
||||
"pcre2_ord2utf.c",
|
||||
"pcre2_pattern_info.c",
|
||||
|
|
@ -46,7 +47,6 @@ if env["builtin_pcre2"]:
|
|||
"pcre2_substring.c",
|
||||
"pcre2_tables.c",
|
||||
"pcre2_ucd.c",
|
||||
# "pcre2_ucptables.c", # Included in `pcre2_tables.c`.
|
||||
"pcre2_valid_utf.c",
|
||||
"pcre2_xclass.c",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -890,19 +890,20 @@ Exclude:
|
|||
Additional:
|
||||
- Update `openxrLoaderVersion` in `platform/android/java/app/config.gradle`
|
||||
|
||||
|
||||
## pcre2
|
||||
|
||||
- Upstream: http://www.pcre.org
|
||||
- Version: 10.45 (2dce7761b1831fd3f82a9c2bd5476259d945da4d, 2025)
|
||||
- Version: 10.47 (f454e231fe5006dd7ff8f4693fd2b8eb94333429, 2025)
|
||||
- License: BSD-3-Clause
|
||||
|
||||
Files extracted from upstream source:
|
||||
|
||||
- Files listed in the file `NON-AUTOTOOLS-BUILD` steps 1-4
|
||||
- All `.h` files in `src/` apart from `pcre2posix.h`
|
||||
- `src/pcre2_jit_match.c`
|
||||
- `src/pcre2_jit_misc.c`
|
||||
- `src/pcre2_ucptables.c`
|
||||
- All `.h` files in `src/` apart from `pcre2posix.h`, `pcre2_printint_inc.h`, `pcre2test_inc.h`
|
||||
- `src/pcre2_compile_cgroup.c`
|
||||
- `src/pcre2_match_next.c`
|
||||
- `src/pcre2_{jit_char,jit_match,jit_misc,jit_simd,ucptables}_inc.h`
|
||||
- `deps/sljit/sljit_src`
|
||||
- `AUTHORS.md` and `LICENCE.md`
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
PCRE2 Authorship and Contributors
|
||||
=================================
|
||||
|
||||
COPYRIGHT
|
||||
Copyright
|
||||
---------
|
||||
|
||||
Please see the file [LICENCE](./LICENCE.md) in the PCRE2 distribution for
|
||||
copyright details.
|
||||
|
||||
|
||||
MAINTAINERS
|
||||
Maintainers
|
||||
-----------
|
||||
|
||||
The PCRE and PCRE2 libraries were authored and maintained by Philip Hazel.
|
||||
|
|
@ -62,7 +62,7 @@ Both administrators are volunteers acting in a personal capacity.
|
|||
</table>
|
||||
|
||||
|
||||
CONTRIBUTORS
|
||||
Contributors
|
||||
------------
|
||||
|
||||
Many others have participated and contributed to PCRE2 over its history.
|
||||
|
|
@ -77,7 +77,7 @@ All names listed alphabetically.
|
|||
|
||||
### Contributors to PCRE2
|
||||
|
||||
This list includes names up until the PCRE2 10.44 release. New names will be
|
||||
This list includes names up until the PCRE2 10.47 release. New names will be
|
||||
added from the Git history on each release.
|
||||
|
||||
Scott Bell
|
||||
|
|
@ -93,13 +93,16 @@ added from the Git history on each release.
|
|||
Addison Crump
|
||||
Alex Dowad
|
||||
Daniel Engberg
|
||||
Marco Feuerstein
|
||||
Daniel Richard G
|
||||
Isaac Oscar Gariano
|
||||
David Gaussmann
|
||||
Andrey Gorbachev
|
||||
Jordan Griege
|
||||
Jason Hood
|
||||
Bumsu Hyeon
|
||||
Roy Ivy
|
||||
Nobuhiro Iwamatsu
|
||||
Martin Joerg
|
||||
Guillem Jover
|
||||
Ralf Junker
|
||||
|
|
@ -114,13 +117,17 @@ added from the Git history on each release.
|
|||
Kai Lu
|
||||
Behzod Mansurov
|
||||
B. Scott Michel
|
||||
Greg Minshall
|
||||
Nathan Moinvaziri
|
||||
Mike Munday
|
||||
Marc Mutz
|
||||
Fabio Pagani
|
||||
Christian Persch
|
||||
Alex Reinking
|
||||
Joshua Rogers
|
||||
Tristan Ross
|
||||
William A Rowe Jr
|
||||
Rocco Ruscitti
|
||||
David Seifert
|
||||
Yaakov Selkowitz
|
||||
Rich Siegel
|
||||
|
|
@ -131,6 +138,7 @@ added from the Git history on each release.
|
|||
Greg Thain
|
||||
Lucas Trzesniewski
|
||||
Theodore Tsirpanis
|
||||
Aaron M. Ucko
|
||||
Matthew Vernon
|
||||
Rémi Verschelde
|
||||
Thomas Voss
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
PCRE2 License
|
||||
PCRE2 Licence
|
||||
=============
|
||||
|
||||
| SPDX-License-Identifier: | BSD-3-Clause WITH PCRE2-exception |
|
||||
|
|
@ -16,7 +16,8 @@ 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 library is built. The just-in-time compiler is separately licensed under the
|
||||
"2-clause BSD" licence.
|
||||
|
||||
|
||||
COPYRIGHT
|
||||
|
|
@ -53,6 +54,8 @@ COPYRIGHT
|
|||
Copyright (c) 2009-2024 Zoltan Herczeg
|
||||
All rights reserved.
|
||||
|
||||
The code in the `deps/sljit` directory has its own LICENSE file.
|
||||
|
||||
### All other contributions
|
||||
|
||||
Many other contributors have participated in the authorship of PCRE2. As PCRE2
|
||||
|
|
@ -99,5 +102,3 @@ 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
|
||||
|
|
|
|||
|
|
@ -49,9 +49,9 @@
|
|||
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.
|
||||
The unused blocks are stored in a chain list pointed by sljit_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.
|
||||
|
|
@ -115,20 +115,20 @@ struct free_block {
|
|||
#define ALIGN_SIZE(size) (((size) + sizeof(struct block_header) + 7u) & ~(sljit_uw)7)
|
||||
#define CHUNK_EXTRA_SIZE (sizeof(struct block_header) + CHUNK_HEADER_SIZE)
|
||||
|
||||
static struct free_block* free_blocks;
|
||||
static sljit_uw allocated_size;
|
||||
static sljit_uw total_size;
|
||||
static struct free_block* sljit_free_blocks;
|
||||
static sljit_uw sljit_allocated_size;
|
||||
static sljit_uw sljit_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->next = sljit_free_blocks;
|
||||
free_block->prev = NULL;
|
||||
if (free_blocks)
|
||||
free_blocks->prev = free_block;
|
||||
free_blocks = free_block;
|
||||
if (sljit_free_blocks)
|
||||
sljit_free_blocks->prev = free_block;
|
||||
sljit_free_blocks = free_block;
|
||||
}
|
||||
|
||||
static SLJIT_INLINE void sljit_remove_free_block(struct free_block *free_block)
|
||||
|
|
@ -139,8 +139,8 @@ static SLJIT_INLINE void sljit_remove_free_block(struct free_block *free_block)
|
|||
if (free_block->prev)
|
||||
free_block->prev->next = free_block->next;
|
||||
else {
|
||||
SLJIT_ASSERT(free_blocks == free_block);
|
||||
free_blocks = free_block->next;
|
||||
SLJIT_ASSERT(sljit_free_blocks == free_block);
|
||||
sljit_free_blocks = free_block->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -166,7 +166,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size)
|
|||
size = ALIGN_SIZE(size);
|
||||
|
||||
SLJIT_ALLOCATOR_LOCK();
|
||||
free_block = free_blocks;
|
||||
free_block = sljit_free_blocks;
|
||||
while (free_block) {
|
||||
if (free_block->size >= size) {
|
||||
chunk_size = free_block->size;
|
||||
|
|
@ -186,7 +186,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size)
|
|||
header = (struct block_header*)free_block;
|
||||
size = chunk_size;
|
||||
}
|
||||
allocated_size += size;
|
||||
sljit_allocated_size += size;
|
||||
header->size = size;
|
||||
SLJIT_ALLOCATOR_UNLOCK();
|
||||
return MEM_START(header);
|
||||
|
|
@ -207,7 +207,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size)
|
|||
#endif /* SLJIT_HAS_EXECUTABLE_OFFSET */
|
||||
|
||||
chunk_size -= CHUNK_EXTRA_SIZE;
|
||||
total_size += chunk_size;
|
||||
sljit_total_size += chunk_size;
|
||||
|
||||
header = (struct block_header*)(((sljit_u8*)chunk_header) + CHUNK_HEADER_SIZE);
|
||||
|
||||
|
|
@ -218,7 +218,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size)
|
|||
|
||||
if (chunk_size > size + 64) {
|
||||
/* Cut the allocated space into a free and a used block. */
|
||||
allocated_size += size;
|
||||
sljit_allocated_size += size;
|
||||
header->size = size;
|
||||
chunk_size -= size;
|
||||
|
||||
|
|
@ -231,7 +231,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size)
|
|||
next_header = AS_BLOCK_HEADER(free_block, chunk_size);
|
||||
} else {
|
||||
/* All space belongs to this allocation. */
|
||||
allocated_size += chunk_size;
|
||||
sljit_allocated_size += chunk_size;
|
||||
header->size = chunk_size;
|
||||
next_header = AS_BLOCK_HEADER(header, chunk_size);
|
||||
}
|
||||
|
|
@ -254,7 +254,7 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void *ptr)
|
|||
#ifdef SLJIT_HAS_EXECUTABLE_OFFSET
|
||||
header = AS_BLOCK_HEADER(header, -header->executable_offset);
|
||||
#endif /* SLJIT_HAS_EXECUTABLE_OFFSET */
|
||||
allocated_size -= header->size;
|
||||
sljit_allocated_size -= header->size;
|
||||
|
||||
SLJIT_UPDATE_WX_FLAGS(NULL, NULL, 0);
|
||||
|
||||
|
|
@ -282,9 +282,9 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void *ptr)
|
|||
|
||||
/* 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;
|
||||
/* If this block is freed, we still have (sljit_allocated_size / 2) free space. */
|
||||
if (sljit_total_size - free_block->size > (sljit_allocated_size * 3 / 2)) {
|
||||
sljit_total_size -= free_block->size;
|
||||
sljit_remove_free_block(free_block);
|
||||
free_chunk(free_block, free_block->size + CHUNK_EXTRA_SIZE);
|
||||
}
|
||||
|
|
@ -302,19 +302,19 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void)
|
|||
SLJIT_ALLOCATOR_LOCK();
|
||||
SLJIT_UPDATE_WX_FLAGS(NULL, NULL, 0);
|
||||
|
||||
free_block = free_blocks;
|
||||
free_block = sljit_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_total_size -= free_block->size;
|
||||
sljit_remove_free_block(free_block);
|
||||
free_chunk(free_block, free_block->size + CHUNK_EXTRA_SIZE);
|
||||
}
|
||||
free_block = next_free_block;
|
||||
}
|
||||
|
||||
SLJIT_ASSERT(total_size || (!total_size && !free_blocks));
|
||||
SLJIT_ASSERT(sljit_total_size || (!sljit_total_size && !sljit_free_blocks));
|
||||
SLJIT_UPDATE_WX_FLAGS(NULL, NULL, 1);
|
||||
SLJIT_ALLOCATOR_UNLOCK();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@
|
|||
SLJIT_SEPARATE_VECTOR_REGISTERS : if this macro is defined, the vector registers do not
|
||||
overlap with floating point registers
|
||||
SLJIT_WORD_SHIFT : the shift required to apply when accessing a sljit_sw/sljit_uw array by index
|
||||
SLJIT_POINTER_SHIFT : the shift required to apply when accessing a sljit_sp/sljit_up 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
|
||||
|
|
@ -96,15 +97,21 @@
|
|||
SLJIT_TMP_FR(i) : accessing temporary floating point registers
|
||||
SLJIT_TMP_VR0 .. VR9 : accessing temporary vector registers
|
||||
SLJIT_TMP_VR(i) : accessing temporary vector registers
|
||||
SLJIT_TMP_DEST_REG : a temporary register for results
|
||||
SLJIT_TMP_MEM_REG : a temporary base register for accessing memory
|
||||
(can be the same as SLJIT_TMP_DEST_REG)
|
||||
SLJIT_TMP_DEST_FREG : a temporary register for float results
|
||||
SLJIT_TMP_DEST_VREG : a temporary register for vector results
|
||||
SLJIT_TMP_DEST_REG : a temporary register for results, see the rules below
|
||||
SLJIT_TMP_DEST_FREG : a temporary register for float results, see the rules below
|
||||
SLJIT_TMP_DEST_VREG : a temporary register for vector results, see the rules below
|
||||
SLJIT_TMP_OPT_REG : a temporary register which might not be defined, see the rules below
|
||||
SLJIT_FUNC : calling convention attribute for both calling JIT from C and C calling back from JIT
|
||||
SLJIT_W(number) : defining 64 bit constants on 64 bit architectures (platform independent helper)
|
||||
SLJIT_F64_SECOND(reg) : provides the register index of the second 32 bit part of a 64 bit
|
||||
floating point register when SLJIT_HAS_F64_AS_F32_PAIR returns non-zero
|
||||
|
||||
Temporary register rules (e.g. SLJIT_TMP_DEST_REG / SLJIT_TMP_OPT_REG):
|
||||
Sljit tries to emit instructions without using any temporary registers whenever it is possible.
|
||||
When a single temporary register is needed, it is always the "OPT" register. When two temporary
|
||||
registers are needed, both the "DEST" and "OPT" are used. The x86-32 does not define an "OPT"
|
||||
register, and handles all cases without an "OPT" register which requires an "OPT" register
|
||||
on other architectures.
|
||||
*/
|
||||
|
||||
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
|
||||
|
|
@ -602,7 +609,6 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void *code);
|
|||
#define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 0
|
||||
#define SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS 1
|
||||
#define SLJIT_TMP_DEST_REG SLJIT_TMP_R0
|
||||
#define SLJIT_TMP_MEM_REG SLJIT_TMP_R0
|
||||
#define SLJIT_TMP_DEST_FREG SLJIT_TMP_FR0
|
||||
#define SLJIT_LOCALS_OFFSET_BASE (8 * (sljit_s32)sizeof(sljit_sw))
|
||||
#define SLJIT_PREF_SHIFT_REG SLJIT_R2
|
||||
|
|
@ -627,7 +633,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void *code);
|
|||
#define SLJIT_LOCALS_OFFSET_BASE (4 * (sljit_s32)sizeof(sljit_sw))
|
||||
#endif /* !_WIN64 */
|
||||
#define SLJIT_TMP_DEST_REG SLJIT_TMP_R0
|
||||
#define SLJIT_TMP_MEM_REG SLJIT_TMP_R0
|
||||
#define SLJIT_TMP_OPT_REG SLJIT_TMP_R1
|
||||
#define SLJIT_TMP_DEST_FREG SLJIT_TMP_FR0
|
||||
#define SLJIT_PREF_SHIFT_REG SLJIT_R3
|
||||
#define SLJIT_MASKED_SHIFT 1
|
||||
|
|
@ -644,7 +650,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void *code);
|
|||
#define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 8
|
||||
#define SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS 2
|
||||
#define SLJIT_TMP_DEST_REG SLJIT_TMP_R1
|
||||
#define SLJIT_TMP_MEM_REG SLJIT_TMP_R1
|
||||
#define SLJIT_TMP_OPT_REG SLJIT_TMP_R0
|
||||
#define SLJIT_TMP_DEST_FREG SLJIT_TMP_FR0
|
||||
#define SLJIT_LOCALS_OFFSET_BASE 0
|
||||
|
||||
|
|
@ -657,7 +663,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void *code);
|
|||
#define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 8
|
||||
#define SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS 2
|
||||
#define SLJIT_TMP_DEST_REG SLJIT_TMP_R0
|
||||
#define SLJIT_TMP_MEM_REG SLJIT_TMP_R0
|
||||
#define SLJIT_TMP_OPT_REG SLJIT_TMP_R1
|
||||
#define SLJIT_TMP_DEST_FREG SLJIT_TMP_FR0
|
||||
#define SLJIT_LOCALS_OFFSET_BASE (2 * (sljit_s32)sizeof(sljit_sw))
|
||||
#define SLJIT_MASKED_SHIFT 1
|
||||
|
|
@ -674,7 +680,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void *code);
|
|||
#define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 18
|
||||
#define SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS 2
|
||||
#define SLJIT_TMP_DEST_REG SLJIT_TMP_R1
|
||||
#define SLJIT_TMP_MEM_REG SLJIT_TMP_R1
|
||||
#define SLJIT_TMP_OPT_REG SLJIT_TMP_R0
|
||||
#define SLJIT_TMP_DEST_FREG SLJIT_TMP_FR0
|
||||
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) || (defined _AIX)
|
||||
#define SLJIT_LOCALS_OFFSET_BASE ((6 + 8) * (sljit_s32)sizeof(sljit_sw))
|
||||
|
|
@ -702,7 +708,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void *code);
|
|||
#define SLJIT_NUMBER_OF_TEMPORARY_REGISTERS 5
|
||||
#define SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS 3
|
||||
#define SLJIT_TMP_DEST_REG SLJIT_TMP_R1
|
||||
#define SLJIT_TMP_MEM_REG SLJIT_TMP_R1
|
||||
#define SLJIT_TMP_OPT_REG SLJIT_TMP_R0
|
||||
#define SLJIT_TMP_DEST_FREG SLJIT_TMP_FR0
|
||||
#define SLJIT_MASKED_SHIFT 1
|
||||
#define SLJIT_MASKED_SHIFT32 1
|
||||
|
|
@ -721,7 +727,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void *code);
|
|||
#define SLJIT_NUMBER_OF_SAVED_VECTOR_REGISTERS 0
|
||||
#define SLJIT_NUMBER_OF_TEMPORARY_VECTOR_REGISTERS 2
|
||||
#define SLJIT_TMP_DEST_REG SLJIT_TMP_R1
|
||||
#define SLJIT_TMP_MEM_REG SLJIT_TMP_R1
|
||||
#define SLJIT_TMP_OPT_REG SLJIT_TMP_R0
|
||||
#define SLJIT_TMP_DEST_FREG SLJIT_TMP_FR0
|
||||
#define SLJIT_TMP_DEST_VREG SLJIT_TMP_VR0
|
||||
#define SLJIT_LOCALS_OFFSET_BASE 0
|
||||
|
|
@ -759,8 +765,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void *code);
|
|||
#define SLJIT_NUMBER_OF_FLOAT_REGISTERS 15
|
||||
#define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 8
|
||||
#define SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS 1
|
||||
#define SLJIT_TMP_DEST_REG SLJIT_TMP_R0
|
||||
#define SLJIT_TMP_MEM_REG SLJIT_TMP_R2
|
||||
#define SLJIT_TMP_DEST_REG SLJIT_TMP_R2
|
||||
#define SLJIT_TMP_OPT_REG SLJIT_TMP_R1
|
||||
#define SLJIT_TMP_DEST_FREG SLJIT_TMP_FR0
|
||||
#define SLJIT_LOCALS_OFFSET_BASE SLJIT_S390X_DEFAULT_STACK_FRAME_SIZE
|
||||
#define SLJIT_MASKED_SHIFT 1
|
||||
|
|
@ -776,7 +782,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void *code);
|
|||
#define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 12
|
||||
#define SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS 2
|
||||
#define SLJIT_TMP_DEST_REG SLJIT_TMP_R1
|
||||
#define SLJIT_TMP_MEM_REG SLJIT_TMP_R1
|
||||
#define SLJIT_TMP_OPT_REG SLJIT_TMP_R0
|
||||
#define SLJIT_TMP_DEST_FREG SLJIT_TMP_FR0
|
||||
#define SLJIT_LOCALS_OFFSET_BASE 0
|
||||
#define SLJIT_MASKED_SHIFT 1
|
||||
|
|
@ -793,7 +799,6 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void *code);
|
|||
#define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 0
|
||||
#define SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS 0
|
||||
#define SLJIT_TMP_DEST_REG 0
|
||||
#define SLJIT_TMP_MEM_REG 0
|
||||
#define SLJIT_TMP_DEST_FREG 0
|
||||
#define SLJIT_LOCALS_OFFSET_BASE 0
|
||||
|
||||
|
|
@ -965,6 +970,37 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void *code);
|
|||
|
||||
#endif /* !SLJIT_COMPILE_ASSERT */
|
||||
|
||||
#ifndef SLJIT_FALLTHROUGH
|
||||
|
||||
#if defined(__cplusplus) && __cplusplus >= 202002L && \
|
||||
defined(__has_cpp_attribute)
|
||||
/* Standards-compatible C++ variant. */
|
||||
#if __has_cpp_attribute(fallthrough)
|
||||
#define SLJIT_FALLTHROUGH [[fallthrough]];
|
||||
#endif
|
||||
#elif !defined(__cplusplus) && \
|
||||
defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L && \
|
||||
defined(__has_c_attribute)
|
||||
/* Standards-compatible C variant. */
|
||||
#if __has_c_attribute(fallthrough)
|
||||
#define SLJIT_FALLTHROUGH [[fallthrough]];
|
||||
#endif
|
||||
#elif ((defined(__clang__) && __clang_major__ >= 10) || \
|
||||
(defined(__GNUC__) && __GNUC__ >= 7)) && \
|
||||
defined(__has_attribute)
|
||||
/* Clang and GCC syntax. Rule out old versions because apparently Clang at
|
||||
least has a broken implementation of __has_attribute. */
|
||||
#if __has_attribute(fallthrough)
|
||||
#define SLJIT_FALLTHROUGH __attribute__((fallthrough));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef SLJIT_FALLTHROUGH
|
||||
#define SLJIT_FALLTHROUGH
|
||||
#endif
|
||||
|
||||
#endif /* !SLJIT_FALLTHROUGH */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -95,17 +95,12 @@
|
|||
#define VARIABLE_FLAG_SHIFT (10)
|
||||
/* All variable flags are even. */
|
||||
#define VARIABLE_FLAG_MASK (0x3e << VARIABLE_FLAG_SHIFT)
|
||||
#define ALL_STATUS_FLAGS_MASK (VARIABLE_FLAG_MASK | SLJIT_SET_Z)
|
||||
#define GET_FLAG_TYPE(op) ((op) >> VARIABLE_FLAG_SHIFT)
|
||||
#define GET_FLAG_TYPE_MASK(op) (((op) >> VARIABLE_FLAG_SHIFT) & 0x3e)
|
||||
|
||||
#define GET_OPCODE(op) \
|
||||
((op) & 0xff)
|
||||
|
||||
#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))
|
||||
#define GET_OPCODE(op) ((op) & 0xff)
|
||||
#define HAS_FLAGS(op) ((op) & ALL_STATUS_FLAGS_MASK)
|
||||
#define GET_ALL_FLAGS(op) ((op) & (SLJIT_32 | ALL_STATUS_FLAGS_MASK))
|
||||
|
||||
#if (defined SLJIT_64BIT_ARCHITECTURE && SLJIT_64BIT_ARCHITECTURE)
|
||||
#define TYPE_CAST_NEEDED(op) \
|
||||
|
|
@ -155,10 +150,22 @@
|
|||
#define SLJIT_SIMD_TYPE_MASK(m) ((sljit_s32)0xff000fff & ~(SLJIT_SIMD_FLOAT | SLJIT_SIMD_TEST | (m)))
|
||||
#define SLJIT_SIMD_TYPE_MASK2(m) ((sljit_s32)0xc0000fff & ~(SLJIT_SIMD_FLOAT | SLJIT_SIMD_TEST | (m)))
|
||||
|
||||
/* Jump flags. */
|
||||
/* Label definitions. */
|
||||
|
||||
#define SLJIT_LABEL_ALIGNED ((~(sljit_uw)0) - 1)
|
||||
|
||||
struct sljit_extended_label {
|
||||
struct sljit_label label;
|
||||
sljit_uw index;
|
||||
sljit_uw data;
|
||||
};
|
||||
|
||||
/* Jump definitions. */
|
||||
|
||||
/* Jump flag bits. */
|
||||
#define JUMP_ADDR 0x1
|
||||
#define JUMP_MOV_ADDR 0x2
|
||||
/* SLJIT_REWRITABLE_JUMP is 0x1000. */
|
||||
/* SLJIT_REWRITABLE_JUMP is 0x10000. */
|
||||
|
||||
#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86)
|
||||
# define PATCH_MB 0x04
|
||||
|
|
@ -172,14 +179,15 @@
|
|||
# define JUMP_MAX_SIZE ((sljit_uw)5)
|
||||
# define CJUMP_MAX_SIZE ((sljit_uw)6)
|
||||
#endif /* SLJIT_CONFIG_X86_64 */
|
||||
# define TYPE_SHIFT 13
|
||||
# define TYPE_SHIFT 17
|
||||
#if (defined SLJIT_DEBUG && SLJIT_DEBUG)
|
||||
/* Bits 7..12 is for debug jump size, SLJIT_REWRITABLE_JUMP is 0x1000 */
|
||||
# define JUMP_SIZE_SHIFT 7
|
||||
/* Bits 7..15 is for debug jump size, SLJIT_REWRITABLE_JUMP is 0x10000 */
|
||||
# define JUMP_SIZE_SHIFT 8
|
||||
#endif /* SLJIT_DEBUG */
|
||||
#endif /* SLJIT_CONFIG_X86 */
|
||||
|
||||
#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) || (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
|
||||
/* SLJIT_REWRITABLE_JUMP is 0x10000. */
|
||||
# define IS_BL 0x04
|
||||
# define PATCH_B 0x08
|
||||
#endif /* SLJIT_CONFIG_ARM_V6 || SLJIT_CONFIG_ARM_V7 */
|
||||
|
|
@ -194,8 +202,11 @@
|
|||
#endif /* SLJIT_CONFIG_ARM_V7 */
|
||||
|
||||
#if (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2)
|
||||
/* SLJIT_REWRITABLE_JUMP is 0x10000. */
|
||||
# define IS_COND 0x04
|
||||
# define IS_BL 0x08
|
||||
/* mov_addr does not use IS_BL */
|
||||
# define IS_ABS IS_BL
|
||||
/* conditional + imm8 */
|
||||
# define PATCH_TYPE1 0x10
|
||||
/* conditional + imm20 */
|
||||
|
|
@ -214,6 +225,7 @@
|
|||
#endif /* SLJIT_CONFIG_ARM_THUMB2 */
|
||||
|
||||
#if (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64)
|
||||
/* SLJIT_REWRITABLE_JUMP is 0x10000. */
|
||||
# define IS_COND 0x004
|
||||
# define IS_CBZ 0x008
|
||||
# define IS_BL 0x010
|
||||
|
|
@ -227,6 +239,7 @@
|
|||
#endif /* SLJIT_CONFIG_ARM_64 */
|
||||
|
||||
#if (defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC)
|
||||
/* SLJIT_REWRITABLE_JUMP is 0x10000. */
|
||||
# define IS_COND 0x004
|
||||
# define IS_CALL 0x008
|
||||
# define PATCH_B 0x010
|
||||
|
|
@ -243,6 +256,7 @@
|
|||
#endif /* SLJIT_CONFIG_PPC */
|
||||
|
||||
#if (defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS)
|
||||
/* SLJIT_REWRITABLE_JUMP is 0x10000. */
|
||||
# define IS_MOVABLE 0x004
|
||||
# define IS_JAL 0x008
|
||||
# define IS_CALL 0x010
|
||||
|
|
@ -270,26 +284,36 @@
|
|||
#endif /* SLJIT_CONFIG_MIPS */
|
||||
|
||||
#if (defined SLJIT_CONFIG_RISCV && SLJIT_CONFIG_RISCV)
|
||||
# define IS_COND 0x004
|
||||
# define IS_CALL 0x008
|
||||
/* SLJIT_REWRITABLE_JUMP is 0x10000. */
|
||||
# define IS_COND 0x0004
|
||||
# define IS_CALL 0x0008
|
||||
|
||||
# define PATCH_B 0x010
|
||||
# define PATCH_J 0x020
|
||||
# define IS_COND16 0x0010
|
||||
# define PATCH_B 0x0020
|
||||
# define PATCH_J 0x0040
|
||||
# define PATCH_16 0x0080
|
||||
|
||||
#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
|
||||
# define PATCH_REL32 0x0100
|
||||
# define PATCH_ABS32 0x0200
|
||||
# define PATCH_ABS44 0x0400
|
||||
# define PATCH_ABS52 0x0800
|
||||
# define JUMP_SIZE_SHIFT 58
|
||||
# define JUMP_MAX_SIZE ((sljit_uw)6)
|
||||
# define JUMP_MAX_SIZE ((sljit_uw)12)
|
||||
#else /* !SLJIT_CONFIG_RISCV_64 */
|
||||
# define JUMP_SIZE_SHIFT 26
|
||||
# define JUMP_MAX_SIZE ((sljit_uw)2)
|
||||
# define JUMP_MAX_SIZE ((sljit_uw)4)
|
||||
#endif /* SLJIT_CONFIG_RISCV_64 */
|
||||
#endif /* SLJIT_CONFIG_RISCV */
|
||||
|
||||
#if (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X)
|
||||
/* SLJIT_REWRITABLE_JUMP is 0x10000. */
|
||||
# define PATCH_POOL 0x004
|
||||
# define PATCH_IMM32 0x008
|
||||
#endif /* SLJIT_CONFIG_S390X */
|
||||
|
||||
#if (defined SLJIT_CONFIG_LOONGARCH && SLJIT_CONFIG_LOONGARCH)
|
||||
/* SLJIT_REWRITABLE_JUMP is 0x10000. */
|
||||
# define IS_COND 0x004
|
||||
# define IS_CALL 0x008
|
||||
|
||||
|
|
@ -303,6 +327,7 @@
|
|||
# define JUMP_MAX_SIZE ((sljit_uw)4)
|
||||
|
||||
#endif /* SLJIT_CONFIG_LOONGARCH */
|
||||
|
||||
/* Stack management. */
|
||||
|
||||
#define GET_SAVED_REGISTERS_SIZE(scratches, saveds, extra) \
|
||||
|
|
@ -451,12 +476,12 @@
|
|||
/* Public functions */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86)
|
||||
#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) || (defined SLJIT_CONFIG_RISCV && SLJIT_CONFIG_RISCV)
|
||||
#define SLJIT_NEEDS_COMPILER_INIT 1
|
||||
static sljit_s32 compiler_initialized = 0;
|
||||
/* A thread safe initialization. */
|
||||
static void init_compiler(void);
|
||||
#endif /* SLJIT_CONFIG_X86 */
|
||||
#endif /* SLJIT_CONFIG_X86 || SLJIT_CONFIG_RISCV */
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_compiler* sljit_create_compiler(void *allocator_data)
|
||||
{
|
||||
|
|
@ -475,8 +500,12 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_compiler* sljit_create_compiler(void *allo
|
|||
&& (sizeof(sljit_sw) == 4 || sizeof(sljit_sw) == 8)
|
||||
&& (sizeof(sljit_uw) == sizeof(sljit_sw)),
|
||||
invalid_integer_types);
|
||||
SLJIT_COMPILE_ASSERT(SLJIT_REWRITABLE_JUMP != SLJIT_32,
|
||||
rewritable_jump_and_single_op_must_not_be_the_same);
|
||||
SLJIT_COMPILE_ASSERT((SLJIT_REWRITABLE_JUMP & SLJIT_32) == 0
|
||||
&& (ALL_STATUS_FLAGS_MASK & SLJIT_32) == 0
|
||||
&& (SLJIT_REWRITABLE_JUMP & ALL_STATUS_FLAGS_MASK) == 0,
|
||||
rewritable_jump_and_status_flag_bits_and_sljit_32_must_not_have_common_bits);
|
||||
SLJIT_COMPILE_ASSERT((VARIABLE_FLAG_MASK & SLJIT_SET_Z) == 0,
|
||||
rewritable_jump_and_status_flag_bits_must_not_have_common_bits);
|
||||
SLJIT_COMPILE_ASSERT(!(SLJIT_EQUAL & 0x1) && !(SLJIT_LESS & 0x1) && !(SLJIT_F_EQUAL & 0x1) && !(SLJIT_JUMP & 0x1),
|
||||
conditional_flags_must_be_even_numbers);
|
||||
|
||||
|
|
@ -615,8 +644,8 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_target(struct sljit_jump *jump, sljit_uw
|
|||
}
|
||||
}
|
||||
|
||||
#define SLJIT_CURRENT_FLAGS_ALL \
|
||||
(SLJIT_CURRENT_FLAGS_32 | SLJIT_CURRENT_FLAGS_ADD | SLJIT_CURRENT_FLAGS_SUB | SLJIT_CURRENT_FLAGS_COMPARE)
|
||||
#define SLJIT_CURRENT_FLAGS_ALL (SLJIT_CURRENT_FLAGS_32 | SLJIT_CURRENT_FLAGS_ADD \
|
||||
| SLJIT_CURRENT_FLAGS_SUB | SLJIT_CURRENT_FLAGS_COMPARE | SLJIT_CURRENT_FLAGS_OP2CMPZ)
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_current_flags(struct sljit_compiler *compiler, sljit_s32 current_flags)
|
||||
{
|
||||
|
|
@ -624,12 +653,18 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_current_flags(struct sljit_compiler *com
|
|||
SLJIT_UNUSED_ARG(current_flags);
|
||||
|
||||
#if (defined SLJIT_HAS_STATUS_FLAGS_STATE && SLJIT_HAS_STATUS_FLAGS_STATE)
|
||||
#if (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X)
|
||||
if (current_flags & SLJIT_CURRENT_FLAGS_OP2CMPZ) {
|
||||
current_flags |= SLJIT_SET_Z;
|
||||
}
|
||||
#endif /* SLJIT_CONFIG_S390X */
|
||||
|
||||
compiler->status_flags_state = current_flags;
|
||||
#endif /* SLJIT_HAS_STATUS_FLAGS_STATE */
|
||||
|
||||
#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) {
|
||||
if ((current_flags & ~(ALL_STATUS_FLAGS_MASK | SLJIT_CURRENT_FLAGS_ALL)) == 0) {
|
||||
compiler->last_flags = GET_FLAG_TYPE(current_flags) | (current_flags & (SLJIT_32 | SLJIT_SET_Z));
|
||||
}
|
||||
#endif /* SLJIT_ARGUMENT_CHECKS */
|
||||
|
|
@ -826,22 +861,34 @@ static SLJIT_INLINE void set_label(struct sljit_label *label, struct sljit_compi
|
|||
label->next = NULL;
|
||||
label->u.index = compiler->label_count++;
|
||||
label->size = compiler->size;
|
||||
|
||||
if (compiler->last_label != NULL)
|
||||
compiler->last_label->next = label;
|
||||
else
|
||||
compiler->labels = label;
|
||||
|
||||
compiler->last_label = label;
|
||||
}
|
||||
|
||||
static SLJIT_INLINE void set_extended_label(struct sljit_extended_label *ext_label, struct sljit_compiler *compiler, sljit_uw type, sljit_uw data)
|
||||
{
|
||||
set_label(&ext_label->label, compiler);
|
||||
ext_label->index = ext_label->label.u.index;
|
||||
ext_label->label.u.index = type;
|
||||
ext_label->data = data;
|
||||
}
|
||||
|
||||
static SLJIT_INLINE void set_jump(struct sljit_jump *jump, struct sljit_compiler *compiler, sljit_u32 flags)
|
||||
{
|
||||
jump->next = NULL;
|
||||
jump->flags = flags;
|
||||
jump->u.label = NULL;
|
||||
|
||||
if (compiler->last_jump != NULL)
|
||||
compiler->last_jump->next = jump;
|
||||
else
|
||||
compiler->jumps = jump;
|
||||
|
||||
compiler->last_jump = jump;
|
||||
}
|
||||
|
||||
|
|
@ -1318,6 +1365,10 @@ static const char* call_arg_names[] = {
|
|||
"void", "w", "32", "p", "f64", "f32"
|
||||
};
|
||||
|
||||
static const char* op_addr_types[] = {
|
||||
"mov_addr", "mov_abs_addr", "add_abs_addr"
|
||||
};
|
||||
|
||||
#endif /* SLJIT_VERBOSE */
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
|
@ -1328,18 +1379,21 @@ static const char* call_arg_names[] = {
|
|||
|| (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
|
||||
|
||||
#define SLJIT_SKIP_CHECKS(compiler) (compiler)->skip_checks = 1
|
||||
#define SLJIT_CHECK_OPCODE(op, flags) ((op) & ~(SLJIT_32 | SLJIT_SET_Z | VARIABLE_FLAG_MASK | (flags)))
|
||||
#define SLJIT_CHECK_OPCODE(op, flags) ((op) & ~(SLJIT_32 | ALL_STATUS_FLAGS_MASK | (flags)))
|
||||
|
||||
static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_generate_code(struct sljit_compiler *compiler)
|
||||
static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_generate_code(struct sljit_compiler *compiler, sljit_s32 options)
|
||||
{
|
||||
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
|
||||
struct sljit_jump *jump;
|
||||
#endif /* SLJIT_ARGUMENT_CHECKS */
|
||||
|
||||
SLJIT_UNUSED_ARG(compiler);
|
||||
SLJIT_UNUSED_ARG(options);
|
||||
|
||||
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
|
||||
CHECK_ARGUMENT(compiler->size > 0);
|
||||
CHECK_ARGUMENT((options & ~(SLJIT_GENERATE_CODE_BUFFER | SLJIT_GENERATE_CODE_NO_CONTEXT)) == 0);
|
||||
|
||||
jump = compiler->jumps;
|
||||
while (jump) {
|
||||
/* All jumps have target. */
|
||||
|
|
@ -1643,11 +1697,11 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op1(struct sljit_compiler
|
|||
case SLJIT_REV_U32:
|
||||
case SLJIT_REV_S32:
|
||||
/* Nothing allowed */
|
||||
CHECK_ARGUMENT(!(op & (SLJIT_32 | SLJIT_SET_Z | VARIABLE_FLAG_MASK)));
|
||||
CHECK_ARGUMENT(!(op & (SLJIT_32 | ALL_STATUS_FLAGS_MASK)));
|
||||
break;
|
||||
default:
|
||||
/* Only SLJIT_32 is allowed. */
|
||||
CHECK_ARGUMENT(!(op & (SLJIT_SET_Z | VARIABLE_FLAG_MASK)));
|
||||
CHECK_ARGUMENT(!(op & ALL_STATUS_FLAGS_MASK));
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -1679,8 +1733,8 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_atomic_load(struct sljit_
|
|||
|
||||
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
|
||||
CHECK_ARGUMENT(sljit_has_cpu_feature(SLJIT_HAS_ATOMIC));
|
||||
CHECK_ARGUMENT(SLJIT_CHECK_OPCODE(op, SLJIT_ATOMIC_TEST | SLJIT_ATOMIC_USE_CAS | SLJIT_ATOMIC_USE_LS | SLJIT_SET_Z | VARIABLE_FLAG_MASK) >= SLJIT_MOV
|
||||
&& SLJIT_CHECK_OPCODE(op, SLJIT_ATOMIC_TEST | SLJIT_ATOMIC_USE_CAS | SLJIT_ATOMIC_USE_LS | SLJIT_SET_Z | VARIABLE_FLAG_MASK) <= SLJIT_MOV_P);
|
||||
CHECK_ARGUMENT(SLJIT_CHECK_OPCODE(op, SLJIT_ATOMIC_TEST | SLJIT_ATOMIC_USE_CAS | SLJIT_ATOMIC_USE_LS | ALL_STATUS_FLAGS_MASK) >= SLJIT_MOV
|
||||
&& SLJIT_CHECK_OPCODE(op, SLJIT_ATOMIC_TEST | SLJIT_ATOMIC_USE_CAS | SLJIT_ATOMIC_USE_LS | ALL_STATUS_FLAGS_MASK) <= SLJIT_MOV_P);
|
||||
CHECK_ARGUMENT((op & (SLJIT_ATOMIC_USE_CAS | SLJIT_ATOMIC_USE_LS)) != (SLJIT_ATOMIC_USE_CAS | SLJIT_ATOMIC_USE_LS));
|
||||
|
||||
/* All arguments must be valid registers. */
|
||||
|
|
@ -1778,6 +1832,49 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_atomic_store(struct sljit
|
|||
CHECK_RETURN_OK;
|
||||
}
|
||||
|
||||
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
|
||||
|
||||
static sljit_s32 check_sljit_emit_op2_operation(struct sljit_compiler *compiler, sljit_s32 op)
|
||||
{
|
||||
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:
|
||||
return !(op & VARIABLE_FLAG_MASK);
|
||||
case SLJIT_MUL:
|
||||
return !(op & SLJIT_SET_Z) && (!(op & VARIABLE_FLAG_MASK) || GET_FLAG_TYPE(op) == SLJIT_OVERFLOW);
|
||||
case SLJIT_ADD:
|
||||
return !(op & VARIABLE_FLAG_MASK)
|
||||
|| GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY)
|
||||
|| GET_FLAG_TYPE(op) == SLJIT_OVERFLOW;
|
||||
case SLJIT_SUB:
|
||||
return !(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);
|
||||
case SLJIT_ADDC:
|
||||
case SLJIT_SUBC:
|
||||
return (!(op & VARIABLE_FLAG_MASK) || GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY))
|
||||
&& (compiler->last_flags & 0xff) == GET_FLAG_TYPE(SLJIT_SET_CARRY)
|
||||
&& (op & SLJIT_32) == (compiler->last_flags & SLJIT_32);
|
||||
break;
|
||||
case SLJIT_ROTL:
|
||||
case SLJIT_ROTR:
|
||||
return !(op & ALL_STATUS_FLAGS_MASK);
|
||||
}
|
||||
|
||||
/* Operation type should be checked earlier. */
|
||||
SLJIT_UNREACHABLE();
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* SLJIT_ARGUMENT_CHECKS */
|
||||
|
||||
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,
|
||||
|
|
@ -1790,49 +1887,7 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op2(struct sljit_compiler
|
|||
|
||||
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
|
||||
CHECK_ARGUMENT(SLJIT_CHECK_OPCODE(op, 0) >= SLJIT_ADD && SLJIT_CHECK_OPCODE(op, 0) <= 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;
|
||||
}
|
||||
CHECK_ARGUMENT(check_sljit_emit_op2_operation(compiler, op));
|
||||
|
||||
if (unset) {
|
||||
CHECK_ARGUMENT(HAS_FLAGS(op));
|
||||
|
|
@ -1923,6 +1978,36 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_shift_into(struct sljit_c
|
|||
CHECK_RETURN_OK;
|
||||
}
|
||||
|
||||
static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op2_shift(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_sw shift_arg)
|
||||
{
|
||||
SLJIT_UNUSED_ARG(shift_arg);
|
||||
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
|
||||
CHECK_ARGUMENT((op & ~SLJIT_SRC2_UNDEFINED) == (SLJIT_ADD | SLJIT_SHL_IMM));
|
||||
FUNCTION_CHECK_DST(dst, dstw);
|
||||
FUNCTION_CHECK_SRC(src1, src1w);
|
||||
FUNCTION_CHECK_SRC(src2, src2w);
|
||||
compiler->last_flags = 0;
|
||||
#endif /* SLJIT_ARGUMENT_CHECKS */
|
||||
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
|
||||
if (SLJIT_UNLIKELY(!!compiler->verbose)) {
|
||||
fprintf(compiler->verbose, " %s.shl_imm%s ", op2_names[GET_OPCODE(op) - SLJIT_OP2_BASE],
|
||||
(op & SLJIT_SRC2_UNDEFINED) ? ".src2und" : "");
|
||||
|
||||
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, ", #%" SLJIT_PRINT_D "d\n", shift_arg);
|
||||
}
|
||||
#endif /* SLJIT_VERBOSE */
|
||||
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)
|
||||
{
|
||||
|
|
@ -2005,12 +2090,12 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op_custom(struct sljit_co
|
|||
|
||||
#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86)
|
||||
CHECK_ARGUMENT(size > 0 && size < 16);
|
||||
#elif (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2)
|
||||
#elif (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2) || (defined SLJIT_CONFIG_RISCV && SLJIT_CONFIG_RISCV)
|
||||
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 /* !SLJIT_CONFIG_X86 && !SLJIT_CONFIG_ARM_THUMB2 && !SLJIT_CONFIG_S390X */
|
||||
#else /* !SLJIT_CONFIG_X86 && !SLJIT_CONFIG_ARM_THUMB2 && !SLJIT_CONFIG_RISCV && !SLJIT_CONFIG_S390X */
|
||||
CHECK_ARGUMENT(size == 4 && (((sljit_sw)instruction) & 0x3) == 0);
|
||||
#endif /* SLJIT_CONFIG_X86 */
|
||||
|
||||
|
|
@ -2039,7 +2124,7 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fop1(struct sljit_compile
|
|||
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
|
||||
CHECK_ARGUMENT(sljit_has_cpu_feature(SLJIT_HAS_FPU));
|
||||
CHECK_ARGUMENT(SLJIT_CHECK_OPCODE(op, 0) >= SLJIT_MOV_F64 && SLJIT_CHECK_OPCODE(op, 0) <= SLJIT_ABS_F64);
|
||||
CHECK_ARGUMENT(!(op & (SLJIT_SET_Z | VARIABLE_FLAG_MASK)));
|
||||
CHECK_ARGUMENT(!(op & ALL_STATUS_FLAGS_MASK));
|
||||
FUNCTION_FCHECK(src, srcw, op & SLJIT_32);
|
||||
FUNCTION_FCHECK(dst, dstw, op & SLJIT_32);
|
||||
#endif /* SLJIT_ARGUMENT_CHECKS */
|
||||
|
|
@ -2110,7 +2195,7 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fop1_conv_sw_from_f64(str
|
|||
|
||||
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
|
||||
CHECK_ARGUMENT(sljit_has_cpu_feature(SLJIT_HAS_FPU));
|
||||
CHECK_ARGUMENT(!(op & (SLJIT_SET_Z | VARIABLE_FLAG_MASK)));
|
||||
CHECK_ARGUMENT(!(op & ALL_STATUS_FLAGS_MASK));
|
||||
FUNCTION_FCHECK(src, srcw, op & SLJIT_32);
|
||||
FUNCTION_CHECK_DST(dst, dstw);
|
||||
#endif /* SLJIT_ARGUMENT_CHECKS */
|
||||
|
|
@ -2139,7 +2224,7 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fop1_conv_f64_from_w(stru
|
|||
|
||||
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
|
||||
CHECK_ARGUMENT(sljit_has_cpu_feature(SLJIT_HAS_FPU));
|
||||
CHECK_ARGUMENT(!(op & (SLJIT_SET_Z | VARIABLE_FLAG_MASK)));
|
||||
CHECK_ARGUMENT(!(op & ALL_STATUS_FLAGS_MASK));
|
||||
FUNCTION_CHECK_SRC(src, srcw);
|
||||
FUNCTION_FCHECK(dst, dstw, op & SLJIT_32);
|
||||
#endif /* SLJIT_ARGUMENT_CHECKS */
|
||||
|
|
@ -2170,7 +2255,7 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fop2(struct sljit_compile
|
|||
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
|
||||
CHECK_ARGUMENT(sljit_has_cpu_feature(SLJIT_HAS_FPU));
|
||||
CHECK_ARGUMENT(SLJIT_CHECK_OPCODE(op, 0) >= SLJIT_ADD_F64 && SLJIT_CHECK_OPCODE(op, 0) <= SLJIT_DIV_F64);
|
||||
CHECK_ARGUMENT(!(op & (SLJIT_SET_Z | VARIABLE_FLAG_MASK)));
|
||||
CHECK_ARGUMENT(!(op & ALL_STATUS_FLAGS_MASK));
|
||||
FUNCTION_FCHECK(src1, src1w, op & SLJIT_32);
|
||||
FUNCTION_FCHECK(src2, src2w, op & SLJIT_32);
|
||||
FUNCTION_FCHECK(dst, dstw, op & SLJIT_32);
|
||||
|
|
@ -2269,7 +2354,7 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fcopy(struct sljit_compil
|
|||
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
|
||||
CHECK_ARGUMENT(sljit_has_cpu_feature(SLJIT_HAS_FPU));
|
||||
CHECK_ARGUMENT(SLJIT_CHECK_OPCODE(op, 0) >= SLJIT_COPY_TO_F64 && SLJIT_CHECK_OPCODE(op, 0) <= SLJIT_COPY_FROM_F64);
|
||||
CHECK_ARGUMENT(!(op & (SLJIT_SET_Z | VARIABLE_FLAG_MASK)));
|
||||
CHECK_ARGUMENT(!(op & ALL_STATUS_FLAGS_MASK));
|
||||
CHECK_ARGUMENT(FUNCTION_CHECK_IS_FREG(freg, op & SLJIT_32));
|
||||
|
||||
#if (defined SLJIT_64BIT_ARCHITECTURE && SLJIT_64BIT_ARCHITECTURE)
|
||||
|
|
@ -2341,6 +2426,37 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_label(struct sljit_compil
|
|||
CHECK_RETURN_OK;
|
||||
}
|
||||
|
||||
static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_aligned_label(struct sljit_compiler *compiler,
|
||||
sljit_s32 alignment, struct sljit_read_only_buffer *buffers)
|
||||
{
|
||||
SLJIT_UNUSED_ARG(compiler);
|
||||
SLJIT_UNUSED_ARG(buffers);
|
||||
|
||||
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
|
||||
CHECK_ARGUMENT(alignment >= SLJIT_LABEL_ALIGN_1 && alignment <= SLJIT_LABEL_ALIGN_16);
|
||||
compiler->last_flags = 0;
|
||||
#endif /* SLJIT_ARGUMENT_CHECKS */
|
||||
|
||||
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
|
||||
if (SLJIT_UNLIKELY(!!compiler->verbose)) {
|
||||
fprintf(compiler->verbose, "label.al%d:%s", 1 << alignment, buffers == NULL ? "\n" : " [");
|
||||
|
||||
if (buffers != NULL) {
|
||||
fprintf(compiler->verbose, "%ld", (long int)buffers->size);
|
||||
buffers = buffers->next;
|
||||
|
||||
while (buffers != NULL) {
|
||||
fprintf(compiler->verbose, ", %ld", (long int)buffers->size);
|
||||
buffers = buffers->next;
|
||||
}
|
||||
|
||||
fprintf(compiler->verbose, "]\n");
|
||||
}
|
||||
}
|
||||
#endif /* SLJIT_VERBOSE */
|
||||
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)
|
||||
|
|
@ -2427,6 +2543,11 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_cmp(struct sljit_compiler
|
|||
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(!(type & ~(0xff | SLJIT_REWRITABLE_JUMP | SLJIT_32)));
|
||||
CHECK_ARGUMENT((type & 0xff) >= SLJIT_EQUAL && (type & 0xff) <= SLJIT_SIG_LESS_EQUAL);
|
||||
|
|
@ -2472,6 +2593,40 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fcmp(struct sljit_compile
|
|||
CHECK_RETURN_OK;
|
||||
}
|
||||
|
||||
static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op2cmpz(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_COMPILE_ASSERT((SLJIT_JUMP_IF_ZERO == SLJIT_SET_Z) && (SLJIT_JUMP_IF_NON_ZERO == 0),
|
||||
incorrect_values_for_sljit_jump_zero_or_non_zero);
|
||||
|
||||
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
|
||||
CHECK_ARGUMENT(SLJIT_CHECK_OPCODE(op, SLJIT_REWRITABLE_JUMP) >= SLJIT_ADD && SLJIT_CHECK_OPCODE(op, SLJIT_REWRITABLE_JUMP) <= SLJIT_ROTR);
|
||||
/* Not all opcodes allow setting zero flags. */
|
||||
CHECK_ARGUMENT(check_sljit_emit_op2_operation(compiler, ((op | SLJIT_SET_Z) & ~SLJIT_REWRITABLE_JUMP)));
|
||||
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);
|
||||
#endif /* SLJIT_ARGUMENT_CHECKS */
|
||||
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
|
||||
if (SLJIT_UNLIKELY(!!compiler->verbose)) {
|
||||
fprintf(compiler->verbose, " cmp%sz.%s%s%s%s%s ", (op & SLJIT_JUMP_IF_ZERO) ? "" : "n",
|
||||
op2_names[GET_OPCODE(op) - SLJIT_OP2_BASE], !(op & SLJIT_32) ? "" : "32",
|
||||
!(op & VARIABLE_FLAG_MASK) ? "" : ".", !(op & VARIABLE_FLAG_MASK) ? "" : jump_names[GET_FLAG_TYPE(op & ~SLJIT_REWRITABLE_JUMP)],
|
||||
!(op & SLJIT_REWRITABLE_JUMP) ? "" : ".r");
|
||||
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 /* SLJIT_VERBOSE */
|
||||
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)
|
||||
{
|
||||
|
|
@ -2578,27 +2733,30 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_select(struct sljit_compi
|
|||
sljit_s32 src2_reg)
|
||||
{
|
||||
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
|
||||
sljit_s32 cond = type & ~SLJIT_32;
|
||||
|
||||
CHECK_ARGUMENT(cond >= SLJIT_EQUAL && cond <= SLJIT_ORDERED_LESS_EQUAL);
|
||||
|
||||
sljit_s32 cond = type & ~(SLJIT_32 | SLJIT_COMPARE_SELECT);
|
||||
CHECK_ARGUMENT((type & SLJIT_COMPARE_SELECT) ? (cond >= SLJIT_LESS && cond <= SLJIT_SET_SIG_LESS_EQUAL)
|
||||
: (cond >= SLJIT_EQUAL && cond <= SLJIT_ORDERED_LESS_EQUAL));
|
||||
CHECK_ARGUMENT(compiler->scratches != -1 && compiler->saveds != -1);
|
||||
CHECK_ARGUMENT(FUNCTION_CHECK_IS_REG(dst_reg));
|
||||
FUNCTION_CHECK_SRC(src1, src1w);
|
||||
CHECK_ARGUMENT(FUNCTION_CHECK_IS_REG(src2_reg));
|
||||
|
||||
if (cond <= SLJIT_NOT_ZERO)
|
||||
CHECK_ARGUMENT(compiler->last_flags & SLJIT_SET_Z);
|
||||
else if ((compiler->last_flags & 0xff) == SLJIT_CARRY) {
|
||||
CHECK_ARGUMENT((type & 0xfe) == SLJIT_CARRY);
|
||||
compiler->last_flags = 0;
|
||||
if (!(type & SLJIT_COMPARE_SELECT)) {
|
||||
if (cond <= SLJIT_NOT_ZERO)
|
||||
CHECK_ARGUMENT(compiler->last_flags & SLJIT_SET_Z);
|
||||
else if ((compiler->last_flags & 0xff) == SLJIT_CARRY) {
|
||||
CHECK_ARGUMENT((type & 0xfe) == SLJIT_CARRY);
|
||||
compiler->last_flags = 0;
|
||||
} else
|
||||
CHECK_ARGUMENT((cond & 0xfe) == (compiler->last_flags & 0xff)
|
||||
|| CHECK_UNORDERED(cond, compiler->last_flags));
|
||||
} else
|
||||
CHECK_ARGUMENT((cond & 0xfe) == (compiler->last_flags & 0xff)
|
||||
|| CHECK_UNORDERED(cond, compiler->last_flags));
|
||||
compiler->last_flags = 0;
|
||||
#endif /* SLJIT_ARGUMENT_CHECKS */
|
||||
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
|
||||
if (SLJIT_UNLIKELY(!!compiler->verbose)) {
|
||||
fprintf(compiler->verbose, " select%s %s, ",
|
||||
fprintf(compiler->verbose, " %sselect%s %s, ",
|
||||
!(type & SLJIT_COMPARE_SELECT) ? "" : "cmp_",
|
||||
!(type & SLJIT_32) ? "" : "32",
|
||||
jump_names[type & ~SLJIT_32]);
|
||||
sljit_verbose_reg(compiler, dst_reg);
|
||||
|
|
@ -2680,7 +2838,7 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_mem(struct sljit_compiler
|
|||
case SLJIT_MOV_P:
|
||||
case SLJIT_MOV:
|
||||
allowed_flags |= SLJIT_MEM_ALIGNED_32;
|
||||
/* fallthrough */
|
||||
SLJIT_FALLTHROUGH
|
||||
case SLJIT_MOV_U32:
|
||||
case SLJIT_MOV_S32:
|
||||
case SLJIT_MOV32:
|
||||
|
|
@ -2714,11 +2872,11 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_mem(struct sljit_compiler
|
|||
!(type & SLJIT_32) ? "" : "32", op1_types[(type & 0xff) - SLJIT_OP1_BASE]);
|
||||
|
||||
if (type & SLJIT_MEM_UNALIGNED)
|
||||
printf(".unal");
|
||||
fprintf(compiler->verbose, ".unal");
|
||||
else if (type & SLJIT_MEM_ALIGNED_16)
|
||||
printf(".al16");
|
||||
fprintf(compiler->verbose, ".al16");
|
||||
else if (type & SLJIT_MEM_ALIGNED_32)
|
||||
printf(".al32");
|
||||
fprintf(compiler->verbose, ".al32");
|
||||
|
||||
if (reg & REG_PAIR_MASK) {
|
||||
fprintf(compiler->verbose, " {");
|
||||
|
|
@ -3176,16 +3334,21 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_get_local_base(struct sljit_co
|
|||
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)
|
||||
static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 op,
|
||||
sljit_s32 dst, sljit_sw dstw,
|
||||
sljit_sw init_value)
|
||||
{
|
||||
SLJIT_UNUSED_ARG(init_value);
|
||||
|
||||
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
|
||||
CHECK_ARGUMENT(op == SLJIT_MOV || op == SLJIT_MOV_S32
|
||||
|| op == SLJIT_MOV32 || (op | SLJIT_32) == SLJIT_MOV32_U8);
|
||||
FUNCTION_CHECK_DST(dst, dstw);
|
||||
#endif /* SLJIT_ARGUMENT_CHECKS */
|
||||
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
|
||||
if (SLJIT_UNLIKELY(!!compiler->verbose)) {
|
||||
fprintf(compiler->verbose, " const ");
|
||||
fprintf(compiler->verbose, " const%s%s ",
|
||||
!(op & SLJIT_32) ? "" : "32", op1_types[GET_OPCODE(op) - SLJIT_OP1_BASE]);
|
||||
sljit_verbose_param(compiler, dst, dstw);
|
||||
fprintf(compiler->verbose, ", #%" SLJIT_PRINT_D "d\n", init_value);
|
||||
}
|
||||
|
|
@ -3193,14 +3356,16 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_const(struct sljit_compil
|
|||
CHECK_RETURN_OK;
|
||||
}
|
||||
|
||||
static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_mov_addr(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
|
||||
static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op_addr(struct sljit_compiler *compiler, sljit_s32 op,
|
||||
sljit_s32 dst, sljit_sw dstw)
|
||||
{
|
||||
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
|
||||
CHECK_ARGUMENT(op == SLJIT_MOV_ADDR || op == SLJIT_MOV_ABS_ADDR || op == SLJIT_ADD_ABS_ADDR);
|
||||
FUNCTION_CHECK_DST(dst, dstw);
|
||||
#endif /* SLJIT_ARGUMENT_CHECKS */
|
||||
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
|
||||
if (SLJIT_UNLIKELY(!!compiler->verbose)) {
|
||||
fprintf(compiler->verbose, " mov_addr ");
|
||||
fprintf(compiler->verbose, " %s ", op_addr_types[op]);
|
||||
sljit_verbose_param(compiler, dst, dstw);
|
||||
fprintf(compiler->verbose, "\n");
|
||||
}
|
||||
|
|
@ -3276,6 +3441,14 @@ static sljit_s32 sljit_emit_fmem_unaligned(struct sljit_compiler *compiler, slji
|
|||
|
||||
#endif /* (!SLJIT_CONFIG_MIPS || SLJIT_MIPS_REV >= 6) && !SLJIT_CONFIG_ARM */
|
||||
|
||||
static void sljit_reset_read_only_buffers(struct sljit_read_only_buffer *buffers)
|
||||
{
|
||||
while (buffers != NULL) {
|
||||
buffers->u.label = NULL;
|
||||
buffers = buffers->next;
|
||||
}
|
||||
}
|
||||
|
||||
/* CPU description section */
|
||||
|
||||
#if (defined SLJIT_32BIT_ARCHITECTURE && SLJIT_32BIT_ARCHITECTURE)
|
||||
|
|
@ -3501,6 +3674,49 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_fcmp(struct sljit_compile
|
|||
return sljit_emit_jump(compiler, type);
|
||||
}
|
||||
|
||||
#if !(defined SLJIT_CONFIG_RISCV && SLJIT_CONFIG_RISCV) \
|
||||
&& !(defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS) \
|
||||
&& !(defined SLJIT_CONFIG_LOONGARCH && SLJIT_CONFIG_LOONGARCH)
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_op2cmpz(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_PTR();
|
||||
CHECK_PTR(check_sljit_emit_op2cmpz(compiler, op, dst, dstw, src1, src1w, src2, src2w));
|
||||
|
||||
SLJIT_SKIP_CHECKS(compiler);
|
||||
PTR_FAIL_IF(sljit_emit_op2(compiler, ((op | SLJIT_SET_Z) & ~SLJIT_REWRITABLE_JUMP), dst, dstw, src1, src1w, src2, src2w));
|
||||
|
||||
SLJIT_SKIP_CHECKS(compiler);
|
||||
return sljit_emit_jump(compiler, ((op & SLJIT_JUMP_IF_ZERO) ? SLJIT_ZERO : SLJIT_NOT_ZERO) | (op & SLJIT_REWRITABLE_JUMP));
|
||||
}
|
||||
|
||||
#else /* SLJIT_CONFIG_RISCV || SLJIT_CONFIG_MIPS || SLJIT_CONFIG_LOONGARCH */
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_op2cmpz(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 reg;
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_PTR(check_sljit_emit_op2cmpz(compiler, op, dst, dstw, src1, src1w, src2, src2w));
|
||||
|
||||
SLJIT_SKIP_CHECKS(compiler);
|
||||
PTR_FAIL_IF(sljit_emit_op2(compiler, (op & ~(SLJIT_SET_Z | SLJIT_REWRITABLE_JUMP)), dst, dstw, src1, src1w, src2, src2w));
|
||||
|
||||
/* When dst is a memory operand, its value is stored in SLJIT_TMP_DEST_FREG. */
|
||||
reg = FAST_IS_REG(dst) ? dst : SLJIT_TMP_DEST_REG;
|
||||
|
||||
SLJIT_SKIP_CHECKS(compiler);
|
||||
return sljit_emit_cmp(compiler, ((op & SLJIT_JUMP_IF_ZERO) ? SLJIT_ZERO : SLJIT_NOT_ZERO) | (op & (SLJIT_32 | SLJIT_REWRITABLE_JUMP)), reg, 0, SLJIT_IMM, 0);
|
||||
}
|
||||
|
||||
#endif /* !SLJIT_CONFIG_RISCV && !SLJIT_CONFIG_MIPS && !SLJIT_CONFIG_LOONGARCH */
|
||||
|
||||
#if !(defined SLJIT_CONFIG_ARM && SLJIT_CONFIG_ARM) \
|
||||
&& !(defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC)
|
||||
|
||||
|
|
@ -3687,4 +3903,23 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_local_base(struct sljit_compiler *c
|
|||
|
||||
#endif /* !SLJIT_CONFIG_X86 && !SLJIT_CONFIG_ARM_64 */
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void* sljit_read_only_buffer_start_writing(sljit_uw addr, sljit_uw size, sljit_sw executable_offset)
|
||||
{
|
||||
SLJIT_UNUSED_ARG(size);
|
||||
SLJIT_UNUSED_ARG(executable_offset);
|
||||
|
||||
SLJIT_UPDATE_WX_FLAGS((void*)addr, (void*)(addr + size), 0);
|
||||
return SLJIT_ADD_EXEC_OFFSET(addr, -executable_offset);
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_read_only_buffer_end_writing(sljit_uw addr, sljit_uw size, sljit_sw executable_offset)
|
||||
{
|
||||
SLJIT_UNUSED_ARG(addr);
|
||||
SLJIT_UNUSED_ARG(size);
|
||||
SLJIT_UNUSED_ARG(executable_offset);
|
||||
|
||||
SLJIT_UPDATE_WX_FLAGS((void*)addr, (void*)(addr + size), 1);
|
||||
SLJIT_CACHE_FLUSH((void*)addr, (void*)(addr + size));
|
||||
}
|
||||
|
||||
#endif /* !SLJIT_CONFIG_UNSUPPORTED */
|
||||
|
|
|
|||
|
|
@ -503,6 +503,16 @@ struct sljit_generate_code_buffer {
|
|||
sljit_sw executable_offset;
|
||||
};
|
||||
|
||||
struct sljit_read_only_buffer {
|
||||
struct sljit_read_only_buffer *next;
|
||||
sljit_uw size;
|
||||
/* Label can be replaced by address after sljit_generate_code. */
|
||||
union {
|
||||
struct sljit_label *label;
|
||||
sljit_uw addr;
|
||||
} u;
|
||||
};
|
||||
|
||||
struct sljit_compiler {
|
||||
sljit_s32 error;
|
||||
sljit_s32 options;
|
||||
|
|
@ -705,6 +715,12 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_compiler_verbose(struct sljit_compiler *comp
|
|||
buffer which type is sljit_generate_code_buffer. */
|
||||
#define SLJIT_GENERATE_CODE_BUFFER 0x1
|
||||
|
||||
/* When SLJIT_INDIRECT_CALL is defined, no function context is
|
||||
created for the generated code (see sljit_set_function_context),
|
||||
so the returned pointer cannot be directly called from C code.
|
||||
The flag is ignored when SLJIT_INDIRECT_CALL is not defined. */
|
||||
#define SLJIT_GENERATE_CODE_NO_CONTEXT 0x2
|
||||
|
||||
/* Create executable code from the instruction stream. This is the final step
|
||||
of the code generation, and no more instructions can be emitted after this call.
|
||||
|
||||
|
|
@ -1450,6 +1466,24 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *
|
|||
sljit_s32 src2_reg,
|
||||
sljit_s32 src3, sljit_sw src3w);
|
||||
|
||||
/* The following options are used by sljit_emit_op2_shift. */
|
||||
|
||||
/* The src2 argument is shifted left by an immedate value. */
|
||||
#define SLJIT_SHL_IMM (1 << 9)
|
||||
/* When src2 argument is a register, its value is undefined after the operation. */
|
||||
#define SLJIT_SRC2_UNDEFINED (1 << 10)
|
||||
|
||||
/* Emits an addition operation, where the second argument is shifted by a value.
|
||||
|
||||
op must be SLJIT_ADD | SLJIT_SHL_IMM, where the immedate value is stored in shift_arg
|
||||
|
||||
Flags: - (may destroy flags) */
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2_shift(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_sw shift_arg);
|
||||
|
||||
/* Starting index of opcodes for sljit_emit_op_src
|
||||
and sljit_emit_op_dst. */
|
||||
#define SLJIT_OP_SRC_DST_BASE 112
|
||||
|
|
@ -1629,8 +1663,53 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fcopy(struct sljit_compiler *compi
|
|||
|
||||
/* Label and jump instructions. */
|
||||
|
||||
/* Emits a label which can be the target of jump / mov_addr instructions. */
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compiler *compiler);
|
||||
|
||||
/* Alignment values for sljit_emit_aligned_label. */
|
||||
|
||||
#define SLJIT_LABEL_ALIGN_1 0
|
||||
#define SLJIT_LABEL_ALIGN_2 1
|
||||
#define SLJIT_LABEL_ALIGN_4 2
|
||||
#define SLJIT_LABEL_ALIGN_8 3
|
||||
#define SLJIT_LABEL_ALIGN_16 4
|
||||
#define SLJIT_LABEL_ALIGN_W SLJIT_WORD_SHIFT
|
||||
#define SLJIT_LABEL_ALIGN_P SLJIT_POINTER_SHIFT
|
||||
|
||||
/* Emits a label which address is aligned to a power of 2 value. When some
|
||||
extra space needs to be added to align the label, that space is filled
|
||||
with SLJIT_NOP instructions. These labels usually represent the end of a
|
||||
compilation block, and a new function or some read-only data (e.g. a
|
||||
jump table) follows it. In these typical cases the SLJIT_NOPs are never
|
||||
executed.
|
||||
|
||||
Optionally, buffers for storing read-only data or code can be allocated
|
||||
by this operation. The buffers are passed as a chain list, and a separate
|
||||
memory area is allocated for each item in the list. All buffers are aligned
|
||||
to SLJIT_NOP instruction size, and their starting address is returned as
|
||||
as a label. The sljit_get_label_abs_addr function or the SLJIT_MOV_ABS_ADDR
|
||||
operation can be used to get the real address. The label of the first buffer
|
||||
is always the same as the returned label. The buffers are initially
|
||||
initialized with SLJIT_NOP instructions. The alignment of the buffers can
|
||||
be controlled by their starting address and sizes. If the starting address
|
||||
is aligned to N, and size is also divisible by N, the next buffer is aligned
|
||||
to N. I.e. if a buffer is 16 byte aligned, and its size is divisible by 4,
|
||||
the next buffer is 4 byte aligned. Note: if a buffer is N (>=2) byte aligned,
|
||||
it is also N/2 byte aligned.
|
||||
|
||||
align represents the alignment, and its value can
|
||||
be specified by SLJIT_LABEL_* constants
|
||||
|
||||
buffers is a list of read-only buffers stored in a chain list.
|
||||
After calling sljit_generate_code, these buffers can be
|
||||
modified by sljit_read_only_buffer_start_writing() /
|
||||
sljit_read_only_buffer_end_writing() functions
|
||||
|
||||
Note: the constant pool (if present) may be stored before the label. */
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_aligned_label(struct sljit_compiler *compiler,
|
||||
sljit_s32 alignment, struct sljit_read_only_buffer *buffers);
|
||||
|
||||
/* The SLJIT_FAST_CALL is a calling method for creating lightweight function
|
||||
calls. This type of calls preserve the values of all registers and stack
|
||||
frame. Unlike normal function calls, the enter and return operations must
|
||||
|
|
@ -1757,16 +1836,16 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compi
|
|||
#define SLJIT_CALL_REG_ARG 39
|
||||
|
||||
/* The target can be changed during runtime (see: sljit_set_jump_addr). */
|
||||
#define SLJIT_REWRITABLE_JUMP 0x1000
|
||||
#define SLJIT_REWRITABLE_JUMP 0x10000
|
||||
/* 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
|
||||
#define SLJIT_CALL_RETURN 0x20000
|
||||
|
||||
/* 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 must be between SLJIT_JUMP and SLJIT_FAST_CALL
|
||||
type can be combined (or'ed) with SLJIT_REWRITABLE_JUMP
|
||||
|
||||
Flags: does not modify flags. */
|
||||
|
|
@ -1780,31 +1859,56 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
|
|||
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.
|
||||
/* Integer comparison operation. In most architectures it is implemented
|
||||
as a compare (sljit_emit_op2u with SLJIT_SUB) operation followed by
|
||||
an sljit_emit_jump. However, some architectures (e.g: ARM64 or RISCV)
|
||||
may optimize the generated code further. 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
|
||||
type can be combined (or'ed) with SLJIT_32 or 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.
|
||||
/* Floating point comparison operation. 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
|
||||
(e.g: MIPS) may optimize the generated code further. 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
|
||||
type can be combined (or'ed) with SLJIT_32 or SLJIT_REWRITABLE_JUMP
|
||||
|
||||
Flags: destroy flags.
|
||||
Note: when an operand is NaN the behaviour depends on the comparison type. */
|
||||
Note: when any 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);
|
||||
|
||||
/* The following flags are used by sljit_emit_op2cmpz(). */
|
||||
#define SLJIT_JUMP_IF_NON_ZERO 0
|
||||
#define SLJIT_JUMP_IF_ZERO SLJIT_SET_Z
|
||||
|
||||
/* Perform an integer arithmetic operation, then its result is compared to
|
||||
zero. In most architectures it is implemented as an sljit_emit_op2
|
||||
followed by an sljit_emit_jump. However, some architectures (e.g: RISCV)
|
||||
may optimize the generated code further. It is suggested to use this
|
||||
operation form when appropriate (e.g. for loops with counters).
|
||||
|
||||
op must be an sljit_emit_op2 operation where zero flag can be set,
|
||||
op can be combined with SLJIT_SET_* status flag setters except
|
||||
SLJIT_SET_Z, SLJIT_REWRITABLE_JUMP or SLJIT_JUMP_IF_* option bits.
|
||||
|
||||
Note: SLJIT_JUMP_IF_NON_ZERO is the default operation if neither
|
||||
SLJIT_JUMP_IF_ZERO or SLJIT_JUMP_IF_NON_ZERO is specified.
|
||||
Flags: sets the variable flag depending on op argument, the
|
||||
zero flag is undefined. */
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_op2cmpz(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);
|
||||
|
||||
/* 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. */
|
||||
|
|
@ -1831,7 +1935,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compi
|
|||
/* 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.
|
||||
by 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).
|
||||
|
|
@ -1844,27 +1948,55 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co
|
|||
sljit_s32 dst, sljit_sw dstw,
|
||||
sljit_s32 type);
|
||||
|
||||
/* The following flags are used by sljit_emit_select(). */
|
||||
|
||||
/* Compare src1 and src2_reg operands before executing select
|
||||
(i.e. converts the select operation to a min/max operation). */
|
||||
#define SLJIT_COMPARE_SELECT SLJIT_SET_Z
|
||||
|
||||
/* Emit a conditional select instruction which moves src1 to dst_reg,
|
||||
if the condition is satisfied, or src2_reg to dst_reg otherwise.
|
||||
if the conditional flag is set, or src2_reg to dst_reg otherwise.
|
||||
The conditional flag should be set before executing the select
|
||||
instruction unless SLJIT_COMPARE_SELECT is specified.
|
||||
|
||||
type must be between SLJIT_EQUAL and SLJIT_ORDERED_LESS_EQUAL
|
||||
when SLJIT_COMPARE_SELECT option is NOT specified
|
||||
type must be between SLJIT_LESS and SLJIT_SET_SIG_LESS_EQUAL
|
||||
when SLJIT_COMPARE_SELECT option is specified
|
||||
type can be combined (or'ed) with SLJIT_32 to move 32 bit
|
||||
register values instead of word sized ones
|
||||
type can be combined (or'ed) with SLJIT_COMPARE_SELECT
|
||||
which compares src1 and src2_reg before executing the select
|
||||
dst_reg and src2_reg must be valid registers
|
||||
src1 must be valid operand
|
||||
|
||||
Note: if src1 is a memory operand, its value
|
||||
might be loaded even if the condition is false.
|
||||
might be loaded even if the condition is false
|
||||
|
||||
Flags: - (does not modify flags) */
|
||||
Note: when SLJIT_COMPARE_SELECT is specified, the status flag
|
||||
bits might not represent the result of a normal compare
|
||||
operation, hence flags are not specified after the operation
|
||||
|
||||
Note: if sljit_has_cpu_feature(SLJIT_HAS_CMOV) returns with a non-zero value:
|
||||
(a) conditional register move (dst_reg==src2_reg, src1 is register)
|
||||
can be performed using a single instruction, except on RISCV,
|
||||
where three instructions are needed
|
||||
(b) conditional clearing (dst_reg==src2_reg, src1==SLJIT_IMM,
|
||||
src1w==0) can be performed using a single instruction,
|
||||
except on x86, where two instructions are needed
|
||||
|
||||
Flags:
|
||||
When SLJIT_COMPARE_SELECT is NOT specified: - (does not modify flags)
|
||||
When SLJIT_COMPARE_SELECT is specified: - (may destroy flags) */
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *compiler, sljit_s32 type,
|
||||
sljit_s32 dst_reg,
|
||||
sljit_s32 src1, sljit_sw src1w,
|
||||
sljit_s32 src2_reg);
|
||||
|
||||
/* Emit a conditional floating point select instruction which moves
|
||||
src1 to dst_reg, if the condition is satisfied, or src2_reg to
|
||||
dst_reg otherwise.
|
||||
src1 to dst_reg, if the conditional flag is set, or src2_reg to
|
||||
dst_reg otherwise. The conditional flag should be set before
|
||||
executing the select instruction.
|
||||
|
||||
type must be between SLJIT_EQUAL and SLJIT_ORDERED_LESS_EQUAL
|
||||
type can be combined (or'ed) with SLJIT_32 to move 32 bit
|
||||
|
|
@ -2301,26 +2433,66 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_atomic_store(struct sljit_compiler
|
|||
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)
|
||||
/* Store a value that can be changed at runtime. The constant
|
||||
can be managed by sljit_get_const_addr and sljit_set_const.
|
||||
|
||||
op must be SLJIT_MOV, SLJIT_MOV32, SLJIT_MOV_S32,
|
||||
SLJIT_MOV_U8, SLJIT_MOV32_U8
|
||||
|
||||
Note: when SLJIT_MOV_U8 is used, and dst is a register,
|
||||
init_value supports a 9 bit signed value between [-256..255]
|
||||
|
||||
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);
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 op,
|
||||
sljit_s32 dst, sljit_sw dstw,
|
||||
sljit_sw init_value);
|
||||
|
||||
/* Opcodes for sljit_emit_mov_addr. */
|
||||
|
||||
/* The address is suitable for jump/call target. */
|
||||
#define SLJIT_MOV_ADDR 0
|
||||
/* The address is suitable for reading memory. */
|
||||
#define SLJIT_MOV_ABS_ADDR 1
|
||||
/* Add absolute address. */
|
||||
#define SLJIT_ADD_ABS_ADDR 2
|
||||
|
||||
/* Store the value of a label (see: sljit_set_label / sljit_set_target)
|
||||
Flags: - (does not modify flags) */
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_mov_addr(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw);
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_op_addr(struct sljit_compiler *compiler, sljit_s32 op,
|
||||
sljit_s32 dst, sljit_sw dstw);
|
||||
|
||||
/* Returns the address of a label after sljit_generate_code is called, and
|
||||
before the compiler is freed by sljit_free_compiler. It is recommended
|
||||
to save these addresses elsewhere before sljit_free_compiler is called.
|
||||
|
||||
The address returned by sljit_get_label_addr is suitable for a jump/call
|
||||
target, and the address returned by sljit_get_label_abs_addr is suitable
|
||||
for reading memory. */
|
||||
|
||||
/* Provides the address of label, jump and const instructions after sljit_generate_code
|
||||
is called. The returned value is unspecified before the sljit_generate_code call.
|
||||
Since these structures are freed by sljit_free_compiler, the addresses must be
|
||||
preserved by the user program elsewere. */
|
||||
static SLJIT_INLINE sljit_uw sljit_get_label_addr(struct sljit_label *label) { return label->u.addr; }
|
||||
#if (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2)
|
||||
static SLJIT_INLINE sljit_uw sljit_get_label_abs_addr(struct sljit_label *label) { return label->u.addr & ~(sljit_uw)1; }
|
||||
#else /* !SLJIT_CONFIG_ARM_THUMB2 */
|
||||
static SLJIT_INLINE sljit_uw sljit_get_label_abs_addr(struct sljit_label *label) { return label->u.addr; }
|
||||
#endif /* SLJIT_CONFIG_ARM_THUMB2 */
|
||||
|
||||
/* Returns the address of jump and const instructions after sljit_generate_code
|
||||
is called, and before the compiler is freed by sljit_free_compiler. It is
|
||||
recommended to save these addresses elsewhere before sljit_free_compiler is called. */
|
||||
|
||||
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);
|
||||
/* The op opcode must be set to the same value that was passed to sljit_emit_const. */
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_s32 op, sljit_sw new_constant, sljit_sw executable_offset);
|
||||
|
||||
/* Only a single buffer is writable at a time, so sljit_read_only_buffer_end_writing()
|
||||
must be called before sljit_read_only_buffer_start_writing() is called again. */
|
||||
SLJIT_API_FUNC_ATTRIBUTE void* sljit_read_only_buffer_start_writing(sljit_uw addr, sljit_uw size, sljit_sw executable_offset);
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_read_only_buffer_end_writing(sljit_uw addr, sljit_uw size, sljit_sw executable_offset);
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* CPU specific functions */
|
||||
|
|
@ -2369,13 +2541,16 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *c
|
|||
|
||||
/* 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. */
|
||||
/* Flags were set by a SUB or SUBC 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
|
||||
|
||||
/* Flags were set by sljit_emit_op2cmpz operation. */
|
||||
#define SLJIT_CURRENT_FLAGS_OP2CMPZ 0x08
|
||||
|
||||
/* 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.
|
||||
|
|
@ -2405,10 +2580,14 @@ static SLJIT_INLINE struct sljit_const *sljit_get_next_const(struct sljit_const
|
|||
|
||||
/* A number starting from 0 is assigned to each label, which
|
||||
represents its creation index. The first label created by the
|
||||
compiler has index 0, the second has index 1, the third has
|
||||
index 2, and so on. The returned value is unspecified after
|
||||
sljit_generate_code() is called. */
|
||||
static SLJIT_INLINE sljit_uw sljit_get_label_index(struct sljit_label *label) { return label->u.index; }
|
||||
compiler has index 0, the second one has index 1, the third one
|
||||
has index 2, and so on. The returned value is unspecified after
|
||||
sljit_generate_code() is called.
|
||||
|
||||
It is recommended to use this function to get the creation index
|
||||
of a label, since sljit_emit_label() may return with the last label,
|
||||
if no code is generated since the last sljit_emit_label() call. */
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_uw sljit_get_label_index(struct sljit_label *label);
|
||||
|
||||
/* The sljit_jump_has_label() and sljit_jump_has_target() functions
|
||||
returns non-zero value if a label or target is set for the jump
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ static const sljit_u8 freg_ebit_map[((SLJIT_NUMBER_OF_FLOAT_REGISTERS + 2) << 1)
|
|||
#define VN(vn) (((sljit_ins)freg_map[vn] << 16) | ((sljit_ins)freg_ebit_map[vn] << 7))
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Instrucion forms */
|
||||
/* Instruction forms */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/* The instruction includes the AL condition.
|
||||
|
|
@ -771,6 +771,12 @@ static SLJIT_INLINE sljit_sw mov_addr_get_length(struct sljit_jump *jump, sljit_
|
|||
#endif /* SLJIT_CONFIG_ARM_V6 */
|
||||
}
|
||||
|
||||
static SLJIT_INLINE sljit_ins *process_extended_label(sljit_ins *code_ptr, struct sljit_extended_label *ext_label)
|
||||
{
|
||||
SLJIT_ASSERT(ext_label->label.u.index == SLJIT_LABEL_ALIGNED);
|
||||
return (sljit_ins*)((sljit_uw)code_ptr & ~(ext_label->data));
|
||||
}
|
||||
|
||||
#if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
|
||||
|
||||
static void reduce_code_size(struct sljit_compiler *compiler)
|
||||
|
|
@ -882,7 +888,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
|||
struct sljit_const *const_;
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_PTR(check_sljit_generate_code(compiler));
|
||||
CHECK_PTR(check_sljit_generate_code(compiler, options));
|
||||
|
||||
/* Second code generation pass. */
|
||||
#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
|
||||
|
|
@ -945,6 +951,11 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
|||
SLJIT_ASSERT(!const_ || const_->addr >= word_count);
|
||||
|
||||
if (next_min_addr == next_label_size) {
|
||||
if (label->u.index >= SLJIT_LABEL_ALIGNED) {
|
||||
code_ptr = process_extended_label(code_ptr, (struct sljit_extended_label*)label);
|
||||
*code_ptr = buf_ptr[-1];
|
||||
}
|
||||
|
||||
label->u.addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
|
||||
label->size = (sljit_uw)(code_ptr - code);
|
||||
label = label->next;
|
||||
|
|
@ -1011,6 +1022,9 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
|||
} while (buf);
|
||||
|
||||
if (label && label->size == word_count) {
|
||||
if (label->u.index >= SLJIT_LABEL_ALIGNED)
|
||||
code_ptr = process_extended_label(code_ptr, (struct sljit_extended_label*)label);
|
||||
|
||||
label->u.addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
|
||||
label->size = (sljit_uw)(code_ptr - code);
|
||||
label = label->next;
|
||||
|
|
@ -1111,17 +1125,23 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
|||
const_ = compiler->consts;
|
||||
while (const_) {
|
||||
buf_ptr = (sljit_ins*)const_->addr;
|
||||
const_->addr = (sljit_uw)code_ptr;
|
||||
|
||||
code_ptr[0] = (sljit_ins)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). */
|
||||
set_const_value((sljit_uw)code_ptr, executable_offset, *buf_ptr, 0);
|
||||
code_ptr += 2;
|
||||
/* Note: MVN = (MOV ^ 0x400000) */
|
||||
SLJIT_ASSERT((*buf_ptr & 0xfdb00000) == MOV || (*buf_ptr & 0xfd100000) == LDR);
|
||||
|
||||
if ((*buf_ptr & 0x4000000) != 0) {
|
||||
const_->addr = (sljit_uw)code_ptr;
|
||||
|
||||
code_ptr[0] = (sljit_ins)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). */
|
||||
set_const_value((sljit_uw)code_ptr, executable_offset, *buf_ptr, 0);
|
||||
code_ptr += 2;
|
||||
}
|
||||
|
||||
const_ = const_->next;
|
||||
}
|
||||
|
|
@ -1800,7 +1820,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
|
|||
src2 = TMP_REG2;
|
||||
} else
|
||||
compiler->shift_imm = (sljit_uw)(-(sljit_sw)compiler->shift_imm) & 0x1f;
|
||||
/* fallthrough */
|
||||
SLJIT_FALLTHROUGH
|
||||
|
||||
case SLJIT_ROTR:
|
||||
shift_type = 3;
|
||||
|
|
@ -2613,6 +2633,54 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *
|
|||
return push_inst(compiler, ORR | RD(dst_reg) | RN(dst_reg) | RM8(TMP_REG2) | ((sljit_ins)(is_left ? 1 : 0) << 5) | 0x10 | RM(TMP_REG1));
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2_shift(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_sw shift_arg)
|
||||
{
|
||||
sljit_s32 dst_r, tmp_r;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_op2_shift(compiler, op, dst, dstw, src1, src1w, src2, src2w, shift_arg));
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
ADJUST_LOCAL_OFFSET(src1, src1w);
|
||||
ADJUST_LOCAL_OFFSET(src2, src2w);
|
||||
|
||||
shift_arg &= 0x1f;
|
||||
|
||||
if (src2 == SLJIT_IMM) {
|
||||
src2w = src2w << shift_arg;
|
||||
shift_arg = 0;
|
||||
}
|
||||
|
||||
if (shift_arg == 0) {
|
||||
SLJIT_SKIP_CHECKS(compiler);
|
||||
return sljit_emit_op2(compiler, GET_OPCODE(op), dst, dstw, src1, src1w, src2, src2w);
|
||||
}
|
||||
|
||||
if (src1 == SLJIT_IMM) {
|
||||
FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)src1w));
|
||||
src1 = TMP_REG1;
|
||||
} else if (src1 & SLJIT_MEM) {
|
||||
FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, TMP_REG1, src1, src1w, TMP_REG1));
|
||||
src1 = TMP_REG1;
|
||||
}
|
||||
|
||||
if (src2 & SLJIT_MEM) {
|
||||
tmp_r = (src1 == TMP_REG1) ? TMP_REG2 : TMP_REG1;
|
||||
FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, tmp_r, src2, src2w, tmp_r));
|
||||
src2 = tmp_r;
|
||||
}
|
||||
|
||||
dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
|
||||
FAIL_IF(push_inst(compiler, ADD | RD(dst_r) | RN(src1) | RM(src2) | ((sljit_ins)shift_arg << 7)));
|
||||
|
||||
if (dst & SLJIT_MEM)
|
||||
return emit_op_mem(compiler, WORD_SIZE, dst_r, dst, dstw, TMP_REG1);
|
||||
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)
|
||||
{
|
||||
|
|
@ -2624,9 +2692,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *comp
|
|||
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
|
||||
if (FAST_IS_REG(src)) {
|
||||
if (src != TMP_REG2)
|
||||
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));
|
||||
|
|
@ -2656,8 +2725,11 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_dst(struct sljit_compiler *comp
|
|||
case SLJIT_FAST_ENTER:
|
||||
SLJIT_ASSERT(reg_map[TMP_REG2] == 14);
|
||||
|
||||
if (FAST_IS_REG(dst))
|
||||
if (FAST_IS_REG(dst)) {
|
||||
if (dst == TMP_REG2)
|
||||
return SLJIT_SUCCESS;
|
||||
return push_inst(compiler, MOV | RD(dst) | RM(TMP_REG2));
|
||||
}
|
||||
break;
|
||||
case SLJIT_GET_RETURN_ADDRESS:
|
||||
size = GET_SAVED_REGISTERS_SIZE(compiler->scratches, compiler->saveds - SLJIT_KEPT_SAVEDS_COUNT(compiler->options), 0);
|
||||
|
|
@ -3065,7 +3137,7 @@ static sljit_ins get_cc(struct sljit_compiler *compiler, sljit_s32 type)
|
|||
case SLJIT_CARRY:
|
||||
if (compiler->status_flags_state & SLJIT_CURRENT_FLAGS_ADD)
|
||||
return 0x20000000;
|
||||
/* fallthrough */
|
||||
SLJIT_FALLTHROUGH
|
||||
|
||||
case SLJIT_LESS:
|
||||
return 0x30000000;
|
||||
|
|
@ -3073,7 +3145,7 @@ static sljit_ins get_cc(struct sljit_compiler *compiler, sljit_s32 type)
|
|||
case SLJIT_NOT_CARRY:
|
||||
if (compiler->status_flags_state & SLJIT_CURRENT_FLAGS_ADD)
|
||||
return 0x30000000;
|
||||
/* fallthrough */
|
||||
SLJIT_FALLTHROUGH
|
||||
|
||||
case SLJIT_GREATER_EQUAL:
|
||||
return 0x20000000;
|
||||
|
|
@ -3108,7 +3180,7 @@ static sljit_ins get_cc(struct sljit_compiler *compiler, sljit_s32 type)
|
|||
case SLJIT_OVERFLOW:
|
||||
if (!(compiler->status_flags_state & (SLJIT_CURRENT_FLAGS_ADD | SLJIT_CURRENT_FLAGS_SUB)))
|
||||
return 0x10000000;
|
||||
/* fallthrough */
|
||||
SLJIT_FALLTHROUGH
|
||||
|
||||
case SLJIT_UNORDERED:
|
||||
return 0x60000000;
|
||||
|
|
@ -3116,7 +3188,7 @@ static sljit_ins get_cc(struct sljit_compiler *compiler, sljit_s32 type)
|
|||
case SLJIT_NOT_OVERFLOW:
|
||||
if (!(compiler->status_flags_state & (SLJIT_CURRENT_FLAGS_ADD | SLJIT_CURRENT_FLAGS_SUB)))
|
||||
return 0x00000000;
|
||||
/* fallthrough */
|
||||
SLJIT_FALLTHROUGH
|
||||
|
||||
case SLJIT_ORDERED:
|
||||
return 0x70000000;
|
||||
|
|
@ -3150,6 +3222,65 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compi
|
|||
return label;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_aligned_label(struct sljit_compiler *compiler,
|
||||
sljit_s32 alignment, struct sljit_read_only_buffer *buffers)
|
||||
{
|
||||
sljit_uw mask, i;
|
||||
struct sljit_label *label;
|
||||
struct sljit_label *next_label;
|
||||
struct sljit_extended_label *ext_label;
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_PTR(check_sljit_emit_aligned_label(compiler, alignment, buffers));
|
||||
|
||||
sljit_reset_read_only_buffers(buffers);
|
||||
|
||||
#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
|
||||
if (SLJIT_UNLIKELY(compiler->cpool_diff != CONST_POOL_EMPTY))
|
||||
PTR_FAIL_IF(push_cpool(compiler));
|
||||
#endif /* SLJIT_CONFIG_ARM_V6 */
|
||||
|
||||
if (alignment <= SLJIT_LABEL_ALIGN_4) {
|
||||
SLJIT_SKIP_CHECKS(compiler);
|
||||
label = sljit_emit_label(compiler);
|
||||
PTR_FAIL_IF(!label);
|
||||
} else {
|
||||
/* The used space is filled with NOPs. */
|
||||
mask = ((sljit_uw)1 << alignment) - sizeof(sljit_ins);
|
||||
|
||||
for (i = (mask >> 2); i != 0; i--)
|
||||
PTR_FAIL_IF(push_inst(compiler, NOP));
|
||||
|
||||
ext_label = (struct sljit_extended_label*)ensure_abuf(compiler, sizeof(struct sljit_extended_label));
|
||||
PTR_FAIL_IF(!ext_label);
|
||||
set_extended_label(ext_label, compiler, SLJIT_LABEL_ALIGNED, mask);
|
||||
label = &ext_label->label;
|
||||
}
|
||||
|
||||
if (buffers == NULL)
|
||||
return label;
|
||||
|
||||
next_label = label;
|
||||
|
||||
while (1) {
|
||||
buffers->u.label = next_label;
|
||||
|
||||
for (i = (buffers->size + 3) >> 2; i > 0; i--)
|
||||
PTR_FAIL_IF(push_inst(compiler, NOP));
|
||||
|
||||
buffers = buffers->next;
|
||||
|
||||
if (buffers == NULL)
|
||||
break;
|
||||
|
||||
SLJIT_SKIP_CHECKS(compiler);
|
||||
next_label = sljit_emit_label(compiler);
|
||||
PTR_FAIL_IF(!next_label);
|
||||
}
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type)
|
||||
{
|
||||
struct sljit_jump *jump;
|
||||
|
|
@ -3604,7 +3735,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *comp
|
|||
sljit_s32 src1, sljit_sw src1w,
|
||||
sljit_s32 src2_reg)
|
||||
{
|
||||
sljit_ins cc, tmp;
|
||||
sljit_ins cc, tmp, tmp2;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_select(compiler, type, dst_reg, src1, src1w, src2_reg));
|
||||
|
|
@ -3615,7 +3746,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *comp
|
|||
src1 = src2_reg;
|
||||
src1w = 0;
|
||||
src2_reg = dst_reg;
|
||||
type ^= 0x1;
|
||||
if (!(type & SLJIT_COMPARE_SELECT))
|
||||
type ^= 0x1;
|
||||
}
|
||||
|
||||
if (src1 & SLJIT_MEM) {
|
||||
|
|
@ -3624,7 +3756,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *comp
|
|||
if (src2_reg != dst_reg) {
|
||||
src1 = src2_reg;
|
||||
src1w = 0;
|
||||
type ^= 0x1;
|
||||
if (!(type & SLJIT_COMPARE_SELECT))
|
||||
type ^= 0x1;
|
||||
} else {
|
||||
src1 = TMP_REG1;
|
||||
src1w = 0;
|
||||
|
|
@ -3632,29 +3765,48 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *comp
|
|||
} else if (dst_reg != src2_reg)
|
||||
FAIL_IF(push_inst(compiler, MOV | RD(dst_reg) | RM(src2_reg)));
|
||||
|
||||
cc = get_cc(compiler, type & ~SLJIT_32);
|
||||
if (type & SLJIT_COMPARE_SELECT)
|
||||
type ^= 0x1;
|
||||
|
||||
cc = get_cc(compiler, type & ~(SLJIT_32 | SLJIT_COMPARE_SELECT));
|
||||
|
||||
if (SLJIT_UNLIKELY(src1 == SLJIT_IMM)) {
|
||||
tmp = get_imm((sljit_uw)src1w);
|
||||
if (tmp)
|
||||
if (tmp) {
|
||||
if (type & SLJIT_COMPARE_SELECT)
|
||||
FAIL_IF(push_inst(compiler, (CMP | SET_FLAGS | RN(dst_reg) | tmp)));
|
||||
return push_inst(compiler, ((MOV | RD(dst_reg) | tmp) & ~COND_MASK) | cc);
|
||||
}
|
||||
|
||||
tmp = get_imm(~(sljit_uw)src1w);
|
||||
if (tmp && (type & SLJIT_COMPARE_SELECT)) {
|
||||
tmp2 = get_imm((sljit_uw)-src1w);
|
||||
if (tmp2)
|
||||
FAIL_IF(push_inst(compiler, (CMN | SET_FLAGS | RN(dst_reg) | tmp2)));
|
||||
else
|
||||
tmp = 0;
|
||||
}
|
||||
|
||||
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_ins)src1w;
|
||||
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 /* !SLJIT_CONFIG_ARM_V7 */
|
||||
if (!(type & SLJIT_COMPARE_SELECT)) {
|
||||
tmp = (sljit_ins)src1w;
|
||||
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));
|
||||
}
|
||||
#endif /* SLJIT_CONFIG_ARM_V7 */
|
||||
|
||||
FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)src1w));
|
||||
src1 = TMP_REG1;
|
||||
#endif /* SLJIT_CONFIG_ARM_V7 */
|
||||
}
|
||||
|
||||
if (type & SLJIT_COMPARE_SELECT)
|
||||
FAIL_IF(push_inst(compiler, (CMP | SET_FLAGS | RN(dst_reg) | RM(src1))));
|
||||
|
||||
return push_inst(compiler, ((MOV | RD(dst_reg) | RM(src1)) & ~COND_MASK) | cc);
|
||||
}
|
||||
|
||||
|
|
@ -4688,13 +4840,19 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_atomic_store(struct sljit_compiler
|
|||
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)
|
||||
#define SLJIT_EMIT_CONST_U8(c) \
|
||||
(((c) & 0x100) != 0 ? (MVN | SRC2_IMM | (~(c) & 0xff)) : (MOV | SRC2_IMM | ((c) & 0xff)))
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 op,
|
||||
sljit_s32 dst, sljit_sw dstw,
|
||||
sljit_sw init_value)
|
||||
{
|
||||
struct sljit_const *const_;
|
||||
sljit_s32 dst_r;
|
||||
sljit_s32 mem_flags = WORD_SIZE;
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_PTR(check_sljit_emit_const(compiler, dst, dstw, init_value));
|
||||
CHECK_PTR(check_sljit_emit_const(compiler, op, dst, dstw, init_value));
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
|
||||
const_ = (struct sljit_const*)ensure_abuf(compiler, sizeof(struct sljit_const));
|
||||
|
|
@ -4703,35 +4861,52 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi
|
|||
|
||||
dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
|
||||
|
||||
if (GET_OPCODE(op) == SLJIT_MOV_U8) {
|
||||
PTR_FAIL_IF(push_inst(compiler, SLJIT_EMIT_CONST_U8(init_value) | RD(dst_r)));
|
||||
mem_flags = BYTE_SIZE;
|
||||
} else {
|
||||
#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
|
||||
PTR_FAIL_IF(push_inst_with_unique_literal(compiler,
|
||||
EMIT_DATA_TRANSFER(WORD_SIZE | LOAD_DATA, 1, dst_r, TMP_PC, 0), (sljit_ins)init_value));
|
||||
compiler->patches++;
|
||||
PTR_FAIL_IF(push_inst_with_unique_literal(compiler,
|
||||
EMIT_DATA_TRANSFER(WORD_SIZE | LOAD_DATA, 1, dst_r, TMP_PC, 0), (sljit_ins)init_value));
|
||||
compiler->patches++;
|
||||
#else /* !SLJIT_CONFIG_ARM_V6 */
|
||||
PTR_FAIL_IF(emit_imm(compiler, dst_r, init_value));
|
||||
PTR_FAIL_IF(emit_imm(compiler, dst_r, init_value));
|
||||
#endif /* SLJIT_CONFIG_ARM_V6 */
|
||||
}
|
||||
|
||||
if (dst & SLJIT_MEM)
|
||||
PTR_FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG2, dst, dstw, TMP_REG1));
|
||||
PTR_FAIL_IF(emit_op_mem(compiler, mem_flags, TMP_REG2, dst, dstw, TMP_REG1));
|
||||
|
||||
return const_;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_mov_addr(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_op_addr(struct sljit_compiler *compiler, sljit_s32 op,
|
||||
sljit_s32 dst, sljit_sw dstw)
|
||||
{
|
||||
struct sljit_jump *jump;
|
||||
sljit_s32 dst_r;
|
||||
sljit_s32 dst_r, target_r;
|
||||
SLJIT_UNUSED_ARG(op);
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_PTR(check_sljit_emit_mov_addr(compiler, dst, dstw));
|
||||
CHECK_PTR(check_sljit_emit_op_addr(compiler, op, dst, dstw));
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
|
||||
dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
|
||||
|
||||
if (op != SLJIT_ADD_ABS_ADDR)
|
||||
target_r = dst_r;
|
||||
else {
|
||||
target_r = TMP_REG1;
|
||||
|
||||
if (dst & SLJIT_MEM)
|
||||
PTR_FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, TMP_REG2, dst, dstw, TMP_REG1));
|
||||
}
|
||||
|
||||
#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
|
||||
PTR_FAIL_IF(push_inst_with_unique_literal(compiler, EMIT_DATA_TRANSFER(WORD_SIZE | LOAD_DATA, 1, dst_r, TMP_PC, 0), 0));
|
||||
PTR_FAIL_IF(push_inst_with_unique_literal(compiler, EMIT_DATA_TRANSFER(WORD_SIZE | LOAD_DATA, 1, target_r, TMP_PC, 0), 0));
|
||||
compiler->patches++;
|
||||
#else /* !SLJIT_CONFIG_ARM_V6 */
|
||||
PTR_FAIL_IF(push_inst(compiler, RD(dst_r)));
|
||||
PTR_FAIL_IF(push_inst(compiler, RD(target_r)));
|
||||
#endif /* SLJIT_CONFIG_ARM_V6 */
|
||||
|
||||
jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
|
||||
|
|
@ -4742,6 +4917,9 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_mov_addr(struct sljit_com
|
|||
compiler->size += 1;
|
||||
#endif /* SLJIT_CONFIG_ARM_V7 */
|
||||
|
||||
if (op == SLJIT_ADD_ABS_ADDR)
|
||||
PTR_FAIL_IF(push_inst(compiler, ADD | RD(dst_r) | RN(dst_r) | RM(TMP_REG1)));
|
||||
|
||||
if (dst & SLJIT_MEM)
|
||||
PTR_FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG2, dst, dstw, TMP_REG1));
|
||||
return jump;
|
||||
|
|
@ -4752,7 +4930,21 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_ta
|
|||
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)
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_s32 op, sljit_sw new_constant, sljit_sw executable_offset)
|
||||
{
|
||||
set_const_value(addr, executable_offset, (sljit_uw)new_constant, 1);
|
||||
sljit_ins *inst;
|
||||
|
||||
if (GET_OPCODE(op) != SLJIT_MOV_U8) {
|
||||
set_const_value(addr, executable_offset, (sljit_uw)new_constant, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
inst = (sljit_ins*)addr;
|
||||
SLJIT_ASSERT((inst[0] & 0xfff00000) == (MOV | SRC2_IMM) || (inst[0] & 0xfff00000) == (MVN | SRC2_IMM));
|
||||
|
||||
SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 0);
|
||||
*inst = SLJIT_EMIT_CONST_U8(new_constant) | (*inst & 0xf000);
|
||||
SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 1);
|
||||
inst = (sljit_ins*)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,9 +24,15 @@
|
|||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef __ARM_FEATURE_ATOMICS
|
||||
#define ARM_ATOMIC_INFO " (LSE)"
|
||||
#else
|
||||
#define ARM_ATOMIC_INFO ""
|
||||
#endif
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE const char* sljit_get_platform_name(void)
|
||||
{
|
||||
return "ARM-64" SLJIT_CPUINFO;
|
||||
return "ARM-64" ARM_ATOMIC_INFO SLJIT_CPUINFO;
|
||||
}
|
||||
|
||||
/* Length of an instruction word */
|
||||
|
|
@ -64,7 +70,7 @@ static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 3] = {
|
|||
#define VM(vm) ((sljit_ins)freg_map[vm] << 16)
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Instrucion forms */
|
||||
/* Instruction forms */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
#define ADC 0x9a000000
|
||||
|
|
@ -91,6 +97,7 @@ static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 3] = {
|
|||
#define CLZ 0xdac01000
|
||||
#define CSEL 0x9a800000
|
||||
#define CSINC 0x9a800400
|
||||
#define CSINV 0xda800000
|
||||
#define DMB_SY 0xd5033fbf
|
||||
#define DUP_e 0x0e000400
|
||||
#define DUP_g 0x0e000c00
|
||||
|
|
@ -385,6 +392,12 @@ static SLJIT_INLINE void generate_jump_or_mov_addr(struct sljit_jump *jump, slji
|
|||
buf_ptr[3] = MOVK | ((sljit_ins)((sljit_uw)addr >> 48) << 5) | (3 << 21) | dst;
|
||||
}
|
||||
|
||||
static SLJIT_INLINE sljit_ins *process_extended_label(sljit_ins *code_ptr, struct sljit_extended_label *ext_label)
|
||||
{
|
||||
SLJIT_ASSERT(ext_label->label.u.index == SLJIT_LABEL_ALIGNED);
|
||||
return (sljit_ins*)((sljit_uw)code_ptr & ~(ext_label->data));
|
||||
}
|
||||
|
||||
static void reduce_code_size(struct sljit_compiler *compiler)
|
||||
{
|
||||
struct sljit_label *label;
|
||||
|
|
@ -499,7 +512,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
|||
struct sljit_const *const_;
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_PTR(check_sljit_generate_code(compiler));
|
||||
CHECK_PTR(check_sljit_generate_code(compiler, options));
|
||||
|
||||
reduce_code_size(compiler);
|
||||
|
||||
|
|
@ -529,6 +542,11 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
|||
|
||||
/* These structures are ordered by their address. */
|
||||
if (next_min_addr == next_label_size) {
|
||||
if (label->u.index >= SLJIT_LABEL_ALIGNED) {
|
||||
code_ptr = process_extended_label(code_ptr, (struct sljit_extended_label*)label);
|
||||
*code_ptr = buf_ptr[-1];
|
||||
}
|
||||
|
||||
label->u.addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
|
||||
label->size = (sljit_uw)(code_ptr - code);
|
||||
label = label->next;
|
||||
|
|
@ -565,6 +583,9 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
|||
} while (buf);
|
||||
|
||||
if (label && label->size == word_count) {
|
||||
if (label->u.index >= SLJIT_LABEL_ALIGNED)
|
||||
code_ptr = process_extended_label(code_ptr, (struct sljit_extended_label*)label);
|
||||
|
||||
label->u.addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
|
||||
label->size = (sljit_uw)(code_ptr - code);
|
||||
label = label->next;
|
||||
|
|
@ -884,7 +905,7 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
|
|||
if (flags & ARG1_IMM)
|
||||
break;
|
||||
imm = -imm;
|
||||
/* Fall through. */
|
||||
SLJIT_FALLTHROUGH
|
||||
case SLJIT_ADD:
|
||||
if (op != SLJIT_SUB)
|
||||
compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD;
|
||||
|
|
@ -930,7 +951,7 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
|
|||
FAIL_IF(push_inst(compiler, (ORN ^ inv_bits) | RD(dst) | RN(TMP_ZERO) | RM(reg)));
|
||||
goto set_flags;
|
||||
}
|
||||
/* fallthrough */
|
||||
SLJIT_FALLTHROUGH
|
||||
case SLJIT_OR:
|
||||
inst_bits = logical_imm(imm, LOGICAL_IMM_CHECK | ((flags & INT_OP) ? 16 : 32));
|
||||
if (!inst_bits)
|
||||
|
|
@ -1039,7 +1060,7 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
|
|||
SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG1);
|
||||
if (dst == arg2)
|
||||
return SLJIT_SUCCESS;
|
||||
/* fallthrough */
|
||||
SLJIT_FALLTHROUGH
|
||||
case SLJIT_MOV_U32:
|
||||
SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG1);
|
||||
return push_inst(compiler, (MOV ^ W_OP) | RD(dst) | RM(arg2));
|
||||
|
|
@ -1124,7 +1145,7 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
|
|||
case SLJIT_ROTL:
|
||||
FAIL_IF(push_inst(compiler, (SUB ^ inv_bits) | RD(TMP_REG2) | RN(TMP_ZERO) | RM(arg2)));
|
||||
arg2 = TMP_REG2;
|
||||
/* fallthrough */
|
||||
SLJIT_FALLTHROUGH
|
||||
case SLJIT_ROTR:
|
||||
return push_inst(compiler, (RORV ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2));
|
||||
case SLJIT_MULADD:
|
||||
|
|
@ -1855,6 +1876,54 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *
|
|||
return push_inst(compiler, (ORR ^ inv_bits) | RD(dst_reg) | RN(dst_reg) | RM(TMP_REG1));
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2_shift(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_sw shift_arg)
|
||||
{
|
||||
sljit_s32 dst_r, tmp_r;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_op2_shift(compiler, op, dst, dstw, src1, src1w, src2, src2w, shift_arg));
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
ADJUST_LOCAL_OFFSET(src1, src1w);
|
||||
ADJUST_LOCAL_OFFSET(src2, src2w);
|
||||
|
||||
shift_arg &= 0x3f;
|
||||
|
||||
if (src2 == SLJIT_IMM) {
|
||||
src2w = src2w << shift_arg;
|
||||
shift_arg = 0;
|
||||
}
|
||||
|
||||
if (shift_arg == 0) {
|
||||
SLJIT_SKIP_CHECKS(compiler);
|
||||
return sljit_emit_op2(compiler, GET_OPCODE(op), dst, dstw, src1, src1w, src2, src2w);
|
||||
}
|
||||
|
||||
if (src1 == SLJIT_IMM) {
|
||||
FAIL_IF(load_immediate(compiler, TMP_REG2, src1w));
|
||||
src1 = TMP_REG2;
|
||||
} else if (src1 & SLJIT_MEM) {
|
||||
FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG2, src1, src1w, TMP_REG2));
|
||||
src1 = TMP_REG2;
|
||||
}
|
||||
|
||||
if (src2 & SLJIT_MEM) {
|
||||
tmp_r = (src1 == TMP_REG2) ? TMP_REG1 : TMP_REG2;
|
||||
FAIL_IF(emit_op_mem(compiler, WORD_SIZE, tmp_r, src2, src2w, tmp_r));
|
||||
src2 = tmp_r;
|
||||
}
|
||||
|
||||
dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
|
||||
FAIL_IF(push_inst(compiler, ADD | RD(dst_r) | RN(src1) | RM(src2) | ((sljit_ins)shift_arg << 10)));
|
||||
|
||||
if (dst & SLJIT_MEM)
|
||||
return emit_op_mem(compiler, WORD_SIZE | STORE, dst_r, dst, dstw, TMP_REG2);
|
||||
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)
|
||||
{
|
||||
|
|
@ -1864,9 +1933,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *comp
|
|||
|
||||
switch (op) {
|
||||
case SLJIT_FAST_RETURN:
|
||||
if (FAST_IS_REG(src))
|
||||
FAIL_IF(push_inst(compiler, MOV | RD(TMP_LR) | RM(src)));
|
||||
else
|
||||
if (FAST_IS_REG(src)) {
|
||||
if (src != TMP_LR)
|
||||
FAIL_IF(push_inst(compiler, MOV | RD(TMP_LR) | 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));
|
||||
|
|
@ -1906,8 +1976,11 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_dst(struct sljit_compiler *comp
|
|||
|
||||
switch (op) {
|
||||
case SLJIT_FAST_ENTER:
|
||||
if (FAST_IS_REG(dst))
|
||||
if (FAST_IS_REG(dst)) {
|
||||
if (dst == TMP_LR)
|
||||
return SLJIT_SUCCESS;
|
||||
return push_inst(compiler, MOV | RD(dst) | RM(TMP_LR));
|
||||
}
|
||||
break;
|
||||
case SLJIT_GET_RETURN_ADDRESS:
|
||||
dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
|
||||
|
|
@ -2291,7 +2364,7 @@ static sljit_ins get_cc(struct sljit_compiler *compiler, sljit_s32 type)
|
|||
case SLJIT_CARRY:
|
||||
if (compiler->status_flags_state & SLJIT_CURRENT_FLAGS_ADD)
|
||||
return 0x3;
|
||||
/* fallthrough */
|
||||
SLJIT_FALLTHROUGH
|
||||
|
||||
case SLJIT_LESS:
|
||||
return 0x2;
|
||||
|
|
@ -2299,7 +2372,7 @@ static sljit_ins get_cc(struct sljit_compiler *compiler, sljit_s32 type)
|
|||
case SLJIT_NOT_CARRY:
|
||||
if (compiler->status_flags_state & SLJIT_CURRENT_FLAGS_ADD)
|
||||
return 0x2;
|
||||
/* fallthrough */
|
||||
SLJIT_FALLTHROUGH
|
||||
|
||||
case SLJIT_GREATER_EQUAL:
|
||||
return 0x3;
|
||||
|
|
@ -2334,7 +2407,7 @@ static sljit_ins get_cc(struct sljit_compiler *compiler, sljit_s32 type)
|
|||
case SLJIT_OVERFLOW:
|
||||
if (!(compiler->status_flags_state & (SLJIT_CURRENT_FLAGS_ADD | SLJIT_CURRENT_FLAGS_SUB)))
|
||||
return 0x0;
|
||||
/* fallthrough */
|
||||
SLJIT_FALLTHROUGH
|
||||
|
||||
case SLJIT_UNORDERED:
|
||||
return 0x7;
|
||||
|
|
@ -2342,7 +2415,7 @@ static sljit_ins get_cc(struct sljit_compiler *compiler, sljit_s32 type)
|
|||
case SLJIT_NOT_OVERFLOW:
|
||||
if (!(compiler->status_flags_state & (SLJIT_CURRENT_FLAGS_ADD | SLJIT_CURRENT_FLAGS_SUB)))
|
||||
return 0x1;
|
||||
/* fallthrough */
|
||||
SLJIT_FALLTHROUGH
|
||||
|
||||
case SLJIT_ORDERED:
|
||||
return 0x6;
|
||||
|
|
@ -2376,6 +2449,60 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compi
|
|||
return label;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_aligned_label(struct sljit_compiler *compiler,
|
||||
sljit_s32 alignment, struct sljit_read_only_buffer *buffers)
|
||||
{
|
||||
sljit_uw mask, i;
|
||||
struct sljit_label *label;
|
||||
struct sljit_label *next_label;
|
||||
struct sljit_extended_label *ext_label;
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_PTR(check_sljit_emit_aligned_label(compiler, alignment, buffers));
|
||||
|
||||
sljit_reset_read_only_buffers(buffers);
|
||||
|
||||
if (alignment <= SLJIT_LABEL_ALIGN_4) {
|
||||
SLJIT_SKIP_CHECKS(compiler);
|
||||
label = sljit_emit_label(compiler);
|
||||
PTR_FAIL_IF(!label);
|
||||
} else {
|
||||
/* The used space is filled with NOPs. */
|
||||
mask = ((sljit_uw)1 << alignment) - sizeof(sljit_ins);
|
||||
|
||||
for (i = (mask >> 2); i != 0; i--)
|
||||
PTR_FAIL_IF(push_inst(compiler, NOP));
|
||||
|
||||
ext_label = (struct sljit_extended_label*)ensure_abuf(compiler, sizeof(struct sljit_extended_label));
|
||||
PTR_FAIL_IF(!ext_label);
|
||||
set_extended_label(ext_label, compiler, SLJIT_LABEL_ALIGNED, mask);
|
||||
label = &ext_label->label;
|
||||
}
|
||||
|
||||
if (buffers == NULL)
|
||||
return label;
|
||||
|
||||
next_label = label;
|
||||
|
||||
while (1) {
|
||||
buffers->u.label = next_label;
|
||||
|
||||
for (i = (buffers->size + 3) >> 2; i > 0; i--)
|
||||
PTR_FAIL_IF(push_inst(compiler, NOP));
|
||||
|
||||
buffers = buffers->next;
|
||||
|
||||
if (buffers == NULL)
|
||||
break;
|
||||
|
||||
SLJIT_SKIP_CHECKS(compiler);
|
||||
next_label = sljit_emit_label(compiler);
|
||||
PTR_FAIL_IF(!next_label);
|
||||
}
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type)
|
||||
{
|
||||
struct sljit_jump *jump;
|
||||
|
|
@ -2565,6 +2692,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *comp
|
|||
sljit_s32 src2_reg)
|
||||
{
|
||||
sljit_ins inv_bits = (type & SLJIT_32) ? W_OP : 0;
|
||||
sljit_ins op = CSEL;
|
||||
sljit_ins cmp = 0;
|
||||
sljit_ins cc;
|
||||
|
||||
CHECK_ERROR();
|
||||
|
|
@ -2575,15 +2704,38 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *comp
|
|||
if (src1 == SLJIT_IMM) {
|
||||
if (type & SLJIT_32)
|
||||
src1w = (sljit_s32)src1w;
|
||||
FAIL_IF(load_immediate(compiler, TMP_REG2, src1w));
|
||||
src1 = TMP_REG2;
|
||||
|
||||
if (src1w <= 1 && src1w >= -1) {
|
||||
src1 = TMP_ZERO;
|
||||
cmp = (SUBI ^ inv_bits) | (1 << 29) | RD(TMP_ZERO);
|
||||
|
||||
if (src1w == 1) {
|
||||
op = CSINC;
|
||||
cmp = (SUBI ^ inv_bits) | (1 << 29) | RD(TMP_ZERO) | (1 << 10);
|
||||
} else if (src1w == -1) {
|
||||
op = CSINV;
|
||||
cmp = (ADDI ^ inv_bits) | (1 << 29) | RD(TMP_ZERO) | (1 << 10);
|
||||
}
|
||||
|
||||
src1w = 0;
|
||||
} else {
|
||||
FAIL_IF(load_immediate(compiler, TMP_REG2, src1w));
|
||||
src1 = TMP_REG2;
|
||||
}
|
||||
} else if (src1 & SLJIT_MEM) {
|
||||
FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG2, src1, src1w, TMP_REG2));
|
||||
src1 = TMP_REG2;
|
||||
}
|
||||
|
||||
cc = get_cc(compiler, type & ~SLJIT_32);
|
||||
return push_inst(compiler, (CSEL ^ inv_bits) | (cc << 12) | RD(dst_reg) | RN(src2_reg) | RM(src1));
|
||||
if (type & SLJIT_COMPARE_SELECT) {
|
||||
type ^= 0x1;
|
||||
if (cmp == 0)
|
||||
cmp = (SUB ^ inv_bits) | (1 << 29) | RD(TMP_ZERO) | RM(src1);
|
||||
FAIL_IF(push_inst(compiler, cmp | RN(src2_reg)));
|
||||
}
|
||||
|
||||
cc = get_cc(compiler, type & ~(SLJIT_32 | SLJIT_COMPARE_SELECT));
|
||||
return push_inst(compiler, (op ^ inv_bits) | (cc << 12) | RD(dst_reg) | RN(src2_reg) | RM(src1));
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fselect(struct sljit_compiler *compiler, sljit_s32 type,
|
||||
|
|
@ -2701,19 +2853,19 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem_update(struct sljit_compiler *
|
|||
break;
|
||||
case SLJIT_MOV_S8:
|
||||
sign = 1;
|
||||
/* fallthrough */
|
||||
SLJIT_FALLTHROUGH
|
||||
case SLJIT_MOV_U8:
|
||||
inst = STURBI | (MEM_SIZE_SHIFT(BYTE_SIZE) << 30) | 0x400;
|
||||
break;
|
||||
case SLJIT_MOV_S16:
|
||||
sign = 1;
|
||||
/* fallthrough */
|
||||
SLJIT_FALLTHROUGH
|
||||
case SLJIT_MOV_U16:
|
||||
inst = STURBI | (MEM_SIZE_SHIFT(HALF_SIZE) << 30) | 0x400;
|
||||
break;
|
||||
case SLJIT_MOV_S32:
|
||||
sign = 1;
|
||||
/* fallthrough */
|
||||
SLJIT_FALLTHROUGH
|
||||
case SLJIT_MOV_U32:
|
||||
case SLJIT_MOV32:
|
||||
inst = STURBI | (MEM_SIZE_SHIFT(INT_SIZE) << 30) | 0x400;
|
||||
|
|
@ -3378,6 +3530,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_atomic_store(struct sljit_compiler
|
|||
{
|
||||
sljit_ins ins;
|
||||
sljit_ins cmp = 0;
|
||||
SLJIT_UNUSED_ARG(temp_reg); /* !__ARM_FEATURE_ATOMICS */
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_atomic_store(compiler, op, src_reg, mem_reg, temp_reg));
|
||||
|
|
@ -3467,6 +3620,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_local_base(struct sljit_compiler *c
|
|||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_get_local_base(compiler, dst, dstw, offset));
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
ADJUST_LOCAL_OFFSET(SLJIT_MEM1(SLJIT_SP), offset);
|
||||
|
||||
dst_reg = FAST_IS_REG(dst) ? dst : TMP_REG1;
|
||||
|
|
@ -3500,13 +3654,21 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_local_base(struct sljit_compiler *c
|
|||
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)
|
||||
#define SLJIT_EMIT_CONST_U8(c) \
|
||||
(((c) & 0x100) != 0 ? (MOVN | (sljit_ins)((~(c) & 0xff) << 5)) : (MOVZ | (sljit_ins)(((c) & 0xff) << 5)))
|
||||
#define SLJIT_EMIT_CONST_S32(c) \
|
||||
(((c) < 0) ? (MOVN | (sljit_ins)((~(c) & 0xffff) << 5)) : (MOVZ | (sljit_ins)(((c) & 0xffff) << 5)))
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 op,
|
||||
sljit_s32 dst, sljit_sw dstw,
|
||||
sljit_sw init_value)
|
||||
{
|
||||
struct sljit_const *const_;
|
||||
sljit_s32 dst_r;
|
||||
sljit_s32 mem_flags = WORD_SIZE | STORE;
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_PTR(check_sljit_emit_const(compiler, dst, dstw, init_value));
|
||||
CHECK_PTR(check_sljit_emit_const(compiler, op, dst, dstw, init_value));
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
|
||||
const_ = (struct sljit_const*)ensure_abuf(compiler, sizeof(struct sljit_const));
|
||||
|
|
@ -3514,24 +3676,58 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi
|
|||
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));
|
||||
|
||||
switch (GET_OPCODE(op)) {
|
||||
case SLJIT_MOV_U8:
|
||||
PTR_FAIL_IF(push_inst(compiler, SLJIT_EMIT_CONST_U8(init_value) | RD(dst_r)));
|
||||
mem_flags = BYTE_SIZE | STORE;
|
||||
break;
|
||||
|
||||
case SLJIT_MOV32:
|
||||
case SLJIT_MOV_S32:
|
||||
if (GET_OPCODE(op) == SLJIT_MOV32) {
|
||||
init_value = (sljit_u32)init_value;
|
||||
mem_flags = INT_SIZE | STORE;
|
||||
} else
|
||||
init_value = (sljit_s32)init_value;
|
||||
|
||||
PTR_FAIL_IF(push_inst(compiler, SLJIT_EMIT_CONST_S32(init_value) | RD(dst_r)));
|
||||
PTR_FAIL_IF(push_inst(compiler, MOVK | (1 << 21) | (sljit_ins)((init_value >> 11) & 0x1fffe0) | RD(dst_r)));
|
||||
break;
|
||||
|
||||
default:
|
||||
PTR_FAIL_IF(emit_imm64_const(compiler, dst_r, (sljit_uw)init_value));
|
||||
break;
|
||||
}
|
||||
|
||||
if (dst & SLJIT_MEM)
|
||||
PTR_FAIL_IF(emit_op_mem(compiler, WORD_SIZE | STORE, dst_r, dst, dstw, TMP_REG2));
|
||||
PTR_FAIL_IF(emit_op_mem(compiler, mem_flags, dst_r, dst, dstw, TMP_REG2));
|
||||
return const_;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_mov_addr(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_op_addr(struct sljit_compiler *compiler, sljit_s32 op,
|
||||
sljit_s32 dst, sljit_sw dstw)
|
||||
{
|
||||
struct sljit_jump *jump;
|
||||
sljit_s32 dst_r;
|
||||
sljit_s32 dst_r, target_r;
|
||||
SLJIT_UNUSED_ARG(op);
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_PTR(check_sljit_emit_mov_addr(compiler, dst, dstw));
|
||||
CHECK_PTR(check_sljit_emit_op_addr(compiler, op, dst, dstw));
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
|
||||
dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
|
||||
PTR_FAIL_IF(push_inst(compiler, RD(dst_r)));
|
||||
|
||||
if (op != SLJIT_ADD_ABS_ADDR)
|
||||
target_r = dst_r;
|
||||
else {
|
||||
target_r = TMP_REG2;
|
||||
|
||||
if (dst & SLJIT_MEM)
|
||||
PTR_FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG1, dst, dstw, TMP_REG2));
|
||||
}
|
||||
|
||||
PTR_FAIL_IF(push_inst(compiler, RD(target_r)));
|
||||
|
||||
jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
|
||||
PTR_FAIL_IF(!jump);
|
||||
|
|
@ -3539,6 +3735,9 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_mov_addr(struct sljit_com
|
|||
|
||||
compiler->size += 3;
|
||||
|
||||
if (op == SLJIT_ADD_ABS_ADDR)
|
||||
PTR_FAIL_IF(push_inst(compiler, ADD | RD(dst_r) | RN(dst_r) | RM(TMP_REG2)));
|
||||
|
||||
if (dst & SLJIT_MEM)
|
||||
PTR_FAIL_IF(emit_op_mem(compiler, WORD_SIZE | STORE, dst_r, dst, dstw, TMP_REG2));
|
||||
|
||||
|
|
@ -3565,7 +3764,42 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_ta
|
|||
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_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_s32 op, sljit_sw new_constant, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_set_jump_addr(addr, (sljit_uw)new_constant, executable_offset);
|
||||
sljit_ins* inst;
|
||||
|
||||
switch (GET_OPCODE(op)) {
|
||||
case SLJIT_MOV_U8:
|
||||
inst = (sljit_ins*)addr;
|
||||
SLJIT_ASSERT((inst[0] & 0xffe00000) == MOVZ || (inst[0] & 0xffe00000) == MOVN);
|
||||
|
||||
SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 0);
|
||||
inst[0] = SLJIT_EMIT_CONST_U8(new_constant) | (inst[0] & 0x1f);
|
||||
SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 1);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 1);
|
||||
return;
|
||||
|
||||
case SLJIT_MOV32:
|
||||
case SLJIT_MOV_S32:
|
||||
if (GET_OPCODE(op) == SLJIT_MOV32)
|
||||
new_constant = (sljit_u32)new_constant;
|
||||
else
|
||||
new_constant = (sljit_s32)new_constant;
|
||||
|
||||
inst = (sljit_ins*)addr;
|
||||
SLJIT_ASSERT(((inst[0] & 0xffe00000) == MOVZ || (inst[0] & 0xffe00000) == MOVN) && (inst[1] & 0xffe00000) == (MOVK | (1 << 21)));
|
||||
|
||||
SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 0);
|
||||
inst[0] = SLJIT_EMIT_CONST_S32(new_constant) | (inst[0] & 0x1f);
|
||||
inst[1] = MOVK | (1 << 21) | (sljit_ins)((new_constant >> 11) & 0x1fffe0) | (inst[1] & 0x1f);
|
||||
SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 1);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 2);
|
||||
return;
|
||||
|
||||
default:
|
||||
sljit_set_jump_addr(addr, (sljit_uw)new_constant, executable_offset);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ static const sljit_u8 freg_ebit_map[((SLJIT_NUMBER_OF_FLOAT_REGISTERS + 2) << 1)
|
|||
(COPY_BITS(imm, 11, 26, 1) | COPY_BITS(imm, 8, 12, 3) | ((sljit_ins)imm & 0xff))
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Instrucion forms */
|
||||
/* Instruction forms */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/* dot '.' changed to _
|
||||
|
|
@ -160,6 +160,7 @@ static const sljit_u8 freg_ebit_map[((SLJIT_NUMBER_OF_FLOAT_REGISTERS + 2) << 1)
|
|||
#define LSR_WI 0xea4f0010
|
||||
#define MLA 0xfb000000
|
||||
#define MOV 0x4600
|
||||
#define MOVI 0x2000
|
||||
#define MOVS 0x0000
|
||||
#define MOVSI 0x2000
|
||||
#define MOVT 0xf2c00000
|
||||
|
|
@ -444,6 +445,9 @@ static SLJIT_INLINE void generate_jump_or_mov_addr(struct sljit_jump *jump, slji
|
|||
|
||||
diff = (sljit_sw)((jump->flags & JUMP_ADDR) ? jump->u.target : jump->u.label->u.addr);
|
||||
|
||||
if ((jump->flags & (JUMP_MOV_ADDR | IS_ABS)) == (JUMP_MOV_ADDR | IS_ABS))
|
||||
diff &= ~(sljit_sw)1;
|
||||
|
||||
if (SLJIT_UNLIKELY(type == 0)) {
|
||||
ins = (jump->flags & JUMP_MOV_ADDR) ? *jump_inst : RDN3(TMP_REG1);
|
||||
set_imm32_const((sljit_u16*)jump->addr, ins, (sljit_uw)diff);
|
||||
|
|
@ -506,6 +510,12 @@ static SLJIT_INLINE void generate_jump_or_mov_addr(struct sljit_jump *jump, slji
|
|||
jump_inst[1] |= 0xd000;
|
||||
}
|
||||
|
||||
static SLJIT_INLINE sljit_u16 *process_extended_label(sljit_u16 *code_ptr, struct sljit_extended_label *ext_label)
|
||||
{
|
||||
SLJIT_ASSERT(ext_label->label.u.index == SLJIT_LABEL_ALIGNED);
|
||||
return (sljit_u16*)((sljit_uw)code_ptr & ~(ext_label->data));
|
||||
}
|
||||
|
||||
static void reduce_code_size(struct sljit_compiler *compiler)
|
||||
{
|
||||
struct sljit_label *label;
|
||||
|
|
@ -615,7 +625,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
|||
struct sljit_const *const_;
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_PTR(check_sljit_generate_code(compiler));
|
||||
CHECK_PTR(check_sljit_generate_code(compiler, options));
|
||||
|
||||
reduce_code_size(compiler);
|
||||
|
||||
|
|
@ -645,6 +655,11 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
|||
|
||||
/* These structures are ordered by their address. */
|
||||
if (next_min_addr == next_label_size) {
|
||||
if (label->u.index >= SLJIT_LABEL_ALIGNED) {
|
||||
code_ptr = process_extended_label(code_ptr, (struct sljit_extended_label*)label);
|
||||
*code_ptr = buf_ptr[-1];
|
||||
}
|
||||
|
||||
label->u.addr = ((sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset)) | 0x1;
|
||||
label->size = (sljit_uw)(code_ptr - code);
|
||||
label = label->next;
|
||||
|
|
@ -682,6 +697,9 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
|||
} while (buf);
|
||||
|
||||
if (label && label->size == half_count) {
|
||||
if (label->u.index >= SLJIT_LABEL_ALIGNED)
|
||||
code_ptr = process_extended_label(code_ptr, (struct sljit_extended_label*)label);
|
||||
|
||||
label->u.addr = ((sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset)) | 0x1;
|
||||
label->size = (sljit_uw)(code_ptr - code);
|
||||
label = label->next;
|
||||
|
|
@ -1025,7 +1043,7 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
|
|||
return push_inst32(compiler, ASR_WI | (flags & SET_FLAGS) | RD4(dst) | RM4(reg) | IMM5(imm));
|
||||
case SLJIT_ROTL:
|
||||
imm = (imm ^ 0x1f) + 1;
|
||||
/* fallthrough */
|
||||
SLJIT_FALLTHROUGH
|
||||
default: /* SLJIT_ROTR */
|
||||
return push_inst32(compiler, ROR_WI | RD4(dst) | RM4(reg) | IMM5(imm));
|
||||
}
|
||||
|
|
@ -1161,7 +1179,7 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
|
|||
reg = (arg2 == TMP_REG1) ? TMP_REG1 : TMP_REG2;
|
||||
FAIL_IF(push_inst32(compiler, ANDI | RD4(reg) | RN4(arg2) | 0x1f));
|
||||
arg2 = (sljit_uw)reg;
|
||||
/* fallthrough */
|
||||
SLJIT_FALLTHROUGH
|
||||
case SLJIT_SHL:
|
||||
if (dst == (sljit_s32)arg1 && IS_2_LO_REGS(dst, arg2))
|
||||
return push_inst16(compiler, LSLS | RD3(dst) | RN3(arg2));
|
||||
|
|
@ -1170,7 +1188,7 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
|
|||
reg = (arg2 == TMP_REG1) ? TMP_REG1 : TMP_REG2;
|
||||
FAIL_IF(push_inst32(compiler, ANDI | RD4(reg) | RN4(arg2) | 0x1f));
|
||||
arg2 = (sljit_uw)reg;
|
||||
/* fallthrough */
|
||||
SLJIT_FALLTHROUGH
|
||||
case SLJIT_LSHR:
|
||||
if (dst == (sljit_s32)arg1 && IS_2_LO_REGS(dst, arg2))
|
||||
return push_inst16(compiler, LSRS | RD3(dst) | RN3(arg2));
|
||||
|
|
@ -1179,7 +1197,7 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
|
|||
reg = (arg2 == TMP_REG1) ? TMP_REG1 : TMP_REG2;
|
||||
FAIL_IF(push_inst32(compiler, ANDI | RD4(reg) | RN4(arg2) | 0x1f));
|
||||
arg2 = (sljit_uw)reg;
|
||||
/* fallthrough */
|
||||
SLJIT_FALLTHROUGH
|
||||
case SLJIT_ASHR:
|
||||
if (dst == (sljit_s32)arg1 && IS_2_LO_REGS(dst, arg2))
|
||||
return push_inst16(compiler, ASRS | RD3(dst) | RN3(arg2));
|
||||
|
|
@ -1188,7 +1206,7 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
|
|||
reg = (arg2 == TMP_REG1) ? TMP_REG1 : TMP_REG2;
|
||||
FAIL_IF(push_inst32(compiler, RSB_WI | RD4(reg) | RN4(arg2) | 0));
|
||||
arg2 = (sljit_uw)reg;
|
||||
/* fallthrough */
|
||||
SLJIT_FALLTHROUGH
|
||||
case SLJIT_ROTR:
|
||||
if (dst == (sljit_s32)arg1 && IS_2_LO_REGS(dst, arg2))
|
||||
return push_inst16(compiler, RORS | RD3(dst) | RN3(arg2));
|
||||
|
|
@ -2182,6 +2200,54 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *
|
|||
return push_inst32(compiler, ORR_W | RD4(dst_reg) | RN4(dst_reg) | RM4(TMP_REG1));
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2_shift(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_sw shift_arg)
|
||||
{
|
||||
sljit_s32 dst_r, tmp_r;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_op2_shift(compiler, op, dst, dstw, src1, src1w, src2, src2w, shift_arg));
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
ADJUST_LOCAL_OFFSET(src1, src1w);
|
||||
ADJUST_LOCAL_OFFSET(src2, src2w);
|
||||
|
||||
shift_arg &= 0x1f;
|
||||
|
||||
if (src2 == SLJIT_IMM) {
|
||||
src2w = src2w << shift_arg;
|
||||
shift_arg = 0;
|
||||
}
|
||||
|
||||
if (shift_arg == 0) {
|
||||
SLJIT_SKIP_CHECKS(compiler);
|
||||
return sljit_emit_op2(compiler, GET_OPCODE(op), dst, dstw, src1, src1w, src2, src2w);
|
||||
}
|
||||
|
||||
if (src1 == SLJIT_IMM) {
|
||||
FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)src1w));
|
||||
src1 = TMP_REG1;
|
||||
} else if (src1 & SLJIT_MEM) {
|
||||
FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG1, src1, src1w, TMP_REG1));
|
||||
src1 = TMP_REG1;
|
||||
}
|
||||
|
||||
if (src2 & SLJIT_MEM) {
|
||||
tmp_r = (src1 == TMP_REG1) ? TMP_REG2 : TMP_REG1;
|
||||
FAIL_IF(emit_op_mem(compiler, WORD_SIZE, tmp_r, src2, src2w, tmp_r));
|
||||
src2 = tmp_r;
|
||||
}
|
||||
|
||||
dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
|
||||
FAIL_IF(push_inst32(compiler, ADD_W | RD4(dst_r) | RN4(src1) | RM4(src2) | ((sljit_ins)(shift_arg & 0x3) << 6) | ((sljit_ins)(shift_arg & 0x1c) << 10)));
|
||||
|
||||
if (dst & SLJIT_MEM)
|
||||
return emit_op_mem(compiler, WORD_SIZE | STORE, dst_r, dst, dstw, TMP_REG1);
|
||||
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)
|
||||
{
|
||||
|
|
@ -2193,9 +2259,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *comp
|
|||
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
|
||||
if (FAST_IS_REG(src)) {
|
||||
if (src != TMP_REG2)
|
||||
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));
|
||||
|
|
@ -2224,8 +2291,11 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_dst(struct sljit_compiler *comp
|
|||
case SLJIT_FAST_ENTER:
|
||||
SLJIT_ASSERT(reg_map[TMP_REG2] == 14);
|
||||
|
||||
if (FAST_IS_REG(dst))
|
||||
if (FAST_IS_REG(dst)) {
|
||||
if (dst == TMP_REG2)
|
||||
return SLJIT_SUCCESS;
|
||||
return push_inst16(compiler, MOV | SET_REGS44(dst, TMP_REG2));
|
||||
}
|
||||
break;
|
||||
case SLJIT_GET_RETURN_ADDRESS:
|
||||
size = GET_SAVED_REGISTERS_SIZE(compiler->scratches, compiler->saveds - SLJIT_KEPT_SAVEDS_COUNT(compiler->options), 0);
|
||||
|
|
@ -2632,7 +2702,7 @@ static sljit_uw get_cc(struct sljit_compiler *compiler, sljit_s32 type)
|
|||
case SLJIT_CARRY:
|
||||
if (compiler->status_flags_state & SLJIT_CURRENT_FLAGS_ADD)
|
||||
return 0x2;
|
||||
/* fallthrough */
|
||||
SLJIT_FALLTHROUGH
|
||||
|
||||
case SLJIT_LESS:
|
||||
return 0x3;
|
||||
|
|
@ -2640,7 +2710,7 @@ static sljit_uw get_cc(struct sljit_compiler *compiler, sljit_s32 type)
|
|||
case SLJIT_NOT_CARRY:
|
||||
if (compiler->status_flags_state & SLJIT_CURRENT_FLAGS_ADD)
|
||||
return 0x3;
|
||||
/* fallthrough */
|
||||
SLJIT_FALLTHROUGH
|
||||
|
||||
case SLJIT_GREATER_EQUAL:
|
||||
return 0x2;
|
||||
|
|
@ -2675,7 +2745,7 @@ static sljit_uw get_cc(struct sljit_compiler *compiler, sljit_s32 type)
|
|||
case SLJIT_OVERFLOW:
|
||||
if (!(compiler->status_flags_state & (SLJIT_CURRENT_FLAGS_ADD | SLJIT_CURRENT_FLAGS_SUB)))
|
||||
return 0x1;
|
||||
/* fallthrough */
|
||||
SLJIT_FALLTHROUGH
|
||||
|
||||
case SLJIT_UNORDERED:
|
||||
return 0x6;
|
||||
|
|
@ -2683,7 +2753,7 @@ static sljit_uw get_cc(struct sljit_compiler *compiler, sljit_s32 type)
|
|||
case SLJIT_NOT_OVERFLOW:
|
||||
if (!(compiler->status_flags_state & (SLJIT_CURRENT_FLAGS_ADD | SLJIT_CURRENT_FLAGS_SUB)))
|
||||
return 0x0;
|
||||
/* fallthrough */
|
||||
SLJIT_FALLTHROUGH
|
||||
|
||||
case SLJIT_ORDERED:
|
||||
return 0x7;
|
||||
|
|
@ -2717,6 +2787,60 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compi
|
|||
return label;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_aligned_label(struct sljit_compiler *compiler,
|
||||
sljit_s32 alignment, struct sljit_read_only_buffer *buffers)
|
||||
{
|
||||
sljit_uw mask, i;
|
||||
struct sljit_label *label;
|
||||
struct sljit_label *next_label;
|
||||
struct sljit_extended_label *ext_label;
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_PTR(check_sljit_emit_aligned_label(compiler, alignment, buffers));
|
||||
|
||||
sljit_reset_read_only_buffers(buffers);
|
||||
|
||||
if (alignment <= SLJIT_LABEL_ALIGN_2) {
|
||||
SLJIT_SKIP_CHECKS(compiler);
|
||||
label = sljit_emit_label(compiler);
|
||||
PTR_FAIL_IF(!label);
|
||||
} else {
|
||||
/* The used space is filled with NOPs. */
|
||||
mask = ((sljit_uw)1 << alignment) - sizeof(sljit_u16);
|
||||
|
||||
for (i = (mask >> 1); i != 0; i--)
|
||||
PTR_FAIL_IF(push_inst16(compiler, NOP));
|
||||
|
||||
ext_label = (struct sljit_extended_label*)ensure_abuf(compiler, sizeof(struct sljit_extended_label));
|
||||
PTR_FAIL_IF(!ext_label);
|
||||
set_extended_label(ext_label, compiler, SLJIT_LABEL_ALIGNED, mask);
|
||||
label = &ext_label->label;
|
||||
}
|
||||
|
||||
if (buffers == NULL)
|
||||
return label;
|
||||
|
||||
next_label = label;
|
||||
|
||||
while (1) {
|
||||
buffers->u.label = next_label;
|
||||
|
||||
for (i = (buffers->size + 1) >> 1; i > 0; i--)
|
||||
PTR_FAIL_IF(push_inst16(compiler, NOP));
|
||||
|
||||
buffers = buffers->next;
|
||||
|
||||
if (buffers == NULL)
|
||||
break;
|
||||
|
||||
SLJIT_SKIP_CHECKS(compiler);
|
||||
next_label = sljit_emit_label(compiler);
|
||||
PTR_FAIL_IF(!next_label);
|
||||
}
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type)
|
||||
{
|
||||
struct sljit_jump *jump;
|
||||
|
|
@ -3166,7 +3290,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *comp
|
|||
sljit_s32 src1, sljit_sw src1w,
|
||||
sljit_s32 src2_reg)
|
||||
{
|
||||
sljit_uw cc, tmp;
|
||||
sljit_uw cc, tmp, tmp2;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_select(compiler, type, dst_reg, src1, src1w, src2_reg));
|
||||
|
|
@ -3177,7 +3301,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *comp
|
|||
src1 = src2_reg;
|
||||
src1w = 0;
|
||||
src2_reg = dst_reg;
|
||||
type ^= 0x1;
|
||||
if (!(type & SLJIT_COMPARE_SELECT))
|
||||
type ^= 0x1;
|
||||
}
|
||||
|
||||
if (src1 & SLJIT_MEM) {
|
||||
|
|
@ -3186,7 +3311,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *comp
|
|||
if (src2_reg != dst_reg) {
|
||||
src1 = src2_reg;
|
||||
src1w = 0;
|
||||
type ^= 0x1;
|
||||
if (!(type & SLJIT_COMPARE_SELECT))
|
||||
type ^= 0x1;
|
||||
} else {
|
||||
src1 = TMP_REG1;
|
||||
src1w = 0;
|
||||
|
|
@ -3194,9 +3320,55 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *comp
|
|||
} else if (dst_reg != src2_reg)
|
||||
FAIL_IF(push_inst16(compiler, MOV | SET_REGS44(dst_reg, src2_reg)));
|
||||
|
||||
cc = get_cc(compiler, type & ~SLJIT_32);
|
||||
if ((type & SLJIT_COMPARE_SELECT))
|
||||
type ^= 0x1;
|
||||
cc = get_cc(compiler, type & ~(SLJIT_32 | SLJIT_COMPARE_SELECT));
|
||||
|
||||
if (src1 == SLJIT_IMM && (type & SLJIT_COMPARE_SELECT)) {
|
||||
tmp = (sljit_uw)src1w;
|
||||
if (tmp <= 0xff && reg_map[dst_reg] <= 7) {
|
||||
if (type & SLJIT_COMPARE_SELECT)
|
||||
FAIL_IF(push_inst16(compiler, CMPI | IMM8(tmp) | RDN3(dst_reg)));
|
||||
FAIL_IF(push_inst16(compiler, IT | (cc << 4) | 0x8));
|
||||
return push_inst16(compiler, MOVI | IMM8(tmp) | RDN3(dst_reg));
|
||||
}
|
||||
|
||||
tmp = get_imm((sljit_uw)src1w);
|
||||
if (tmp != INVALID_IMM) {
|
||||
if (type & SLJIT_COMPARE_SELECT)
|
||||
FAIL_IF(push_inst32(compiler, CMPI_W | RN4(dst_reg) | tmp));
|
||||
FAIL_IF(push_inst16(compiler, IT | (cc << 4) | 0x8));
|
||||
return push_inst32(compiler, MOV_WI | RD4(dst_reg) | tmp);
|
||||
}
|
||||
|
||||
tmp = get_imm(~(sljit_uw)src1w);
|
||||
if (tmp != INVALID_IMM && (type & SLJIT_COMPARE_SELECT)) {
|
||||
tmp2 = get_imm(NEGATE(src1w));
|
||||
if (tmp2 != INVALID_IMM)
|
||||
FAIL_IF(push_inst32(compiler, CMNI_W | RN4(dst_reg) | tmp2));
|
||||
else
|
||||
tmp = INVALID_IMM;
|
||||
}
|
||||
|
||||
if (tmp != INVALID_IMM) {
|
||||
FAIL_IF(push_inst16(compiler, IT | (cc << 4) | 0x8));
|
||||
return push_inst32(compiler, MVN_WI | RD4(dst_reg) | tmp);
|
||||
}
|
||||
|
||||
if (type & SLJIT_COMPARE_SELECT) {
|
||||
FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)src1w));
|
||||
src1 = TMP_REG1;
|
||||
}
|
||||
}
|
||||
|
||||
if (src1 != SLJIT_IMM) {
|
||||
if (type & SLJIT_COMPARE_SELECT) {
|
||||
if (IS_2_LO_REGS(dst_reg, src1))
|
||||
FAIL_IF(push_inst16(compiler, CMP | RD3(dst_reg) | RN3(src1)));
|
||||
else
|
||||
FAIL_IF(push_inst16(compiler, CMP_X | SET_REGS44(dst_reg, src1)));
|
||||
}
|
||||
|
||||
FAIL_IF(push_inst16(compiler, IT | (cc << 4) | 0x8));
|
||||
return push_inst16(compiler, MOV | SET_REGS44(dst_reg, src1));
|
||||
}
|
||||
|
|
@ -3210,18 +3382,6 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *comp
|
|||
| 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)src1w);
|
||||
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)src1w);
|
||||
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)src1w;
|
||||
|
|
@ -4357,13 +4517,16 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_atomic_store(struct sljit_compiler
|
|||
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)
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 op,
|
||||
sljit_s32 dst, sljit_sw dstw,
|
||||
sljit_sw init_value)
|
||||
{
|
||||
struct sljit_const *const_;
|
||||
sljit_s32 dst_r;
|
||||
sljit_s32 mem_flags = WORD_SIZE | STORE;
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_PTR(check_sljit_emit_const(compiler, dst, dstw, init_value));
|
||||
CHECK_PTR(check_sljit_emit_const(compiler, op, dst, dstw, init_value));
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
|
||||
const_ = (struct sljit_const*)ensure_abuf(compiler, sizeof(struct sljit_const));
|
||||
|
|
@ -4371,32 +4534,55 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi
|
|||
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 (GET_OPCODE(op) == SLJIT_MOV_U8) {
|
||||
PTR_FAIL_IF(push_inst32(compiler,
|
||||
((init_value & 0x100) != 0 ? (MVN_WI | (~init_value & 0xff)) : (MOV_WI | (init_value & 0xff))) | RD4(dst_r)));
|
||||
mem_flags = BYTE_SIZE | STORE;
|
||||
} else
|
||||
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));
|
||||
PTR_FAIL_IF(emit_op_mem(compiler, mem_flags, dst_r, dst, dstw, TMP_REG2));
|
||||
return const_;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_mov_addr(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_op_addr(struct sljit_compiler *compiler, sljit_s32 op,
|
||||
sljit_s32 dst, sljit_sw dstw)
|
||||
{
|
||||
struct sljit_jump *jump;
|
||||
sljit_s32 dst_r;
|
||||
sljit_s32 dst_r, target_r;
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_PTR(check_sljit_emit_mov_addr(compiler, dst, dstw));
|
||||
CHECK_PTR(check_sljit_emit_op_addr(compiler, op, dst, dstw));
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
|
||||
dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
|
||||
|
||||
if (op != SLJIT_ADD_ABS_ADDR)
|
||||
target_r = dst_r;
|
||||
else {
|
||||
target_r = TMP_REG1;
|
||||
|
||||
if (dst & SLJIT_MEM)
|
||||
PTR_FAIL_IF(emit_op_mem(compiler, WORD_SIZE, dst_r, dst, dstw, TMP_REG1));
|
||||
}
|
||||
|
||||
jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
|
||||
PTR_FAIL_IF(!jump);
|
||||
set_mov_addr(jump, compiler, 0);
|
||||
|
||||
dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
|
||||
PTR_FAIL_IF(push_inst16(compiler, RDN3(dst_r)));
|
||||
if (op != SLJIT_MOV_ADDR)
|
||||
jump->flags |= IS_ABS;
|
||||
|
||||
PTR_FAIL_IF(push_inst16(compiler, RDN3(target_r)));
|
||||
compiler->size += 3;
|
||||
|
||||
if (op == SLJIT_ADD_ABS_ADDR)
|
||||
PTR_FAIL_IF(push_inst16(compiler, ADD | SET_REGS44(dst_r, TMP_REG1)));
|
||||
|
||||
if (dst & SLJIT_MEM)
|
||||
PTR_FAIL_IF(emit_op_mem(compiler, WORD_SIZE | STORE, dst_r, dst, dstw, TMP_REG2));
|
||||
PTR_FAIL_IF(emit_op_mem(compiler, WORD_SIZE | STORE, dst_r, dst, dstw, TMP_REG1));
|
||||
return jump;
|
||||
}
|
||||
|
||||
|
|
@ -4412,7 +4598,28 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_ta
|
|||
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_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_s32 op, sljit_sw new_constant, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_set_jump_addr(addr, (sljit_uw)new_constant, executable_offset);
|
||||
sljit_u16 *inst;
|
||||
|
||||
if (GET_OPCODE(op) != SLJIT_MOV_U8) {
|
||||
sljit_set_jump_addr(addr, (sljit_uw)new_constant, executable_offset);
|
||||
return;
|
||||
}
|
||||
|
||||
inst = (sljit_u16*)addr;
|
||||
SLJIT_ASSERT(inst[0] == (MOV_WI >> 16) || inst[0] == (MVN_WI >> 16));
|
||||
|
||||
SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 0);
|
||||
|
||||
if ((new_constant & 0x100) != 0) {
|
||||
inst[0] = (sljit_u16)(MVN_WI >> 16);
|
||||
new_constant = ~new_constant;
|
||||
} else
|
||||
inst[0] = (sljit_u16)(MOV_WI >> 16);
|
||||
|
||||
inst[1] = (sljit_u16)((new_constant & 0xff) | (inst[1] & 0xf00));
|
||||
SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 1);
|
||||
inst = (sljit_u16 *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst + 1, inst + 2);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 3] = {
|
|||
};
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Instrucion forms */
|
||||
/* Instruction forms */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
|
|
@ -256,6 +256,7 @@ lower parts in the instruction word, denoted by the “L” and “H” suffixes
|
|||
/* Other instructions */
|
||||
#define BREAK OPC_3R(0x54)
|
||||
#define DBGCALL OPC_3R(0x55)
|
||||
#define NOP ANDI
|
||||
#define SYSCALL OPC_3R(0x56)
|
||||
|
||||
/* Basic Floating-Point Instructions */
|
||||
|
|
@ -580,6 +581,12 @@ static SLJIT_INLINE void load_addr_to_reg(struct sljit_jump *jump, sljit_sw exec
|
|||
ins[1] = ORI | RD(reg) | RJ(reg) | IMM_I12(addr);
|
||||
}
|
||||
|
||||
static SLJIT_INLINE sljit_ins *process_extended_label(sljit_ins *code_ptr, struct sljit_extended_label *ext_label)
|
||||
{
|
||||
SLJIT_ASSERT(ext_label->label.u.index == SLJIT_LABEL_ALIGNED);
|
||||
return (sljit_ins*)((sljit_uw)code_ptr & ~(ext_label->data));
|
||||
}
|
||||
|
||||
static void reduce_code_size(struct sljit_compiler *compiler)
|
||||
{
|
||||
struct sljit_label *label;
|
||||
|
|
@ -694,7 +701,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
|||
struct sljit_const *const_;
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_PTR(check_sljit_generate_code(compiler));
|
||||
CHECK_PTR(check_sljit_generate_code(compiler, options));
|
||||
|
||||
reduce_code_size(compiler);
|
||||
|
||||
|
|
@ -724,6 +731,11 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
|||
|
||||
/* These structures are ordered by their address. */
|
||||
if (next_min_addr == next_label_size) {
|
||||
if (label->u.index >= SLJIT_LABEL_ALIGNED) {
|
||||
code_ptr = process_extended_label(code_ptr, (struct sljit_extended_label*)label);
|
||||
*code_ptr = buf_ptr[-1];
|
||||
}
|
||||
|
||||
label->u.addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
|
||||
label->size = (sljit_uw)(code_ptr - code);
|
||||
label = label->next;
|
||||
|
|
@ -759,6 +771,9 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
|||
} while (buf);
|
||||
|
||||
if (label && label->size == word_count) {
|
||||
if (label->u.index >= SLJIT_LABEL_ALIGNED)
|
||||
code_ptr = process_extended_label(code_ptr, (struct sljit_extended_label*)label);
|
||||
|
||||
label->u.addr = (sljit_uw)code_ptr;
|
||||
label->size = (sljit_uw)(code_ptr - code);
|
||||
label = label->next;
|
||||
|
|
@ -893,14 +908,18 @@ static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_r
|
|||
|
||||
if (imm <= 0x7fffffffl && imm >= -0x80000000l) {
|
||||
FAIL_IF(push_inst(compiler, LU12I_W | RD(dst_r) | (sljit_ins)(((imm & 0xffffffff) >> 12) << 5)));
|
||||
return push_inst(compiler, ORI | RD(dst_r) | RJ(dst_r) | IMM_I12(imm));
|
||||
if (IMM_I12(imm) != 0)
|
||||
return push_inst(compiler, ORI | RD(dst_r) | RJ(dst_r) | IMM_I12(imm));
|
||||
return SLJIT_SUCCESS;
|
||||
} else if (imm <= 0x7ffffffffffffl && imm >= -0x8000000000000l) {
|
||||
FAIL_IF(push_inst(compiler, LU12I_W | RD(dst_r) | (sljit_ins)(((imm & 0xffffffff) >> 12) << 5)));
|
||||
FAIL_IF(push_inst(compiler, ORI | RD(dst_r) | RJ(dst_r) | IMM_I12(imm)));
|
||||
if (IMM_I12(imm) != 0)
|
||||
FAIL_IF(push_inst(compiler, ORI | RD(dst_r) | RJ(dst_r) | IMM_I12(imm)));
|
||||
return push_inst(compiler, LU32I_D | RD(dst_r) | (sljit_ins)(((imm >> 32) & 0xfffff) << 5));
|
||||
}
|
||||
FAIL_IF(push_inst(compiler, LU12I_W | RD(dst_r) | (sljit_ins)(((imm & 0xffffffff) >> 12) << 5)));
|
||||
FAIL_IF(push_inst(compiler, ORI | RD(dst_r) | RJ(dst_r) | IMM_I12(imm)));
|
||||
if (IMM_I12(imm) != 0)
|
||||
FAIL_IF(push_inst(compiler, ORI | RD(dst_r) | RJ(dst_r) | IMM_I12(imm)));
|
||||
FAIL_IF(push_inst(compiler, LU32I_D | RD(dst_r) | (sljit_ins)(((imm >> 32) & 0xfffff) << 5)));
|
||||
return push_inst(compiler, LU52I_D | RD(dst_r) | RJ(dst_r) | IMM_I12(imm >> 52));
|
||||
}
|
||||
|
|
@ -1596,7 +1615,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
|
|||
if (src2 >= 0)
|
||||
FAIL_IF(push_inst(compiler, INST(ADDI, op) | RD(EQUAL_FLAG) | RJ(src1) | IMM_I12(0)));
|
||||
else {
|
||||
FAIL_IF(push_inst(compiler, INST(ADDI, op) | RD(EQUAL_FLAG) | RJ(src1) | IMM_I12(-1)));
|
||||
FAIL_IF(push_inst(compiler, INST(ADDI, op) | RD(EQUAL_FLAG) | RJ(TMP_ZERO) | IMM_I12(-1)));
|
||||
FAIL_IF(push_inst(compiler, XOR | RD(EQUAL_FLAG) | RJ(src1) | RK(EQUAL_FLAG)));
|
||||
}
|
||||
} else if (op & SLJIT_SET_Z)
|
||||
|
|
@ -1897,7 +1916,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compile
|
|||
case SLJIT_BREAKPOINT:
|
||||
return push_inst(compiler, BREAK);
|
||||
case SLJIT_NOP:
|
||||
return push_inst(compiler, ANDI | RD(TMP_ZERO) | RJ(TMP_ZERO) | IMM_I12(0));
|
||||
return push_inst(compiler, NOP);
|
||||
case SLJIT_LMUL_UW:
|
||||
FAIL_IF(push_inst(compiler, ADDI_D | RD(TMP_REG1) | RJ(SLJIT_R1) | IMM_I12(0)));
|
||||
FAIL_IF(push_inst(compiler, MULH_DU | RD(SLJIT_R1) | RJ(SLJIT_R0) | RK(SLJIT_R1)));
|
||||
|
|
@ -2155,6 +2174,55 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *
|
|||
return push_inst(compiler, OR | RD(dst_reg) | RJ(dst_reg) | RK(TMP_REG1));
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2_shift(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_sw shift_arg)
|
||||
{
|
||||
sljit_s32 dst_r, tmp_r;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_op2_shift(compiler, op, dst, dstw, src1, src1w, src2, src2w, shift_arg));
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
ADJUST_LOCAL_OFFSET(src1, src1w);
|
||||
ADJUST_LOCAL_OFFSET(src2, src2w);
|
||||
|
||||
shift_arg &= (sljit_sw)((sizeof(sljit_sw) * 8) - 1);
|
||||
|
||||
if (src2 == SLJIT_IMM) {
|
||||
src2w = src2w << shift_arg;
|
||||
shift_arg = 0;
|
||||
}
|
||||
|
||||
if (shift_arg == 0) {
|
||||
SLJIT_SKIP_CHECKS(compiler);
|
||||
return sljit_emit_op2(compiler, GET_OPCODE(op), dst, dstw, src1, src1w, src2, src2w);
|
||||
}
|
||||
|
||||
if (src2 & SLJIT_MEM) {
|
||||
FAIL_IF(emit_op_mem2(compiler, WORD_DATA | LOAD_DATA, TMP_REG2, src2, src2w, src1, src1w));
|
||||
src2 = TMP_REG2;
|
||||
}
|
||||
|
||||
if (src1 == SLJIT_IMM) {
|
||||
FAIL_IF(load_immediate(compiler, TMP_REG1, src1w));
|
||||
src1 = TMP_REG1;
|
||||
} else if (src1 & SLJIT_MEM) {
|
||||
FAIL_IF(emit_op_mem2(compiler, WORD_DATA | LOAD_DATA, TMP_REG1, src1, src1w, dst, dstw));
|
||||
src1 = TMP_REG1;
|
||||
}
|
||||
|
||||
dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
|
||||
tmp_r = (src1 == TMP_REG1) ? TMP_REG2 : TMP_REG1;
|
||||
FAIL_IF(push_inst(compiler, SLLI_D | RD(tmp_r) | RJ(src2) | IMM_I12(shift_arg)));
|
||||
FAIL_IF(push_inst(compiler, ADD_D | RD(dst_r) | RJ(src1) | RK(tmp_r)));
|
||||
|
||||
if (dst & SLJIT_MEM)
|
||||
return emit_op_mem2(compiler, WORD_DATA, dst_r, dst, dstw, 0, 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)
|
||||
{
|
||||
|
|
@ -2166,9 +2234,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *comp
|
|||
|
||||
switch (op) {
|
||||
case SLJIT_FAST_RETURN:
|
||||
if (FAST_IS_REG(src))
|
||||
FAIL_IF(push_inst(compiler, ADDI_D | RD(RETURN_ADDR_REG) | RJ(src) | IMM_I12(0)));
|
||||
else
|
||||
if (FAST_IS_REG(src)) {
|
||||
if (src != RETURN_ADDR_REG)
|
||||
FAIL_IF(push_inst(compiler, ADDI_D | RD(RETURN_ADDR_REG) | RJ(src) | IMM_I12(0)));
|
||||
} else
|
||||
FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, RETURN_ADDR_REG, src, srcw));
|
||||
|
||||
return push_inst(compiler, JIRL | RD(TMP_ZERO) | RJ(RETURN_ADDR_REG) | IMM_I12(0));
|
||||
|
|
@ -2207,8 +2276,11 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_dst(struct sljit_compiler *comp
|
|||
|
||||
switch (op) {
|
||||
case SLJIT_FAST_ENTER:
|
||||
if (FAST_IS_REG(dst))
|
||||
if (FAST_IS_REG(dst)) {
|
||||
if (dst == RETURN_ADDR_REG)
|
||||
return SLJIT_SUCCESS;
|
||||
return push_inst(compiler, ADDI_D | RD(dst) | RJ(RETURN_ADDR_REG) | IMM_I12(0));
|
||||
}
|
||||
|
||||
SLJIT_ASSERT(RETURN_ADDR_REG == TMP_REG2);
|
||||
break;
|
||||
|
|
@ -2676,6 +2748,60 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compi
|
|||
return label;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_aligned_label(struct sljit_compiler *compiler,
|
||||
sljit_s32 alignment, struct sljit_read_only_buffer *buffers)
|
||||
{
|
||||
sljit_uw mask, i;
|
||||
struct sljit_label *label;
|
||||
struct sljit_label *next_label;
|
||||
struct sljit_extended_label *ext_label;
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_PTR(check_sljit_emit_aligned_label(compiler, alignment, buffers));
|
||||
|
||||
sljit_reset_read_only_buffers(buffers);
|
||||
|
||||
if (alignment <= SLJIT_LABEL_ALIGN_4) {
|
||||
SLJIT_SKIP_CHECKS(compiler);
|
||||
label = sljit_emit_label(compiler);
|
||||
PTR_FAIL_IF(!label);
|
||||
} else {
|
||||
/* The used space is filled with NOPs. */
|
||||
mask = ((sljit_uw)1 << alignment) - sizeof(sljit_ins);
|
||||
|
||||
for (i = (mask >> 2); i != 0; i--)
|
||||
PTR_FAIL_IF(push_inst(compiler, NOP));
|
||||
|
||||
ext_label = (struct sljit_extended_label*)ensure_abuf(compiler, sizeof(struct sljit_extended_label));
|
||||
PTR_FAIL_IF(!ext_label);
|
||||
set_extended_label(ext_label, compiler, SLJIT_LABEL_ALIGNED, mask);
|
||||
label = &ext_label->label;
|
||||
}
|
||||
|
||||
if (buffers == NULL)
|
||||
return label;
|
||||
|
||||
next_label = label;
|
||||
|
||||
while (1) {
|
||||
buffers->u.label = next_label;
|
||||
|
||||
for (i = (buffers->size + 3) >> 2; i > 0; i--)
|
||||
PTR_FAIL_IF(push_inst(compiler, NOP));
|
||||
|
||||
buffers = buffers->next;
|
||||
|
||||
if (buffers == NULL)
|
||||
break;
|
||||
|
||||
SLJIT_SKIP_CHECKS(compiler);
|
||||
next_label = sljit_emit_label(compiler);
|
||||
PTR_FAIL_IF(!next_label);
|
||||
}
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
static sljit_ins get_jump_instruction(sljit_s32 type)
|
||||
{
|
||||
switch (type) {
|
||||
|
|
@ -3032,19 +3158,27 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *comp
|
|||
{
|
||||
sljit_ins *ptr;
|
||||
sljit_uw size;
|
||||
sljit_s32 is_compare = (type & SLJIT_COMPARE_SELECT);
|
||||
sljit_s32 inp_flags = ((type & SLJIT_32) ? INT_DATA : WORD_DATA) | LOAD_DATA;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_select(compiler, type, dst_reg, src1, src1w, src2_reg));
|
||||
ADJUST_LOCAL_OFFSET(src1, src1w);
|
||||
|
||||
if (src1 == SLJIT_IMM && type & SLJIT_32)
|
||||
src1w = (sljit_s32)src1w;
|
||||
|
||||
type &= ~(SLJIT_32 | SLJIT_COMPARE_SELECT);
|
||||
|
||||
if (dst_reg != src2_reg) {
|
||||
if (dst_reg == src1) {
|
||||
src1 = src2_reg;
|
||||
src1w = 0;
|
||||
type ^= 0x1;
|
||||
if (!is_compare)
|
||||
type ^= 0x1;
|
||||
} else {
|
||||
if (ADDRESSING_DEPENDS_ON(src1, dst_reg)) {
|
||||
SLJIT_ASSERT(!(type & SLJIT_COMPARE_SELECT));
|
||||
FAIL_IF(push_inst(compiler, ADDI_D | RD(TMP_REG1) | RJ(dst_reg) | IMM_I12(0)));
|
||||
|
||||
if ((src1 & REG_MASK) == dst_reg)
|
||||
|
|
@ -3058,6 +3192,15 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *comp
|
|||
}
|
||||
}
|
||||
|
||||
if (is_compare) {
|
||||
if (src1 & SLJIT_MEM) {
|
||||
FAIL_IF(emit_op_mem(compiler, inp_flags, TMP_REG3, src1, src1w));
|
||||
} else if (src1 == SLJIT_IMM) {
|
||||
FAIL_IF(load_immediate(compiler, TMP_REG3, src1w));
|
||||
} else
|
||||
FAIL_IF(push_inst(compiler, ADDI_D | RD(TMP_REG3) | RJ(src1) | IMM_I12(0)));
|
||||
}
|
||||
|
||||
size = compiler->size;
|
||||
|
||||
ptr = (sljit_ins*)ensure_buf(compiler, sizeof(sljit_ins));
|
||||
|
|
@ -3067,13 +3210,35 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *comp
|
|||
if (src1 & SLJIT_MEM) {
|
||||
FAIL_IF(emit_op_mem(compiler, inp_flags, dst_reg, src1, src1w));
|
||||
} else if (src1 == SLJIT_IMM) {
|
||||
if (type & SLJIT_32)
|
||||
src1w = (sljit_s32)src1w;
|
||||
FAIL_IF(load_immediate(compiler, dst_reg, src1w));
|
||||
} else
|
||||
FAIL_IF(push_inst(compiler, ADDI_D | RD(dst_reg) | RJ(src1) | IMM_I12(0)));
|
||||
|
||||
*ptr = get_jump_instruction(type & ~SLJIT_32) | IMM_I16(compiler->size - size);
|
||||
if (is_compare) {
|
||||
switch (type) {
|
||||
case SLJIT_LESS:
|
||||
case SLJIT_LESS_EQUAL:
|
||||
*ptr = BGEU;
|
||||
break;
|
||||
case SLJIT_GREATER:
|
||||
case SLJIT_GREATER_EQUAL:
|
||||
*ptr = BLTU;
|
||||
break;
|
||||
case SLJIT_SIG_LESS:
|
||||
case SLJIT_SIG_LESS_EQUAL:
|
||||
*ptr = BGE;
|
||||
break;
|
||||
default:
|
||||
*ptr = BLT;
|
||||
break;
|
||||
}
|
||||
|
||||
*ptr |= RJ(TMP_REG3) | RD(dst_reg);
|
||||
} else {
|
||||
*ptr = get_jump_instruction(type);
|
||||
}
|
||||
|
||||
*ptr |= IMM_I16(compiler->size - size);
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
@ -3830,13 +3995,16 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_ta
|
|||
SLJIT_CACHE_FLUSH(inst, inst + 4);
|
||||
}
|
||||
|
||||
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_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 op,
|
||||
sljit_s32 dst, sljit_sw dstw,
|
||||
sljit_sw init_value)
|
||||
{
|
||||
struct sljit_const *const_;
|
||||
sljit_s32 dst_r;
|
||||
sljit_s32 mem_flags = WORD_DATA;
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_PTR(check_sljit_emit_const(compiler, dst, dstw, init_value));
|
||||
CHECK_PTR(check_sljit_emit_const(compiler, op, dst, dstw, init_value));
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
|
||||
const_ = (struct sljit_const*)ensure_abuf(compiler, sizeof(struct sljit_const));
|
||||
|
|
@ -3844,39 +4012,112 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi
|
|||
set_const(const_, compiler);
|
||||
|
||||
dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
|
||||
PTR_FAIL_IF(emit_const(compiler, dst_r, init_value, 0));
|
||||
|
||||
switch (GET_OPCODE(op)) {
|
||||
case SLJIT_MOV_U8:
|
||||
if (init_value & 0x100)
|
||||
init_value |= 0xf00;
|
||||
else
|
||||
init_value &= 0xff;
|
||||
|
||||
PTR_FAIL_IF(push_inst(compiler, ADDI_D | RD(dst_r) | RJ(TMP_ZERO) | IMM_I12(init_value)));
|
||||
mem_flags = BYTE_DATA;
|
||||
break;
|
||||
|
||||
case SLJIT_MOV32:
|
||||
mem_flags = INT_DATA;
|
||||
SLJIT_FALLTHROUGH
|
||||
case SLJIT_MOV_S32:
|
||||
PTR_FAIL_IF(push_inst(compiler, LU12I_W | RD(dst_r) | (sljit_ins)((init_value >> 7) & 0x1ffffe0)));
|
||||
PTR_FAIL_IF(push_inst(compiler, ORI | RD(dst_r) | RJ(dst_r) | IMM_I12(init_value)));
|
||||
break;
|
||||
|
||||
default:
|
||||
PTR_FAIL_IF(emit_const(compiler, dst_r, init_value, 0));
|
||||
break;
|
||||
}
|
||||
|
||||
if (dst & SLJIT_MEM)
|
||||
PTR_FAIL_IF(emit_op_mem(compiler, WORD_DATA, TMP_REG2, dst, dstw));
|
||||
PTR_FAIL_IF(emit_op_mem(compiler, mem_flags, TMP_REG2, dst, dstw));
|
||||
|
||||
return const_;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_mov_addr(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_op_addr(struct sljit_compiler *compiler, sljit_s32 op,
|
||||
sljit_s32 dst, sljit_sw dstw)
|
||||
{
|
||||
struct sljit_jump *jump;
|
||||
sljit_s32 dst_r;
|
||||
sljit_s32 dst_r, target_r;
|
||||
SLJIT_UNUSED_ARG(op);
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_PTR(check_sljit_emit_mov_addr(compiler, dst, dstw));
|
||||
CHECK_PTR(check_sljit_emit_op_addr(compiler, op, dst, dstw));
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
|
||||
dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
|
||||
|
||||
if (op != SLJIT_ADD_ABS_ADDR)
|
||||
target_r = dst_r;
|
||||
else {
|
||||
target_r = TMP_REG1;
|
||||
|
||||
if (dst & SLJIT_MEM)
|
||||
PTR_FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, TMP_REG2, dst, dstw));
|
||||
}
|
||||
|
||||
jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
|
||||
PTR_FAIL_IF(!jump);
|
||||
set_mov_addr(jump, compiler, 0);
|
||||
|
||||
dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
|
||||
PTR_FAIL_IF(push_inst(compiler, (sljit_ins)dst_r));
|
||||
PTR_FAIL_IF(push_inst(compiler, (sljit_ins)target_r));
|
||||
|
||||
compiler->size += JUMP_MAX_SIZE - 1;
|
||||
|
||||
if (op == SLJIT_ADD_ABS_ADDR)
|
||||
PTR_FAIL_IF(push_inst(compiler, ADD_D | RD(dst_r) | RJ(dst_r) | RK(TMP_REG1)));
|
||||
|
||||
if (dst & SLJIT_MEM)
|
||||
PTR_FAIL_IF(emit_op_mem(compiler, WORD_DATA, TMP_REG2, dst, dstw));
|
||||
|
||||
return jump;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_s32 op, sljit_sw new_constant, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_set_jump_addr(addr, (sljit_uw)new_constant, executable_offset);
|
||||
sljit_ins* inst;
|
||||
|
||||
switch (GET_OPCODE(op)) {
|
||||
case SLJIT_MOV_U8:
|
||||
inst = (sljit_ins*)addr;
|
||||
SLJIT_ASSERT((inst[0] & OPC_2RI12(0xb)) == ADDI_D);
|
||||
|
||||
if (new_constant & 0x100)
|
||||
new_constant |= 0xf00;
|
||||
else
|
||||
new_constant &= 0xff;
|
||||
|
||||
SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 0);
|
||||
inst[0] = (inst[0] & 0xffc003ff) | (sljit_ins)((new_constant & 0xfff) << 10);
|
||||
SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 1);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 1);
|
||||
return;
|
||||
|
||||
case SLJIT_MOV32:
|
||||
case SLJIT_MOV_S32:
|
||||
inst = (sljit_ins *)addr;
|
||||
SLJIT_ASSERT((inst[0] & OPC_1RI20(0xa)) == LU12I_W && (inst[1] & OPC_2RI12(0xe)) == ORI);
|
||||
|
||||
SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 0);
|
||||
inst[0] = (inst[0] & (OPC_1RI20(0xa) | 0x1f)) | (sljit_ins)((new_constant >> 7) & 0x1ffffe0);
|
||||
inst[1] = (inst[1] & (OPC_2RI12(0xe) | 0x3ff)) | (sljit_ins)((new_constant & 0xfff) << 10);
|
||||
SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 1);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 2);
|
||||
return;
|
||||
|
||||
default:
|
||||
sljit_set_jump_addr(addr, (sljit_uw)new_constant, executable_offset);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -196,18 +196,13 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_ta
|
|||
|
||||
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);
|
||||
inst[0] = (inst[0] & 0xffff0000) | IMM(new_target >> 16);
|
||||
inst[1] = (inst[1] & 0xffff0000) | IMM(new_target);
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -202,20 +202,15 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_ta
|
|||
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);
|
||||
inst[0] = (inst[0] & 0xffff0000) | IMM(new_target >> 48);
|
||||
inst[1] = (inst[1] & 0xffff0000) | IMM(new_target >> 32);
|
||||
inst[3] = (inst[3] & 0xffff0000) | IMM(new_target >> 16);
|
||||
inst[5] = (inst[5] & 0xffff0000) | IMM(new_target);
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 4] = {
|
|||
#endif /* SLJIT_CONFIG_MIPS_32 */
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Instrucion forms */
|
||||
/* Instruction forms */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
#define S(s) ((sljit_ins)reg_map[s] << 21)
|
||||
|
|
@ -709,6 +709,12 @@ static SLJIT_INLINE void load_addr_to_reg(struct sljit_jump *jump)
|
|||
ins[1] = ORI | S(reg) | T(reg) | IMM(addr & 0xffff);
|
||||
}
|
||||
|
||||
static SLJIT_INLINE sljit_ins *process_extended_label(sljit_ins *code_ptr, struct sljit_extended_label *ext_label)
|
||||
{
|
||||
SLJIT_ASSERT(ext_label->label.u.index == SLJIT_LABEL_ALIGNED);
|
||||
return (sljit_ins*)((sljit_uw)code_ptr & ~(ext_label->data));
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler, sljit_s32 options, void *exec_allocator_data)
|
||||
{
|
||||
struct sljit_memory_fragment *buf;
|
||||
|
|
@ -725,7 +731,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
|||
struct sljit_const *const_;
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_PTR(check_sljit_generate_code(compiler));
|
||||
CHECK_PTR(check_sljit_generate_code(compiler, options));
|
||||
reverse_buf(compiler);
|
||||
|
||||
code = (sljit_ins*)allocate_executable_memory(compiler->size * sizeof(sljit_ins), options, exec_allocator_data, &executable_offset);
|
||||
|
|
@ -752,6 +758,11 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
|||
|
||||
/* These structures are ordered by their address. */
|
||||
if (next_min_addr == next_label_size) {
|
||||
if (label->u.index >= SLJIT_LABEL_ALIGNED) {
|
||||
code_ptr = process_extended_label(code_ptr, (struct sljit_extended_label*)label);
|
||||
*code_ptr = buf_ptr[-1];
|
||||
}
|
||||
|
||||
label->u.addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
|
||||
label->size = (sljit_uw)(code_ptr - code);
|
||||
label = label->next;
|
||||
|
|
@ -796,6 +807,9 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
|||
} while (buf);
|
||||
|
||||
if (label && label->size == word_count) {
|
||||
if (label->u.index >= SLJIT_LABEL_ALIGNED)
|
||||
code_ptr = process_extended_label(code_ptr, (struct sljit_extended_label*)label);
|
||||
|
||||
label->u.addr = (sljit_uw)code_ptr;
|
||||
label->size = (sljit_uw)(code_ptr - code);
|
||||
label = label->next;
|
||||
|
|
@ -1532,11 +1546,11 @@ static sljit_s32 emit_op_mem(struct sljit_compiler *compiler, sljit_s32 flags, s
|
|||
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)
|
||||
static SLJIT_INLINE sljit_s32 emit_op_mem2(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg_ar, sljit_s32 arg1, sljit_sw arg1w, sljit_s32 arg2, sljit_sw arg2w)
|
||||
{
|
||||
if (getput_arg_fast(compiler, flags, reg, arg1, arg1w))
|
||||
if (getput_arg_fast(compiler, flags, reg_ar, arg1, arg1w))
|
||||
return compiler->error;
|
||||
return getput_arg(compiler, flags, reg, arg1, arg1w, arg2, arg2w);
|
||||
return getput_arg(compiler, flags, reg_ar, arg1, arg1w, arg2, arg2w);
|
||||
}
|
||||
|
||||
#define EMIT_LOGICAL(op_imm, op_reg) \
|
||||
|
|
@ -2167,7 +2181,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
|
|||
FAIL_IF(push_inst(compiler, SELECT_OP(DSUBU, SUBU) | SA(0) | T(src2) | D(TMP_REG2), DR(TMP_REG2)));
|
||||
src2 = TMP_REG2;
|
||||
}
|
||||
/* fallthrough */
|
||||
SLJIT_FALLTHROUGH
|
||||
|
||||
case SLJIT_ROTR:
|
||||
EMIT_SHIFT(DROTR, DROTR32, ROTR, DROTRV, ROTRV);
|
||||
|
|
@ -2634,7 +2648,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
|
|||
if ((src1 == SLJIT_IMM && src1w == -1) || (src2 == SLJIT_IMM && src2w == -1)) {
|
||||
return emit_op(compiler, op, flags | CUMULATIVE_OP | IMM_OP, dst, dstw, src1, src1w, src2, src2w);
|
||||
}
|
||||
/* fallthrough */
|
||||
SLJIT_FALLTHROUGH
|
||||
case SLJIT_AND:
|
||||
case SLJIT_OR:
|
||||
return emit_op(compiler, op, flags | CUMULATIVE_OP | LOGICAL_OP | IMM_OP, dst, dstw, src1, src1w, src2, src2w);
|
||||
|
|
@ -2780,6 +2794,59 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *
|
|||
return push_inst(compiler, OR | S(dst_reg) | T(TMP_REG1) | D(dst_reg), DR(dst_reg));
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2_shift(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_sw shift_arg)
|
||||
{
|
||||
sljit_s32 dst_r, tmp_r;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_op2_shift(compiler, op, dst, dstw, src1, src1w, src2, src2w, shift_arg));
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
ADJUST_LOCAL_OFFSET(src1, src1w);
|
||||
ADJUST_LOCAL_OFFSET(src2, src2w);
|
||||
|
||||
shift_arg &= (sljit_sw)((sizeof(sljit_sw) * 8) - 1);
|
||||
|
||||
if (src2 == SLJIT_IMM) {
|
||||
src2w = src2w << shift_arg;
|
||||
shift_arg = 0;
|
||||
}
|
||||
|
||||
if (shift_arg == 0) {
|
||||
SLJIT_SKIP_CHECKS(compiler);
|
||||
return sljit_emit_op2(compiler, GET_OPCODE(op), dst, dstw, src1, src1w, src2, src2w);
|
||||
}
|
||||
|
||||
if (src2 & SLJIT_MEM) {
|
||||
FAIL_IF(emit_op_mem2(compiler, WORD_DATA | LOAD_DATA, DR(TMP_REG2), src2, src2w, src1, src1w));
|
||||
src2 = TMP_REG2;
|
||||
}
|
||||
|
||||
if (src1 == SLJIT_IMM) {
|
||||
FAIL_IF(load_immediate(compiler, DR(TMP_REG1), src1w));
|
||||
src1 = TMP_REG1;
|
||||
} else if (src1 & SLJIT_MEM) {
|
||||
FAIL_IF(emit_op_mem2(compiler, WORD_DATA | LOAD_DATA, DR(TMP_REG1), src1, src1w, dst, dstw));
|
||||
src1 = TMP_REG1;
|
||||
}
|
||||
|
||||
dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
|
||||
tmp_r = (src1 == TMP_REG1) ? TMP_REG2 : TMP_REG1;
|
||||
#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
|
||||
FAIL_IF(push_inst(compiler, (shift_arg >= 32 ? DSLL32 : DSLL) | T(src2) | D(tmp_r) | SH_IMM(shift_arg & 0x1f), DR(tmp_r)));
|
||||
#else /* !SLJIT_CONFIG_MIPS_64 */
|
||||
FAIL_IF(push_inst(compiler, SLL | T(src2) | D(tmp_r) | SH_IMM(shift_arg), DR(tmp_r)));
|
||||
#endif /* SLJIT_CONFIG_MIPS_64 */
|
||||
FAIL_IF(push_inst(compiler, ADDU_W | S(src1) | T(tmp_r) | D(dst_r), DR(dst_r)));
|
||||
|
||||
if (dst & SLJIT_MEM)
|
||||
return emit_op_mem2(compiler, WORD_DATA, DR(dst_r), dst, dstw, 0, 0);
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
#undef SELECT_OP3
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *compiler, sljit_s32 op,
|
||||
|
|
@ -2791,9 +2858,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *comp
|
|||
|
||||
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
|
||||
if (FAST_IS_REG(src)) {
|
||||
if (DR(src) != RETURN_ADDR_REG)
|
||||
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));
|
||||
|
|
@ -2825,8 +2893,11 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_dst(struct sljit_compiler *comp
|
|||
|
||||
switch (op) {
|
||||
case SLJIT_FAST_ENTER:
|
||||
if (FAST_IS_REG(dst))
|
||||
if (FAST_IS_REG(dst)) {
|
||||
if (DR(dst) == RETURN_ADDR_REG)
|
||||
return SLJIT_SUCCESS;
|
||||
return push_inst(compiler, ADDU_W | SA(RETURN_ADDR_REG) | TA(0) | D(dst), UNMOVABLE_INS);
|
||||
}
|
||||
break;
|
||||
case SLJIT_GET_RETURN_ADDRESS:
|
||||
dst_ar = DR(FAST_IS_REG(dst) ? dst : TMP_REG2);
|
||||
|
|
@ -3278,6 +3349,60 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compi
|
|||
return label;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_aligned_label(struct sljit_compiler *compiler,
|
||||
sljit_s32 alignment, struct sljit_read_only_buffer *buffers)
|
||||
{
|
||||
sljit_uw mask, i;
|
||||
struct sljit_label *label;
|
||||
struct sljit_label *next_label;
|
||||
struct sljit_extended_label *ext_label;
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_PTR(check_sljit_emit_aligned_label(compiler, alignment, buffers));
|
||||
|
||||
sljit_reset_read_only_buffers(buffers);
|
||||
|
||||
if (alignment <= SLJIT_LABEL_ALIGN_4) {
|
||||
SLJIT_SKIP_CHECKS(compiler);
|
||||
label = sljit_emit_label(compiler);
|
||||
PTR_FAIL_IF(!label);
|
||||
} else {
|
||||
/* The used space is filled with NOPs. */
|
||||
mask = ((sljit_uw)1 << alignment) - sizeof(sljit_ins);
|
||||
|
||||
for (i = (mask >> 2); i != 0; i--)
|
||||
PTR_FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS));
|
||||
|
||||
ext_label = (struct sljit_extended_label*)ensure_abuf(compiler, sizeof(struct sljit_extended_label));
|
||||
PTR_FAIL_IF(!ext_label);
|
||||
set_extended_label(ext_label, compiler, SLJIT_LABEL_ALIGNED, mask);
|
||||
label = &ext_label->label;
|
||||
}
|
||||
|
||||
if (buffers == NULL)
|
||||
return label;
|
||||
|
||||
next_label = label;
|
||||
|
||||
while (1) {
|
||||
buffers->u.label = next_label;
|
||||
|
||||
for (i = (buffers->size + 3) >> 2; i > 0; i--)
|
||||
PTR_FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS));
|
||||
|
||||
buffers = buffers->next;
|
||||
|
||||
if (buffers == NULL)
|
||||
break;
|
||||
|
||||
SLJIT_SKIP_CHECKS(compiler);
|
||||
next_label = sljit_emit_label(compiler);
|
||||
PTR_FAIL_IF(!next_label);
|
||||
}
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
|
||||
#define BRANCH_LENGTH 4
|
||||
#else
|
||||
|
|
@ -3718,7 +3843,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co
|
|||
|
||||
static sljit_ins get_select_cc(sljit_s32 type, sljit_s32 is_float)
|
||||
{
|
||||
switch (type & ~SLJIT_32) {
|
||||
switch (type) {
|
||||
case SLJIT_EQUAL:
|
||||
return (is_float ? MOVZ_S : MOVZ) | TA(EQUAL_FLAG);
|
||||
case SLJIT_NOT_EQUAL:
|
||||
|
|
@ -3789,15 +3914,37 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *comp
|
|||
CHECK(check_sljit_emit_select(compiler, type, dst_reg, src1, src1w, src2_reg));
|
||||
ADJUST_LOCAL_OFFSET(src1, src1w);
|
||||
|
||||
#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
|
||||
if (src1 == SLJIT_IMM && (type & SLJIT_32))
|
||||
src1w = (sljit_s32)src1w;
|
||||
#endif
|
||||
|
||||
type &= ~SLJIT_32;
|
||||
|
||||
if (type & SLJIT_COMPARE_SELECT) {
|
||||
type ^= SLJIT_COMPARE_SELECT;
|
||||
|
||||
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) {
|
||||
if (src1w == 0) {
|
||||
src1 = 0;
|
||||
} else {
|
||||
FAIL_IF(load_immediate(compiler, DR(TMP_REG1), src1w));
|
||||
src1 = TMP_REG1;
|
||||
}
|
||||
}
|
||||
|
||||
src1w = 0;
|
||||
FAIL_IF(emit_op(compiler, SLJIT_SUB | SLJIT_SET(type & ~0x1), IMM_OP, 0, 0, src1, 0, src2_reg, 0));
|
||||
}
|
||||
|
||||
#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1 && SLJIT_MIPS_REV < 6)
|
||||
if (src1 & SLJIT_MEM) {
|
||||
FAIL_IF(emit_op_mem(compiler, inp_flags, DR(TMP_REG1), src1, src1w));
|
||||
src1 = TMP_REG1;
|
||||
} else if (src1 == SLJIT_IMM) {
|
||||
#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
|
||||
if (type & SLJIT_32)
|
||||
src1w = (sljit_s32)src1w;
|
||||
#endif
|
||||
FAIL_IF(load_immediate(compiler, DR(TMP_REG1), src1w));
|
||||
src1 = TMP_REG1;
|
||||
}
|
||||
|
|
@ -3834,16 +3981,12 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *comp
|
|||
}
|
||||
|
||||
SLJIT_SKIP_CHECKS(compiler);
|
||||
jump = sljit_emit_jump(compiler, (type & ~SLJIT_32) ^ 0x1);
|
||||
jump = sljit_emit_jump(compiler, type ^ 0x1);
|
||||
FAIL_IF(!jump);
|
||||
|
||||
if (src1 & SLJIT_MEM) {
|
||||
FAIL_IF(emit_op_mem(compiler, inp_flags, DR(dst_reg), src1, src1w));
|
||||
} else if (src1 == SLJIT_IMM) {
|
||||
#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
|
||||
if (type & SLJIT_32)
|
||||
src1w = (sljit_s32)src1w;
|
||||
#endif /* SLJIT_CONFIG_MIPS_64 */
|
||||
FAIL_IF(load_immediate(compiler, DR(dst_reg), src1w));
|
||||
} else
|
||||
FAIL_IF(push_inst(compiler, mov_ins | S(src1) | TA(0) | D(dst_reg), DR(dst_reg)));
|
||||
|
|
@ -3887,11 +4030,11 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fselect(struct sljit_compiler *com
|
|||
src1 = TMP_FREG2;
|
||||
}
|
||||
|
||||
return push_inst(compiler, get_select_cc(type, 1) | FMT(type) | FS(src1) | FD(dst_freg), MOVABLE_INS);
|
||||
return push_inst(compiler, get_select_cc(type & ~SLJIT_32, 1) | FMT(type) | FS(src1) | FD(dst_freg), MOVABLE_INS);
|
||||
|
||||
#else /* SLJIT_MIPS_REV < 1 || SLJIT_MIPS_REV >= 6 */
|
||||
SLJIT_SKIP_CHECKS(compiler);
|
||||
jump = sljit_emit_jump(compiler, (type & ~SLJIT_32) ^ 0x1);
|
||||
jump = sljit_emit_jump(compiler, type ^ 0x1);
|
||||
FAIL_IF(!jump);
|
||||
|
||||
if (src1 & SLJIT_MEM)
|
||||
|
|
@ -4301,7 +4444,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_atomic_store(struct sljit_compiler
|
|||
#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
|
||||
ins = SCD;
|
||||
break;
|
||||
#endif /* SLJIT_CONFIG_RISCV_64 */
|
||||
#endif /* SLJIT_CONFIG_MIPS_64 */
|
||||
case SLJIT_MOV_S32:
|
||||
case SLJIT_MOV32:
|
||||
op |= SLJIT_32;
|
||||
|
|
@ -4319,13 +4462,16 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_atomic_store(struct sljit_compiler
|
|||
return push_inst(compiler, ins | TA(OTHER_FLAG) | S(mem_reg), OTHER_FLAG);
|
||||
}
|
||||
|
||||
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_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 op,
|
||||
sljit_s32 dst, sljit_sw dstw,
|
||||
sljit_sw init_value)
|
||||
{
|
||||
struct sljit_const *const_;
|
||||
sljit_s32 dst_r;
|
||||
sljit_s32 mem_flags = WORD_DATA;
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_PTR(check_sljit_emit_const(compiler, dst, dstw, init_value));
|
||||
CHECK_PTR(check_sljit_emit_const(compiler, op, dst, dstw, init_value));
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
|
||||
const_ = (struct sljit_const*)ensure_abuf(compiler, sizeof(struct sljit_const));
|
||||
|
|
@ -4333,37 +4479,119 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi
|
|||
set_const(const_, compiler);
|
||||
|
||||
dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
|
||||
PTR_FAIL_IF(emit_const(compiler, dst_r, init_value));
|
||||
|
||||
switch (GET_OPCODE(op)) {
|
||||
case SLJIT_MOV_U8:
|
||||
if (init_value & 0x100)
|
||||
init_value |= 0xff00;
|
||||
else
|
||||
init_value &= 0xff;
|
||||
|
||||
PTR_FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(dst_r) | IMM(init_value), DR(dst_r)));
|
||||
mem_flags = BYTE_DATA;
|
||||
break;
|
||||
|
||||
#if (defined(SLJIT_CONFIG_MIPS_64) && SLJIT_CONFIG_MIPS_64)
|
||||
case SLJIT_MOV32:
|
||||
mem_flags = INT_DATA;
|
||||
SLJIT_FALLTHROUGH
|
||||
case SLJIT_MOV_S32:
|
||||
PTR_FAIL_IF(push_inst(compiler, LUI | T(dst_r) | IMM(init_value >> 16), DR(dst_r)));
|
||||
PTR_FAIL_IF(push_inst(compiler, ORI | S(dst_r) | T(dst_r) | IMM(init_value), DR(dst_r)));
|
||||
break;
|
||||
#endif /* SLJIT_CONFIG_MIPS_64 */
|
||||
|
||||
default:
|
||||
PTR_FAIL_IF(emit_const(compiler, dst_r, init_value));
|
||||
break;
|
||||
}
|
||||
|
||||
if (dst & SLJIT_MEM)
|
||||
PTR_FAIL_IF(emit_op_mem(compiler, WORD_DATA, DR(TMP_REG2), dst, dstw));
|
||||
PTR_FAIL_IF(emit_op_mem(compiler, mem_flags, DR(TMP_REG2), dst, dstw));
|
||||
|
||||
return const_;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_mov_addr(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_op_addr(struct sljit_compiler *compiler, sljit_s32 op,
|
||||
sljit_s32 dst, sljit_sw dstw)
|
||||
{
|
||||
struct sljit_jump *jump;
|
||||
sljit_s32 dst_r;
|
||||
sljit_s32 dst_r, target_r;
|
||||
SLJIT_UNUSED_ARG(op);
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_PTR(check_sljit_emit_mov_addr(compiler, dst, dstw));
|
||||
CHECK_PTR(check_sljit_emit_op_addr(compiler, op, dst, dstw));
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
|
||||
dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
|
||||
|
||||
if (op != SLJIT_ADD_ABS_ADDR)
|
||||
target_r = dst_r;
|
||||
else {
|
||||
target_r = TMP_REG1;
|
||||
|
||||
if (dst & SLJIT_MEM)
|
||||
PTR_FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, DR(TMP_REG2), dst, dstw));
|
||||
}
|
||||
|
||||
jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
|
||||
PTR_FAIL_IF(!jump);
|
||||
set_mov_addr(jump, compiler, 0);
|
||||
|
||||
dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
|
||||
PTR_FAIL_IF(push_inst(compiler, (sljit_ins)dst_r, UNMOVABLE_INS));
|
||||
PTR_FAIL_IF(push_inst(compiler, (sljit_ins)target_r, UNMOVABLE_INS));
|
||||
#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
|
||||
compiler->size += 1;
|
||||
#else
|
||||
compiler->size += 5;
|
||||
#endif
|
||||
|
||||
if (op == SLJIT_ADD_ABS_ADDR)
|
||||
PTR_FAIL_IF(push_inst(compiler, ADDU_W | S(dst_r) | T(TMP_REG1) | D(dst_r), DR(dst_r)));
|
||||
|
||||
if (dst & SLJIT_MEM)
|
||||
PTR_FAIL_IF(emit_op_mem(compiler, WORD_DATA, DR(TMP_REG2), dst, dstw));
|
||||
|
||||
return jump;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_s32 op, sljit_sw new_constant, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_ins *inst;
|
||||
|
||||
switch (GET_OPCODE(op)) {
|
||||
case SLJIT_MOV_U8:
|
||||
inst = (sljit_ins *)addr;
|
||||
SLJIT_ASSERT((inst[0] & 0xfc000000) == ADDIU);
|
||||
|
||||
if (new_constant & 0x100)
|
||||
new_constant |= 0xff00;
|
||||
else
|
||||
new_constant &= 0xff;
|
||||
|
||||
SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 0);
|
||||
inst[0] = (inst[0] & 0xffff0000) | IMM(new_constant);
|
||||
SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 1);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 1);
|
||||
return;
|
||||
|
||||
#if (defined(SLJIT_CONFIG_MIPS_64) && SLJIT_CONFIG_MIPS_64)
|
||||
case SLJIT_MOV32:
|
||||
case SLJIT_MOV_S32:
|
||||
inst = (sljit_ins *)addr;
|
||||
SLJIT_ASSERT((inst[0] & 0xffe00000) == LUI && (inst[1] & 0xfc000000) == ORI);
|
||||
|
||||
SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 0);
|
||||
inst[0] = (inst[0] & 0xffff0000) | IMM(new_constant >> 16);
|
||||
inst[1] = (inst[1] & 0xffff0000) | IMM(new_constant);
|
||||
SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 1);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 2);
|
||||
return;
|
||||
#endif /* SLJIT_CONFIG_MIPS_64 */
|
||||
|
||||
default:
|
||||
sljit_set_jump_addr(addr, (sljit_uw)new_constant, executable_offset);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -477,8 +477,8 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_ta
|
|||
|
||||
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);
|
||||
inst[0] = (inst[0] & 0xffff0000) | IMM(new_target >> 16);
|
||||
inst[1] = (inst[1] & 0xffff0000) | IMM(new_target);
|
||||
SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 1);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 2);
|
||||
|
|
|
|||
|
|
@ -709,10 +709,10 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_ta
|
|||
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);
|
||||
inst[0] = (inst[0] & 0xffff0000u) | IMM(new_target >> 48);
|
||||
inst[1] = (inst[1] & 0xffff0000u) | IMM(new_target >> 32);
|
||||
inst[3] = (inst[3] & 0xffff0000u) | IMM(new_target >> 16);
|
||||
inst[4] = (inst[4] & 0xffff0000u) | IMM(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);
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 3] = {
|
|||
};
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Instrucion forms */
|
||||
/* Instruction forms */
|
||||
/* --------------------------------------------------------------------- */
|
||||
#define D(d) ((sljit_ins)reg_map[d] << 21)
|
||||
#define S(s) ((sljit_ins)reg_map[s] << 21)
|
||||
|
|
@ -504,6 +504,12 @@ static void generate_jump_or_mov_addr(struct sljit_jump *jump, sljit_sw executab
|
|||
#endif /* SLJIT_CONFIG_PPC_32 */
|
||||
}
|
||||
|
||||
static SLJIT_INLINE sljit_ins *process_extended_label(sljit_ins *code_ptr, struct sljit_extended_label *ext_label)
|
||||
{
|
||||
SLJIT_ASSERT(ext_label->label.u.index == SLJIT_LABEL_ALIGNED);
|
||||
return (sljit_ins*)((sljit_uw)code_ptr & ~(ext_label->data));
|
||||
}
|
||||
|
||||
static void reduce_code_size(struct sljit_compiler *compiler)
|
||||
{
|
||||
struct sljit_label *label;
|
||||
|
|
@ -619,18 +625,20 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
|||
struct sljit_const *const_;
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_PTR(check_sljit_generate_code(compiler));
|
||||
CHECK_PTR(check_sljit_generate_code(compiler, options));
|
||||
|
||||
reduce_code_size(compiler);
|
||||
|
||||
#if (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL)
|
||||
if (!(options & SLJIT_GENERATE_CODE_NO_CONTEXT)) {
|
||||
/* add to compiler->size additional instruction space to hold the trampoline and padding */
|
||||
#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
|
||||
compiler->size += (compiler->size & 0x1) + (sizeof(struct sljit_function_context) / sizeof(sljit_ins));
|
||||
#else /* !SLJIT_CONFIG_PPC_64 */
|
||||
compiler->size += (sizeof(struct sljit_function_context) / sizeof(sljit_ins));
|
||||
#endif /* SLJIT_CONFIG_PPC_64 */
|
||||
}
|
||||
#endif /* SLJIT_INDIRECT_CALL */
|
||||
code = (sljit_ins*)allocate_executable_memory(compiler->size * sizeof(sljit_ins), options, exec_allocator_data, &executable_offset);
|
||||
PTR_FAIL_WITH_EXEC_IF(code);
|
||||
|
||||
|
|
@ -657,6 +665,11 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
|||
|
||||
/* These structures are ordered by their address. */
|
||||
if (next_min_addr == next_label_size) {
|
||||
if (label->u.index >= SLJIT_LABEL_ALIGNED) {
|
||||
code_ptr = process_extended_label(code_ptr, (struct sljit_extended_label*)label);
|
||||
*code_ptr = buf_ptr[-1];
|
||||
}
|
||||
|
||||
/* Just recording the address. */
|
||||
label->u.addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
|
||||
label->size = (sljit_uw)(code_ptr - code);
|
||||
|
|
@ -700,6 +713,9 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
|||
} while (buf);
|
||||
|
||||
if (label && label->size == word_count) {
|
||||
if (label->u.index >= SLJIT_LABEL_ALIGNED)
|
||||
code_ptr = process_extended_label(code_ptr, (struct sljit_extended_label*)label);
|
||||
|
||||
label->u.addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
|
||||
label->size = (sljit_uw)(code_ptr - code);
|
||||
label = label->next;
|
||||
|
|
@ -710,7 +726,8 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
|||
SLJIT_ASSERT(!const_);
|
||||
|
||||
#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))));
|
||||
SLJIT_ASSERT(code_ptr - code <= (sljit_sw)(compiler->size -
|
||||
((options & SLJIT_GENERATE_CODE_NO_CONTEXT) ? 0 : (sizeof(struct sljit_function_context) / sizeof(sljit_ins)))));
|
||||
#else
|
||||
SLJIT_ASSERT(code_ptr - code <= (sljit_sw)compiler->size);
|
||||
#endif
|
||||
|
|
@ -727,12 +744,14 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
|||
code = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(code, executable_offset);
|
||||
|
||||
#if (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL)
|
||||
if (!(options & SLJIT_GENERATE_CODE_NO_CONTEXT)) {
|
||||
#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
|
||||
if (((sljit_sw)code_ptr) & 0x4)
|
||||
code_ptr++;
|
||||
#endif /* SLJIT_CONFIG_PPC_64 */
|
||||
sljit_set_function_context(NULL, (struct sljit_function_context*)code_ptr, (sljit_uw)code, (void*)sljit_generate_code);
|
||||
}
|
||||
#endif /* SLJIT_INDIRECT_CALL */
|
||||
|
||||
code_ptr = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
|
||||
|
||||
|
|
@ -740,12 +759,14 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
|||
SLJIT_UPDATE_WX_FLAGS(code, code_ptr, 1);
|
||||
|
||||
#if (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL)
|
||||
compiler->executable_size = (sljit_uw)(code_ptr - code) * sizeof(sljit_ins) + sizeof(struct sljit_function_context);
|
||||
return code_ptr;
|
||||
#else
|
||||
if (!(options & SLJIT_GENERATE_CODE_NO_CONTEXT)) {
|
||||
compiler->executable_size = (sljit_uw)(code_ptr - code) * sizeof(sljit_ins) + sizeof(struct sljit_function_context);
|
||||
return code_ptr;
|
||||
}
|
||||
#endif /* SLJIT_INDIRECT_CALL */
|
||||
|
||||
compiler->executable_size = (sljit_uw)(code_ptr - code) * sizeof(sljit_ins);
|
||||
return code;
|
||||
#endif
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type)
|
||||
|
|
@ -1683,7 +1704,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
|
|||
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
|
||||
op |= SLJIT_32;
|
||||
#endif /* SLJIT_CONFIG_PPC_64 */
|
||||
/* fallthrough */
|
||||
SLJIT_FALLTHROUGH
|
||||
case SLJIT_REV:
|
||||
case SLJIT_REV_U16:
|
||||
case SLJIT_REV_S16:
|
||||
|
|
@ -1925,7 +1946,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
|
|||
if (src1 == SLJIT_IMM && src1w == -1) {
|
||||
return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM4, dst, dstw, TMP_REG1, 0, src2, src2w);
|
||||
}
|
||||
/* fallthrough */
|
||||
SLJIT_FALLTHROUGH
|
||||
case SLJIT_AND:
|
||||
case SLJIT_OR:
|
||||
/* Commutative unsigned operations. */
|
||||
|
|
@ -2103,6 +2124,56 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *
|
|||
return push_inst(compiler, OR | S(dst_reg) | A(dst_reg) | B(TMP_REG1));
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2_shift(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_sw shift_arg)
|
||||
{
|
||||
sljit_s32 dst_r, tmp_r;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_op2_shift(compiler, op, dst, dstw, src1, src1w, src2, src2w, shift_arg));
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
ADJUST_LOCAL_OFFSET(src1, src1w);
|
||||
ADJUST_LOCAL_OFFSET(src2, src2w);
|
||||
|
||||
shift_arg &= (sljit_sw)((sizeof(sljit_sw) * 8) - 1);
|
||||
|
||||
if (src2 == SLJIT_IMM) {
|
||||
src2w = src2w << shift_arg;
|
||||
shift_arg = 0;
|
||||
}
|
||||
|
||||
if (shift_arg == 0) {
|
||||
SLJIT_SKIP_CHECKS(compiler);
|
||||
return sljit_emit_op2(compiler, GET_OPCODE(op), dst, dstw, src1, src1w, src2, src2w);
|
||||
}
|
||||
|
||||
if (src1 == SLJIT_IMM) {
|
||||
FAIL_IF(load_immediate(compiler, TMP_REG1, src1w));
|
||||
src1 = TMP_REG1;
|
||||
} else if (src1 & SLJIT_MEM) {
|
||||
FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, TMP_REG1, src1, src1w, TMP_REG1));
|
||||
src1 = TMP_REG1;
|
||||
}
|
||||
|
||||
tmp_r = (src1 == TMP_REG1) ? TMP_REG2 : TMP_REG1;
|
||||
|
||||
if (src2 & SLJIT_MEM) {
|
||||
FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, tmp_r, src2, src2w, tmp_r));
|
||||
src2 = tmp_r;
|
||||
}
|
||||
|
||||
dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
|
||||
FAIL_IF(push_inst(compiler, SLWI_W(shift_arg) | S(src2) | A(tmp_r)));
|
||||
FAIL_IF(push_inst(compiler, ADD | D(dst_r) | A(src1) | B(tmp_r)));
|
||||
|
||||
if (dst & SLJIT_MEM)
|
||||
return emit_op_mem(compiler, WORD_DATA, dst_r, dst, dstw, TMP_REG1);
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
static sljit_s32 emit_prefetch(struct sljit_compiler *compiler,
|
||||
sljit_s32 src, sljit_sw srcw)
|
||||
{
|
||||
|
|
@ -2322,7 +2393,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compil
|
|||
FAIL_IF(push_inst(compiler, FRSP | FD(dst_r) | FB(src)));
|
||||
break;
|
||||
}
|
||||
/* Fall through. */
|
||||
SLJIT_FALLTHROUGH
|
||||
case SLJIT_MOV_F64:
|
||||
if (src != dst_r) {
|
||||
if (!(dst & SLJIT_MEM))
|
||||
|
|
@ -2447,13 +2518,67 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compi
|
|||
return label;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_aligned_label(struct sljit_compiler *compiler,
|
||||
sljit_s32 alignment, struct sljit_read_only_buffer *buffers)
|
||||
{
|
||||
sljit_uw mask, i;
|
||||
struct sljit_label *label;
|
||||
struct sljit_label *next_label;
|
||||
struct sljit_extended_label *ext_label;
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_PTR(check_sljit_emit_aligned_label(compiler, alignment, buffers));
|
||||
|
||||
sljit_reset_read_only_buffers(buffers);
|
||||
|
||||
if (alignment <= SLJIT_LABEL_ALIGN_4) {
|
||||
SLJIT_SKIP_CHECKS(compiler);
|
||||
label = sljit_emit_label(compiler);
|
||||
PTR_FAIL_IF(!label);
|
||||
} else {
|
||||
/* The used space is filled with NOPs. */
|
||||
mask = ((sljit_uw)1 << alignment) - sizeof(sljit_ins);
|
||||
|
||||
for (i = (mask >> 2); i != 0; i--)
|
||||
PTR_FAIL_IF(push_inst(compiler, NOP));
|
||||
|
||||
ext_label = (struct sljit_extended_label*)ensure_abuf(compiler, sizeof(struct sljit_extended_label));
|
||||
PTR_FAIL_IF(!ext_label);
|
||||
set_extended_label(ext_label, compiler, SLJIT_LABEL_ALIGNED, mask);
|
||||
label = &ext_label->label;
|
||||
}
|
||||
|
||||
if (buffers == NULL)
|
||||
return label;
|
||||
|
||||
next_label = label;
|
||||
|
||||
while (1) {
|
||||
buffers->u.label = next_label;
|
||||
|
||||
for (i = (buffers->size + 3) >> 2; i > 0; i--)
|
||||
PTR_FAIL_IF(push_inst(compiler, NOP));
|
||||
|
||||
buffers = buffers->next;
|
||||
|
||||
if (buffers == NULL)
|
||||
break;
|
||||
|
||||
SLJIT_SKIP_CHECKS(compiler);
|
||||
next_label = sljit_emit_label(compiler);
|
||||
PTR_FAIL_IF(!next_label);
|
||||
}
|
||||
|
||||
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 */
|
||||
SLJIT_FALLTHROUGH
|
||||
|
||||
case SLJIT_EQUAL:
|
||||
case SLJIT_ATOMIC_STORED:
|
||||
|
|
@ -2462,7 +2587,7 @@ static sljit_ins get_bo_bi_flags(struct sljit_compiler *compiler, sljit_s32 type
|
|||
case SLJIT_CARRY:
|
||||
if (compiler->status_flags_state & SLJIT_CURRENT_FLAGS_SUB)
|
||||
return (12 << 21) | (2 << 16);
|
||||
/* fallthrough */
|
||||
SLJIT_FALLTHROUGH
|
||||
|
||||
case SLJIT_NOT_EQUAL:
|
||||
case SLJIT_ATOMIC_NOT_STORED:
|
||||
|
|
@ -2835,6 +2960,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *comp
|
|||
{
|
||||
sljit_ins *ptr;
|
||||
sljit_uw size;
|
||||
sljit_s32 is_compare = (type & SLJIT_COMPARE_SELECT);
|
||||
sljit_ins ins;
|
||||
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
|
||||
sljit_s32 inp_flags = ((type & SLJIT_32) ? INT_DATA : WORD_DATA) | LOAD_DATA;
|
||||
#else /* !SLJIT_CONFIG_PPC_64 */
|
||||
|
|
@ -2846,6 +2973,45 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *comp
|
|||
|
||||
ADJUST_LOCAL_OFFSET(src1, src1w);
|
||||
|
||||
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
|
||||
if (src1 == SLJIT_IMM && (type & SLJIT_32))
|
||||
src1w = (sljit_s32)src1w;
|
||||
#endif /* SLJIT_CONFIG_PPC_64 */
|
||||
|
||||
type &= ~(SLJIT_32 | SLJIT_COMPARE_SELECT);
|
||||
|
||||
if (is_compare) {
|
||||
ins = 0;
|
||||
|
||||
if (src1 & SLJIT_MEM) {
|
||||
FAIL_IF(emit_op_mem(compiler, inp_flags, TMP_REG1, src1, src1w, TMP_REG1));
|
||||
src1 = TMP_REG1;
|
||||
src1w = 0;
|
||||
}
|
||||
|
||||
if (src1 == SLJIT_IMM) {
|
||||
if (type >= SLJIT_LESS && type <= SLJIT_LESS_EQUAL && src1w >= 0 && src1w <= UIMM_MAX)
|
||||
ins = CMPLI | CRD(0) | IMM(src1w);
|
||||
else if (type >= SLJIT_SIG_LESS && type <= SLJIT_SIG_LESS_EQUAL && src1w >= SIMM_MIN && src1w <= SIMM_MAX)
|
||||
ins = CMPI | CRD(0) | IMM(src1w);
|
||||
else {
|
||||
FAIL_IF(load_immediate(compiler, TMP_REG1, src1w));
|
||||
src1 = TMP_REG1;
|
||||
src1w = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (ins == 0)
|
||||
ins = ((type >= SLJIT_LESS && type <= SLJIT_LESS_EQUAL) ? CMPL : CMP) | CRD(0) | B(src1);
|
||||
|
||||
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
|
||||
if (inp_flags == (WORD_DATA | LOAD_DATA))
|
||||
ins |= CRD(1);
|
||||
#endif /* SLJIT_CONFIG_PPC_64 */
|
||||
FAIL_IF(push_inst(compiler, ins | A(src2_reg)));
|
||||
type ^= 0x1;
|
||||
}
|
||||
|
||||
if (dst_reg != src2_reg) {
|
||||
if (dst_reg == src1) {
|
||||
src1 = src2_reg;
|
||||
|
|
@ -2866,7 +3032,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *comp
|
|||
}
|
||||
}
|
||||
|
||||
if (((type & ~SLJIT_32) | 0x1) == SLJIT_NOT_CARRY)
|
||||
if ((type | 0x1) == SLJIT_NOT_CARRY)
|
||||
FAIL_IF(push_inst(compiler, ADDE | RC(ALT_SET_FLAGS) | D(TMP_REG1) | A(TMP_ZERO) | B(TMP_ZERO)));
|
||||
|
||||
size = compiler->size;
|
||||
|
|
@ -2878,15 +3044,11 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *comp
|
|||
if (src1 & SLJIT_MEM) {
|
||||
FAIL_IF(emit_op_mem(compiler, inp_flags, dst_reg, src1, src1w, TMP_REG1));
|
||||
} else if (src1 == SLJIT_IMM) {
|
||||
#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64)
|
||||
if (type & SLJIT_32)
|
||||
src1w = (sljit_s32)src1w;
|
||||
#endif /* SLJIT_CONFIG_RISCV_64 */
|
||||
FAIL_IF(load_immediate(compiler, dst_reg, src1w));
|
||||
} else
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | A(dst_reg) | B(src1)));
|
||||
|
||||
*ptr = BCx | get_bo_bi_flags(compiler, (type ^ 0x1) & ~SLJIT_32) | (sljit_ins)((compiler->size - size) << 2);
|
||||
*ptr = BCx | get_bo_bi_flags(compiler, type ^ 0x1) | (sljit_ins)((compiler->size - size) << 2);
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
@ -3162,7 +3324,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_atomic_load(struct sljit_compiler
|
|||
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
|
||||
ins = LDARX;
|
||||
break;
|
||||
#endif /* SLJIT_CONFIG_RISCV_64 */
|
||||
#endif /* SLJIT_CONFIG_PPC_64 */
|
||||
case SLJIT_MOV_U32:
|
||||
case SLJIT_MOV32:
|
||||
ins = LWARX;
|
||||
|
|
@ -3200,7 +3362,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_atomic_store(struct sljit_compiler
|
|||
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
|
||||
ins = STDCX | 0x1;
|
||||
break;
|
||||
#endif /* SLJIT_CONFIG_RISCV_64 */
|
||||
#endif /* SLJIT_CONFIG_PPC_64 */
|
||||
case SLJIT_MOV_U32:
|
||||
case SLJIT_MOV32:
|
||||
ins = STWCX | 0x1;
|
||||
|
|
@ -3216,13 +3378,16 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_atomic_store(struct sljit_compiler
|
|||
return push_inst(compiler, ins | D(src_reg) | B(mem_reg));
|
||||
}
|
||||
|
||||
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_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 op,
|
||||
sljit_s32 dst, sljit_sw dstw,
|
||||
sljit_sw init_value)
|
||||
{
|
||||
struct sljit_const *const_;
|
||||
sljit_s32 dst_r;
|
||||
sljit_s32 mem_flags = WORD_DATA;
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_PTR(check_sljit_emit_const(compiler, dst, dstw, init_value));
|
||||
CHECK_PTR(check_sljit_emit_const(compiler, op, dst, dstw, init_value));
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
|
||||
const_ = (struct sljit_const*)ensure_abuf(compiler, sizeof(struct sljit_const));
|
||||
|
|
@ -3230,42 +3395,119 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi
|
|||
set_const(const_, compiler);
|
||||
|
||||
dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
|
||||
PTR_FAIL_IF(emit_const(compiler, dst_r, init_value));
|
||||
|
||||
switch (GET_OPCODE(op)) {
|
||||
case SLJIT_MOV_U8:
|
||||
if (init_value & 0x100)
|
||||
init_value |= 0xff00;
|
||||
else
|
||||
init_value &= 0xff;
|
||||
|
||||
PTR_FAIL_IF(push_inst(compiler, ADDI | D(dst_r) | A(0) | IMM(init_value)));
|
||||
mem_flags = BYTE_DATA;
|
||||
break;
|
||||
|
||||
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
|
||||
case SLJIT_MOV32:
|
||||
mem_flags = INT_DATA;
|
||||
SLJIT_FALLTHROUGH
|
||||
case SLJIT_MOV_S32:
|
||||
PTR_FAIL_IF(push_inst(compiler, ADDIS | D(dst_r) | A(0) | IMM(init_value >> 16)));
|
||||
PTR_FAIL_IF(push_inst(compiler, ORI | S(dst_r) | A(dst_r) | IMM(init_value)));
|
||||
break;
|
||||
#endif /* SLJIT_CONFIG_PPC_64 */
|
||||
|
||||
default:
|
||||
PTR_FAIL_IF(emit_const(compiler, dst_r, init_value));
|
||||
break;
|
||||
}
|
||||
|
||||
if (dst & SLJIT_MEM)
|
||||
PTR_FAIL_IF(emit_op_mem(compiler, WORD_DATA, dst_r, dst, dstw, TMP_REG1));
|
||||
PTR_FAIL_IF(emit_op_mem(compiler, mem_flags, dst_r, dst, dstw, TMP_REG1));
|
||||
|
||||
return const_;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_mov_addr(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_op_addr(struct sljit_compiler *compiler, sljit_s32 op,
|
||||
sljit_s32 dst, sljit_sw dstw)
|
||||
{
|
||||
struct sljit_jump *jump;
|
||||
sljit_s32 dst_r;
|
||||
sljit_s32 dst_r, target_r;
|
||||
SLJIT_UNUSED_ARG(op);
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_PTR(check_sljit_emit_mov_addr(compiler, dst, dstw));
|
||||
CHECK_PTR(check_sljit_emit_op_addr(compiler, op, dst, dstw));
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
|
||||
dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
|
||||
|
||||
if (op != SLJIT_ADD_ABS_ADDR)
|
||||
target_r = dst_r;
|
||||
else {
|
||||
target_r = TMP_REG1;
|
||||
|
||||
if (dst & SLJIT_MEM)
|
||||
PTR_FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, dst_r, dst, dstw, TMP_REG1));
|
||||
}
|
||||
|
||||
jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
|
||||
PTR_FAIL_IF(!jump);
|
||||
set_mov_addr(jump, compiler, 0);
|
||||
|
||||
dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
|
||||
PTR_FAIL_IF(push_inst(compiler, (sljit_ins)dst_r));
|
||||
PTR_FAIL_IF(push_inst(compiler, (sljit_ins)target_r));
|
||||
#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
|
||||
compiler->size++;
|
||||
#else
|
||||
compiler->size += 4;
|
||||
#endif
|
||||
|
||||
if (op == SLJIT_ADD_ABS_ADDR)
|
||||
PTR_FAIL_IF(push_inst(compiler, ADD | D(dst_r) | A(dst_r) | B(TMP_REG1)));
|
||||
|
||||
if (dst & SLJIT_MEM)
|
||||
PTR_FAIL_IF(emit_op(compiler, SLJIT_MOV, WORD_DATA, dst, dstw, TMP_REG1, 0, TMP_REG2, 0));
|
||||
PTR_FAIL_IF(emit_op_mem(compiler, WORD_DATA, dst_r, dst, dstw, TMP_REG1));
|
||||
|
||||
return jump;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_s32 op, sljit_sw new_constant, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_set_jump_addr(addr, (sljit_uw)new_constant, executable_offset);
|
||||
sljit_ins *inst;
|
||||
|
||||
switch (GET_OPCODE(op)) {
|
||||
case SLJIT_MOV_U8:
|
||||
inst = (sljit_ins *)addr;
|
||||
SLJIT_ASSERT((inst[0] & 0xfc1f0000) == ADDI);
|
||||
|
||||
if (new_constant & 0x100)
|
||||
new_constant |= 0xff00;
|
||||
else
|
||||
new_constant &= 0xff;
|
||||
|
||||
SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 0);
|
||||
inst[0] = (inst[0] & 0xffff0000) | IMM(new_constant);
|
||||
SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 1);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 1);
|
||||
return;
|
||||
|
||||
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
|
||||
case SLJIT_MOV32:
|
||||
case SLJIT_MOV_S32:
|
||||
inst = (sljit_ins *)addr;
|
||||
SLJIT_ASSERT((inst[0] & 0xfc1f0000) == ADDIS && (inst[1] & 0xfc000000) == ORI);
|
||||
|
||||
SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 0);
|
||||
inst[0] = (inst[0] & 0xffff0000) | IMM(new_constant >> 16);
|
||||
inst[1] = (inst[1] & 0xffff0000) | IMM(new_constant);
|
||||
SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 1);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 2);
|
||||
return;
|
||||
#endif /* SLJIT_CONFIG_PPC_64 */
|
||||
|
||||
default:
|
||||
sljit_set_jump_addr(addr, (sljit_uw)new_constant, executable_offset);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,17 +28,28 @@ static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_r
|
|||
{
|
||||
SLJIT_UNUSED_ARG(tmp_r);
|
||||
|
||||
if (RISCV_HAS_COMPRESSED(200) && imm <= SIMM16_MAX && imm >= SIMM16_MIN)
|
||||
return push_inst16(compiler, C_LI | C_RD(dst_r) | C_IMM_I(imm));
|
||||
|
||||
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 (RISCV_HAS_COMPRESSED(200) && imm <= 0x1ffff && imm >= -0x20000)
|
||||
FAIL_IF(push_inst16(compiler, C_LUI | C_RD(dst_r) | ((sljit_u16)(((imm) & 0x1f000) >> 10) | ((imm) & 0x20000) >> 5)));
|
||||
else
|
||||
FAIL_IF(push_inst(compiler, LUI | RD(dst_r) | (sljit_ins)(imm & ~(sljit_sw)0xfff)));
|
||||
|
||||
if ((imm & 0xfff) == 0)
|
||||
imm &= 0xfff;
|
||||
|
||||
if (imm == 0)
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
if (RISCV_HAS_COMPRESSED(200) && (imm <= 0x1f || imm >= 0xfe0))
|
||||
return push_inst16(compiler, C_ADDI | C_RD(dst_r) | C_IMM_I(imm));
|
||||
|
||||
return push_inst(compiler, ADDI | RD(dst_r) | RS1(dst_r) | IMM_I(imm));
|
||||
}
|
||||
|
||||
|
|
@ -123,20 +134,21 @@ static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_
|
|||
|
||||
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_u16 *inst = (sljit_u16*)addr;
|
||||
SLJIT_UNUSED_ARG(executable_offset);
|
||||
|
||||
if ((new_target & 0x800) != 0)
|
||||
new_target += 0x1000;
|
||||
|
||||
SLJIT_UPDATE_WX_FLAGS(inst, inst + 5, 0);
|
||||
SLJIT_UPDATE_WX_FLAGS(inst, inst + 4, 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);
|
||||
inst[0] = (sljit_u16)((inst[0] & 0xfff) | (new_target & 0xf000));
|
||||
inst[1] = (sljit_u16)(new_target >> 16);
|
||||
SLJIT_ASSERT((inst[2] & 0x707f) == ADDI || (inst[2] & 0x707f) == JALR);
|
||||
inst[3] = (sljit_u16)((inst[3] & 0xf) | (new_target << 4));
|
||||
|
||||
SLJIT_UPDATE_WX_FLAGS(inst, inst + 5, 1);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 5);
|
||||
SLJIT_UPDATE_WX_FLAGS(inst, inst + 4, 1);
|
||||
inst = (sljit_u16 *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 4);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,29 +24,88 @@
|
|||
* 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)
|
||||
static sljit_s32 load_immediate32(struct sljit_compiler *compiler, sljit_s32 dst_r, sljit_sw imm)
|
||||
{
|
||||
sljit_sw high;
|
||||
SLJIT_ASSERT((imm <= 0x7fffffffl && imm > SIMM_MAX) || (imm >= S32_MIN && imm < SIMM_MIN));
|
||||
|
||||
if (imm <= SIMM_MAX && imm >= SIMM_MIN)
|
||||
return push_inst(compiler, ADDI | RD(dst_r) | RS1(TMP_ZERO) | IMM_I(imm));
|
||||
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 <= 0x7fffffffl && imm >= S32_MIN) {
|
||||
if (imm > S32_MAX) {
|
||||
if (RISCV_HAS_COMPRESSED(200) && imm <= 0x1ffff && imm >= -0x20000) {
|
||||
if (imm > 0x1f7ff) {
|
||||
SLJIT_ASSERT((imm & 0x800) != 0);
|
||||
FAIL_IF(push_inst(compiler, LUI | RD(dst_r) | (sljit_ins)0x80000000u));
|
||||
FAIL_IF(push_inst16(compiler, C_LUI | C_RD(dst_r) | (sljit_u16)0x1000));
|
||||
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)));
|
||||
FAIL_IF(push_inst16(compiler, C_LUI | C_RD(dst_r) | ((sljit_u16)(((imm) & 0x1f000) >> 10) | ((imm) & 0x20000) >> 5)));
|
||||
} else {
|
||||
if ((imm & 0x800) != 0)
|
||||
imm += 0x1000;
|
||||
|
||||
if ((imm & 0xfff) == 0)
|
||||
return SLJIT_SUCCESS;
|
||||
FAIL_IF(push_inst(compiler, LUI | RD(dst_r) | (sljit_ins)(imm & ~(sljit_sw)0xfff)));
|
||||
}
|
||||
|
||||
return push_inst(compiler, ADDI | RD(dst_r) | RS1(dst_r) | IMM_I(imm));
|
||||
imm &= 0xfff;
|
||||
|
||||
if (imm == 0)
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
if (RISCV_HAS_COMPRESSED(200) && (imm <= 0x1f || imm >= 0xfe0))
|
||||
return push_inst16(compiler, C_ADDI | C_RD(dst_r) | C_IMM_I(imm));
|
||||
|
||||
return push_inst(compiler, ADDI | RD(dst_r) | RS1(dst_r) | IMM_I(imm));
|
||||
}
|
||||
|
||||
static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_r, sljit_sw imm, sljit_s32 tmp_r)
|
||||
{
|
||||
sljit_sw high, shift;
|
||||
|
||||
if (RISCV_HAS_COMPRESSED(200) && imm <= SIMM16_MAX && imm >= SIMM16_MIN)
|
||||
return push_inst16(compiler, C_LI | C_RD(dst_r) | C_IMM_I(imm));
|
||||
|
||||
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)
|
||||
return load_immediate32(compiler, dst_r, imm);
|
||||
|
||||
/* Shifted small immediates. */
|
||||
|
||||
high = imm;
|
||||
shift = 0;
|
||||
while ((high & 0xff) == 0) {
|
||||
high >>= 8;
|
||||
shift += 8;
|
||||
}
|
||||
|
||||
if ((high & 0xf) == 0) {
|
||||
high >>= 4;
|
||||
shift += 4;
|
||||
}
|
||||
|
||||
if ((high & 0x3) == 0) {
|
||||
high >>= 2;
|
||||
shift += 2;
|
||||
}
|
||||
|
||||
if ((high & 0x1) == 0) {
|
||||
high >>= 1;
|
||||
shift += 1;
|
||||
}
|
||||
|
||||
if (high <= 0x7fffffffl && high >= S32_MIN) {
|
||||
load_immediate(compiler, dst_r, high, tmp_r);
|
||||
|
||||
if (RISCV_HAS_COMPRESSED(200))
|
||||
return push_inst16(compiler, C_SLLI | C_RD(dst_r) | C_IMM_I(shift));
|
||||
return push_inst(compiler, SLLI | RD(dst_r) | RS1(dst_r) | IMM_I(shift));
|
||||
}
|
||||
|
||||
/* Trailing zeroes could be used to produce shifted immediates. */
|
||||
|
|
@ -57,26 +116,15 @@ static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_r
|
|||
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(load_immediate32(compiler, dst_r, high));
|
||||
|
||||
FAIL_IF(push_inst(compiler, LUI | RD(dst_r) | (sljit_ins)(high & ~0xfff)));
|
||||
if (RISCV_HAS_COMPRESSED(200))
|
||||
FAIL_IF(push_inst16(compiler, C_SLLI | C_RD(dst_r) | (sljit_u16)(12 << 2)));
|
||||
else
|
||||
FAIL_IF(push_inst(compiler, SLLI | RD(dst_r) | RS1(dst_r) | IMM_I(12)));
|
||||
|
||||
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;
|
||||
SLJIT_ASSERT((imm & 0xfff) != 0);
|
||||
return push_inst(compiler, XORI | RD(dst_r) | RS1(dst_r) | IMM_I(imm));
|
||||
}
|
||||
|
||||
SLJIT_ASSERT(dst_r != tmp_r);
|
||||
|
|
@ -99,7 +147,10 @@ static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_r
|
|||
}
|
||||
|
||||
if (imm <= SIMM_MAX && imm >= SIMM_MIN) {
|
||||
FAIL_IF(push_inst(compiler, ADDI | RD(dst_r) | RS1(TMP_ZERO) | IMM_I(imm)));
|
||||
if (RISCV_HAS_COMPRESSED(200) && imm <= 0x1f && imm >= -0x20)
|
||||
FAIL_IF(push_inst16(compiler, C_LI | C_RD(dst_r) | C_IMM_I(imm)));
|
||||
else
|
||||
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);
|
||||
|
|
@ -110,19 +161,35 @@ static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_r
|
|||
if ((imm & 0x800) != 0)
|
||||
imm += 0x1000;
|
||||
|
||||
FAIL_IF(push_inst(compiler, LUI | RD(dst_r) | (sljit_ins)(imm & ~0xfff)));
|
||||
if (RISCV_HAS_COMPRESSED(200) && imm <= 0x1ffff && imm >= -0x20000)
|
||||
FAIL_IF(push_inst16(compiler, C_LUI | C_RD(dst_r) | ((sljit_u16)(((imm) & 0x1f000) >> 10) | ((imm) & 0x20000) >> 5)));
|
||||
else
|
||||
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 ((high & 0xfff) != 0) {
|
||||
SLJIT_ASSERT(high <= 0xfff);
|
||||
if (RISCV_HAS_COMPRESSED(200) && (high <= 0x1f || high >= 0xfe0))
|
||||
FAIL_IF(push_inst16(compiler, C_ADDI | C_RD(tmp_r) | C_IMM_I(high)));
|
||||
else
|
||||
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)));
|
||||
else if (imm != 0) {
|
||||
SLJIT_ASSERT(imm <= 0xfff);
|
||||
if (RISCV_HAS_COMPRESSED(200) && (imm <= 0x1f || imm >= 0xfe0))
|
||||
FAIL_IF(push_inst16(compiler, C_ADDI | C_RD(dst_r) | C_IMM_I(imm)));
|
||||
else
|
||||
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)));
|
||||
if (RISCV_HAS_COMPRESSED(200))
|
||||
FAIL_IF(push_inst16(compiler, C_SLLI | C_RD(tmp_r) | (sljit_u16)((high & 0x1000) ? (20 << 2) : (1 << 12))));
|
||||
else
|
||||
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));
|
||||
}
|
||||
|
||||
|
|
@ -190,7 +257,7 @@ static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_
|
|||
|
||||
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_u16 *inst = (sljit_u16*)addr;
|
||||
sljit_sw high;
|
||||
SLJIT_UNUSED_ARG(executable_offset);
|
||||
|
||||
|
|
@ -205,18 +272,20 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_ta
|
|||
if ((high & 0x800) != 0)
|
||||
high += 0x1000;
|
||||
|
||||
SLJIT_UPDATE_WX_FLAGS(inst, inst + 5, 0);
|
||||
SLJIT_UPDATE_WX_FLAGS(inst, inst + 12, 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[0] = (sljit_u16)((inst[0] & 0xfff) | (high & 0xf000));
|
||||
inst[1] = (sljit_u16)(high >> 16);
|
||||
SLJIT_ASSERT((inst[2] & 0x707f) == ADDI);
|
||||
inst[3] = (sljit_u16)((inst[3] & 0xf) | (high << 4));
|
||||
SLJIT_ASSERT((inst[4] & 0x7f) == LUI);
|
||||
inst[4] = (sljit_u16)((inst[4] & 0xfff) | (new_target & 0xf000));
|
||||
inst[5] = (sljit_u16)(new_target >> 16);
|
||||
SLJIT_ASSERT((inst[10] & 0x707f) == ADDI || (inst[10] & 0x707f) == JALR);
|
||||
inst[11] = (sljit_u16)((inst[11] & 0xf) | (new_target << 4));
|
||||
SLJIT_UPDATE_WX_FLAGS(inst, inst + 12, 1);
|
||||
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 5);
|
||||
inst = (sljit_u16 *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 12);
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -93,9 +93,6 @@ static const sljit_gpr r15 = 15; /* reg_map[SLJIT_NUMBER_OF_REGISTERS + 1]: stac
|
|||
#define tmp0 r0
|
||||
#define tmp1 r1
|
||||
|
||||
/* 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 */
|
||||
|
||||
|
|
@ -125,11 +122,6 @@ static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 2] = {
|
|||
#define F32(r) (R32A((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)
|
||||
{
|
||||
|
|
@ -169,14 +161,14 @@ static SLJIT_INLINE sljit_u8 get_cc(struct sljit_compiler *compiler, sljit_s32 t
|
|||
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)
|
||||
sljit_s32 flag_type = GET_FLAG_TYPE(compiler->status_flags_state);
|
||||
if (flag_type >= SLJIT_SIG_LESS && flag_type <= SLJIT_SIG_LESS_EQUAL)
|
||||
return cc0;
|
||||
if (type == SLJIT_OVERFLOW)
|
||||
if (flag_type == SLJIT_OVERFLOW)
|
||||
return (cc0 | cc3);
|
||||
return (cc0 | cc2);
|
||||
}
|
||||
/* fallthrough */
|
||||
SLJIT_FALLTHROUGH
|
||||
|
||||
case SLJIT_ATOMIC_STORED:
|
||||
case SLJIT_F_EQUAL:
|
||||
|
|
@ -185,14 +177,14 @@ static SLJIT_INLINE sljit_u8 get_cc(struct sljit_compiler *compiler, sljit_s32 t
|
|||
|
||||
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)
|
||||
sljit_s32 flag_type = GET_FLAG_TYPE(compiler->status_flags_state);
|
||||
if (flag_type >= SLJIT_SIG_LESS && flag_type <= SLJIT_SIG_LESS_EQUAL)
|
||||
return (cc1 | cc2 | cc3);
|
||||
if (type == SLJIT_OVERFLOW)
|
||||
if (flag_type == SLJIT_OVERFLOW)
|
||||
return (cc1 | cc2);
|
||||
return (cc1 | cc3);
|
||||
}
|
||||
/* fallthrough */
|
||||
SLJIT_FALLTHROUGH
|
||||
|
||||
case SLJIT_UNORDERED_OR_NOT_EQUAL:
|
||||
return (cc1 | cc2 | cc3);
|
||||
|
|
@ -223,7 +215,7 @@ static SLJIT_INLINE sljit_u8 get_cc(struct sljit_compiler *compiler, sljit_s32 t
|
|||
case SLJIT_NOT_CARRY:
|
||||
if (compiler->status_flags_state & SLJIT_CURRENT_FLAGS_SUB)
|
||||
return (cc2 | cc3);
|
||||
/* fallthrough */
|
||||
SLJIT_FALLTHROUGH
|
||||
|
||||
case SLJIT_SIG_LESS_EQUAL:
|
||||
case SLJIT_F_LESS_EQUAL:
|
||||
|
|
@ -233,7 +225,7 @@ static SLJIT_INLINE sljit_u8 get_cc(struct sljit_compiler *compiler, sljit_s32 t
|
|||
case SLJIT_CARRY:
|
||||
if (compiler->status_flags_state & SLJIT_CURRENT_FLAGS_SUB)
|
||||
return (cc0 | cc1);
|
||||
/* fallthrough */
|
||||
SLJIT_FALLTHROUGH
|
||||
|
||||
case SLJIT_SIG_GREATER:
|
||||
case SLJIT_UNORDERED_OR_GREATER:
|
||||
|
|
@ -246,7 +238,7 @@ static SLJIT_INLINE sljit_u8 get_cc(struct sljit_compiler *compiler, sljit_s32 t
|
|||
case SLJIT_OVERFLOW:
|
||||
if (compiler->status_flags_state & SLJIT_SET_Z)
|
||||
return (cc2 | cc3);
|
||||
/* fallthrough */
|
||||
SLJIT_FALLTHROUGH
|
||||
|
||||
case SLJIT_UNORDERED:
|
||||
return cc3;
|
||||
|
|
@ -254,7 +246,7 @@ static SLJIT_INLINE sljit_u8 get_cc(struct sljit_compiler *compiler, sljit_s32 t
|
|||
case SLJIT_NOT_OVERFLOW:
|
||||
if (compiler->status_flags_state & SLJIT_SET_Z)
|
||||
return (cc0 | cc1);
|
||||
/* fallthrough */
|
||||
SLJIT_FALLTHROUGH
|
||||
|
||||
case SLJIT_ORDERED:
|
||||
return (cc0 | cc1 | cc2);
|
||||
|
|
@ -333,7 +325,7 @@ static SLJIT_INLINE int have_facility_static(facility_bit x)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static SLJIT_INLINE unsigned long get_hwcap()
|
||||
static SLJIT_INLINE unsigned long get_hwcap(void)
|
||||
{
|
||||
static unsigned long hwcap = 0;
|
||||
if (SLJIT_UNLIKELY(!hwcap)) {
|
||||
|
|
@ -343,7 +335,7 @@ static SLJIT_INLINE unsigned long get_hwcap()
|
|||
return hwcap;
|
||||
}
|
||||
|
||||
static SLJIT_INLINE int have_stfle()
|
||||
static SLJIT_INLINE int have_stfle(void)
|
||||
{
|
||||
if (have_facility_static(STORE_FACILITY_LIST_EXTENDED_FACILITY))
|
||||
return 1;
|
||||
|
|
@ -410,10 +402,10 @@ HAVE_FACILITY(have_misc2, MISCELLANEOUS_INSTRUCTION_EXTENSIONS_2_FACILITY)
|
|||
#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_s8(d) ((sljit_sw)(d) == (sljit_s8)(d))
|
||||
#define is_s16(d) ((sljit_sw)(d) == (sljit_s16)(d))
|
||||
#define is_s20(d) CHECK_SIGNED((d), 20)
|
||||
#define is_s32(d) ((d) == (sljit_s32)(d))
|
||||
#define is_s32(d) ((sljit_sw)(d) == (sljit_s32)(d))
|
||||
|
||||
static SLJIT_INLINE sljit_ins disp_s20(sljit_s32 d)
|
||||
{
|
||||
|
|
@ -983,6 +975,12 @@ static const sljit_ins store_forms[3] = {
|
|||
0xe30000000024 /* stg */
|
||||
};
|
||||
|
||||
static const sljit_ins store_byte_forms[3] = {
|
||||
0x42000000 /* stc */,
|
||||
0xe30000000072 /* stcy */,
|
||||
0
|
||||
};
|
||||
|
||||
static const sljit_ins load_halfword_forms[3] = {
|
||||
0x48000000 /* lh */,
|
||||
0xe30000000078 /* lhy */,
|
||||
|
|
@ -1021,6 +1019,13 @@ static SLJIT_INLINE sljit_s32 store_word(struct sljit_compiler *compiler, sljit_
|
|||
return load_store_op(compiler, src_r, dst, dstw, is_32bit, store_forms);
|
||||
}
|
||||
|
||||
/* May clobber tmp1. */
|
||||
static SLJIT_INLINE sljit_s32 store_byte(struct sljit_compiler *compiler, sljit_gpr src_r,
|
||||
sljit_s32 dst, sljit_sw dstw)
|
||||
{
|
||||
return load_store_op(compiler, src_r, dst, dstw, 1, store_byte_forms);
|
||||
}
|
||||
|
||||
#undef WHEN
|
||||
|
||||
static sljit_s32 emit_move(struct sljit_compiler *compiler,
|
||||
|
|
@ -1029,7 +1034,7 @@ static sljit_s32 emit_move(struct sljit_compiler *compiler,
|
|||
{
|
||||
sljit_gpr src_r;
|
||||
|
||||
SLJIT_ASSERT(!IS_GPR_REG(src) || dst_r != gpr(src & REG_MASK));
|
||||
SLJIT_ASSERT(!FAST_IS_REG(src) || dst_r != gpr(src & REG_MASK));
|
||||
|
||||
if (src == SLJIT_IMM)
|
||||
return push_load_imm_inst(compiler, dst_r, srcw);
|
||||
|
|
@ -1392,6 +1397,12 @@ static sljit_s32 emit_non_commutative(struct sljit_compiler *compiler, const str
|
|||
return emit_rrf(compiler, ins, dst, src1, src1w, src2, src2w);
|
||||
}
|
||||
|
||||
static SLJIT_INLINE sljit_u16 *process_extended_label(sljit_u16 *code_ptr, struct sljit_extended_label *ext_label)
|
||||
{
|
||||
SLJIT_ASSERT(ext_label->label.u.index == SLJIT_LABEL_ALIGNED);
|
||||
return (sljit_u16*)((sljit_uw)code_ptr & ~(ext_label->data));
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler, sljit_s32 options, void *exec_allocator_data)
|
||||
{
|
||||
struct sljit_label *label;
|
||||
|
|
@ -1413,30 +1424,28 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
|||
sljit_sw source, offset;
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_PTR(check_sljit_generate_code(compiler));
|
||||
CHECK_PTR(check_sljit_generate_code(compiler, options));
|
||||
reverse_buf(compiler);
|
||||
|
||||
jump = compiler->jumps;
|
||||
while (jump != NULL) {
|
||||
if (jump->flags & (SLJIT_REWRITABLE_JUMP | JUMP_ADDR | JUMP_MOV_ADDR)) {
|
||||
if (jump->flags & (SLJIT_REWRITABLE_JUMP | JUMP_ADDR)) {
|
||||
/* encoded: */
|
||||
/* brasl %r14, <rel_addr> (or brcl <mask>, <rel_addr>) */
|
||||
/* replace with: */
|
||||
/* lgrl %r1, <pool_addr> */
|
||||
/* bras %r14, %r1 (or bcr <mask>, %r1) */
|
||||
pool_size += sizeof(*pool);
|
||||
if (((jump->flags & SLJIT_REWRITABLE_JUMP) || !is_s32(jump->u.target)))
|
||||
pool_size += sizeof(sljit_uw);
|
||||
else
|
||||
jump->flags |= PATCH_IMM32;
|
||||
|
||||
if (!(jump->flags & JUMP_MOV_ADDR))
|
||||
ins_size += 2;
|
||||
}
|
||||
jump = jump->next;
|
||||
}
|
||||
|
||||
const_ = compiler->consts;
|
||||
while (const_) {
|
||||
pool_size += sizeof(*pool);
|
||||
const_ = const_->next;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
|
@ -1475,80 +1484,91 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
|||
SLJIT_ASSERT(!const_ || const_->addr >= half_count);
|
||||
|
||||
if (next_min_addr == next_label_size) {
|
||||
if (label->u.index >= SLJIT_LABEL_ALIGNED)
|
||||
code_ptr = process_extended_label(code_ptr, (struct sljit_extended_label*)label);
|
||||
|
||||
label->u.addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
|
||||
label = label->next;
|
||||
next_label_size = SLJIT_GET_NEXT_SIZE(label);
|
||||
}
|
||||
|
||||
if (next_min_addr == next_jump_addr) {
|
||||
jump->addr = (sljit_uw)code_ptr;
|
||||
|
||||
if (SLJIT_UNLIKELY(jump->flags & JUMP_MOV_ADDR)) {
|
||||
source = (sljit_sw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
|
||||
if (jump->flags & PATCH_IMM32) {
|
||||
SLJIT_ASSERT((jump->flags & JUMP_ADDR) && is_s32(jump->u.target));
|
||||
ins = 0xc00100000000 /* lgfi */ | (ins & 0xf000000000);
|
||||
} else if (jump->flags & JUMP_ADDR) {
|
||||
source = (sljit_sw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
|
||||
offset = (sljit_sw)(jump->u.target - (sljit_uw)source);
|
||||
|
||||
jump->addr = (sljit_uw)pool_ptr;
|
||||
if ((offset & 0x1) != 0 || offset > 0xffffffffl || offset < -0x100000000l) {
|
||||
jump->addr = (sljit_uw)pool_ptr;
|
||||
jump->flags |= PATCH_POOL;
|
||||
|
||||
/* store target into pool */
|
||||
offset = (sljit_sw)SLJIT_ADD_EXEC_OFFSET(pool_ptr, executable_offset) - source;
|
||||
pool_ptr++;
|
||||
/* store target into pool */
|
||||
offset = (sljit_sw)SLJIT_ADD_EXEC_OFFSET(pool_ptr, executable_offset) - source;
|
||||
pool_ptr++;
|
||||
|
||||
SLJIT_ASSERT(!(offset & 1));
|
||||
offset >>= 1;
|
||||
SLJIT_ASSERT(is_s32(offset));
|
||||
ins |= (sljit_ins)offset & 0xffffffff;
|
||||
SLJIT_ASSERT(!(offset & 1));
|
||||
offset >>= 1;
|
||||
SLJIT_ASSERT(is_s32(offset));
|
||||
ins = 0xc40800000000 /* lgrl */ | (ins & 0xf000000000) | (sljit_ins)(offset & 0xffffffff);
|
||||
}
|
||||
}
|
||||
} else if (jump->flags & (SLJIT_REWRITABLE_JUMP | JUMP_ADDR)) {
|
||||
sljit_ins arg;
|
||||
|
||||
jump->addr = (sljit_uw)pool_ptr;
|
||||
|
||||
/* load address into tmp1 */
|
||||
source = (sljit_sw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
|
||||
offset = (sljit_sw)SLJIT_ADD_EXEC_OFFSET(pool_ptr, executable_offset) - source;
|
||||
|
||||
SLJIT_ASSERT(!(offset & 1));
|
||||
offset >>= 1;
|
||||
SLJIT_ASSERT(is_s32(offset));
|
||||
if (jump->flags & PATCH_IMM32) {
|
||||
SLJIT_ASSERT((jump->flags & JUMP_ADDR) && is_s32(jump->u.target));
|
||||
code_ptr[0] = (sljit_u16)(0xc001 /* lgfi */ | R4A(tmp1));
|
||||
code_ptr += 3;
|
||||
} else if (!(jump->flags & SLJIT_REWRITABLE_JUMP)) {
|
||||
offset = (sljit_sw)(jump->u.target - (sljit_uw)source);
|
||||
|
||||
code_ptr[0] = (sljit_u16)(0xc408 | R4A(tmp1) /* lgrl */);
|
||||
code_ptr[1] = (sljit_u16)(offset >> 16);
|
||||
code_ptr[2] = (sljit_u16)offset;
|
||||
code_ptr += 3;
|
||||
pool_ptr++;
|
||||
if ((offset & 0x1) != 0 || offset > 0xffffffffl || offset < -0x100000000l)
|
||||
jump->flags |= PATCH_POOL;
|
||||
} else
|
||||
jump->flags |= PATCH_POOL;
|
||||
|
||||
/* branch to tmp1 */
|
||||
arg = (ins >> 36) & 0xf;
|
||||
if (((ins >> 32) & 0xf) == 4) {
|
||||
/* brcl -> bcr */
|
||||
ins = bcr(arg, tmp1);
|
||||
} else {
|
||||
SLJIT_ASSERT(((ins >> 32) & 0xf) == 5);
|
||||
/* brasl -> basr */
|
||||
ins = basr(arg, tmp1);
|
||||
if (jump->flags & PATCH_POOL) {
|
||||
jump->addr = (sljit_uw)pool_ptr;
|
||||
|
||||
/* load address into tmp1 */
|
||||
offset = (sljit_sw)SLJIT_ADD_EXEC_OFFSET(pool_ptr, executable_offset) - source;
|
||||
|
||||
SLJIT_ASSERT(!(offset & 1));
|
||||
offset >>= 1;
|
||||
SLJIT_ASSERT(is_s32(offset));
|
||||
|
||||
code_ptr[0] = (sljit_u16)(0xc408 /* lgrl */ | R4A(tmp1));
|
||||
code_ptr[1] = (sljit_u16)(offset >> 16);
|
||||
code_ptr[2] = (sljit_u16)offset;
|
||||
code_ptr += 3;
|
||||
pool_ptr++;
|
||||
}
|
||||
|
||||
/* Adjust half_count. */
|
||||
half_count += 2;
|
||||
} else
|
||||
jump->addr = (sljit_uw)code_ptr;
|
||||
if (jump->flags & (PATCH_POOL | PATCH_IMM32)) {
|
||||
/* branch to tmp1 */
|
||||
if (((ins >> 32) & 0xf) == 4) {
|
||||
/* brcl -> bcr */
|
||||
ins = 0x0700 /* bcr */ | ((ins >> 32) & 0xf0) | R0A(tmp1);
|
||||
} else {
|
||||
SLJIT_ASSERT(((ins >> 32) & 0xf) == 5);
|
||||
/* brasl -> basr */
|
||||
ins = 0x0d00 /* basr */ | ((ins >> 32) & 0xf0) | R0A(tmp1);
|
||||
}
|
||||
|
||||
/* Adjust half_count. */
|
||||
half_count += 2;
|
||||
}
|
||||
}
|
||||
|
||||
jump = jump->next;
|
||||
next_jump_addr = SLJIT_GET_NEXT_ADDRESS(jump);
|
||||
} else if (next_min_addr == next_const_addr) {
|
||||
/* update instruction with relative address of constant */
|
||||
source = (sljit_sw)code_ptr;
|
||||
offset = (sljit_sw)pool_ptr - source;
|
||||
|
||||
SLJIT_ASSERT(!(offset & 0x1));
|
||||
offset >>= 1; /* halfword (not byte) offset */
|
||||
SLJIT_ASSERT(is_s32(offset));
|
||||
|
||||
ins |= (sljit_ins)offset & 0xffffffff;
|
||||
|
||||
/* update address */
|
||||
const_->addr = (sljit_uw)pool_ptr;
|
||||
|
||||
/* store initial value into pool and update pool address */
|
||||
*(pool_ptr++) = (sljit_uw)(((struct sljit_s390x_const*)const_)->init_value);
|
||||
|
||||
/* move to next constant */
|
||||
} else if (next_min_addr == next_const_addr) {
|
||||
const_->addr = (sljit_uw)code_ptr;
|
||||
const_ = const_->next;
|
||||
next_const_addr = SLJIT_GET_NEXT_ADDRESS(const_);
|
||||
}
|
||||
|
|
@ -1574,6 +1594,9 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
|||
} while (buf);
|
||||
|
||||
if (next_label_size == half_count) {
|
||||
if (label->u.index >= SLJIT_LABEL_ALIGNED)
|
||||
code_ptr = process_extended_label(code_ptr, (struct sljit_extended_label*)label);
|
||||
|
||||
label->u.addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
|
||||
label = label->next;
|
||||
}
|
||||
|
|
@ -1581,25 +1604,30 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
|||
SLJIT_ASSERT(!label);
|
||||
SLJIT_ASSERT(!jump);
|
||||
SLJIT_ASSERT(!const_);
|
||||
SLJIT_ASSERT(code + (ins_size >> 1) == code_ptr);
|
||||
SLJIT_ASSERT((sljit_u8 *)pool + pool_size == (sljit_u8 *)pool_ptr);
|
||||
SLJIT_ASSERT(code_ptr <= code + (ins_size >> 1));
|
||||
SLJIT_ASSERT((sljit_u8 *)pool_ptr <= (sljit_u8 *)pool + pool_size);
|
||||
|
||||
jump = compiler->jumps;
|
||||
while (jump != NULL) {
|
||||
offset = (sljit_sw)((jump->flags & JUMP_ADDR) ? jump->u.target : jump->u.label->u.addr);
|
||||
|
||||
if (jump->flags & (SLJIT_REWRITABLE_JUMP | JUMP_ADDR | JUMP_MOV_ADDR)) {
|
||||
/* Store jump target into pool. */
|
||||
*(sljit_uw*)(jump->addr) = (sljit_uw)offset;
|
||||
} else {
|
||||
if (!(jump->flags & (PATCH_POOL | PATCH_IMM32))) {
|
||||
code_ptr = (sljit_u16*)jump->addr;
|
||||
offset -= (sljit_sw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
|
||||
|
||||
/* offset must be halfword aligned */
|
||||
/* Offset must be halfword aligned. */
|
||||
SLJIT_ASSERT(!(offset & 1));
|
||||
offset >>= 1;
|
||||
SLJIT_ASSERT(is_s32(offset)); /* TODO(mundaym): handle arbitrary offsets */
|
||||
|
||||
code_ptr[1] = (sljit_u16)(offset >> 16);
|
||||
code_ptr[2] = (sljit_u16)offset;
|
||||
} else if (jump->flags & PATCH_POOL) {
|
||||
/* Store jump target into pool. */
|
||||
*(sljit_uw*)(jump->addr) = (sljit_uw)offset;
|
||||
} else {
|
||||
SLJIT_ASSERT(is_s32(offset));
|
||||
code_ptr = (sljit_u16*)jump->addr;
|
||||
code_ptr[1] = (sljit_u16)(offset >> 16);
|
||||
code_ptr[2] = (sljit_u16)offset;
|
||||
}
|
||||
|
|
@ -2243,7 +2271,6 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
|
|||
}
|
||||
/* STORE and STORE IMMEDIATE */
|
||||
if ((dst & SLJIT_MEM) && (FAST_IS_REG(src) || src == SLJIT_IMM)) {
|
||||
struct addr mem;
|
||||
sljit_gpr reg = FAST_IS_REG(src) ? gpr(src) : tmp0;
|
||||
|
||||
if (src == SLJIT_IMM) {
|
||||
|
|
@ -2276,7 +2303,6 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
|
|||
#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:
|
||||
|
|
@ -2335,7 +2361,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
|
|||
case SLJIT_REV_U32:
|
||||
case SLJIT_REV_S32:
|
||||
op |= SLJIT_32;
|
||||
/* fallthrough */
|
||||
SLJIT_FALLTHROUGH
|
||||
case SLJIT_REV:
|
||||
case SLJIT_REV_U16:
|
||||
case SLJIT_REV_S16:
|
||||
|
|
@ -2648,7 +2674,7 @@ static sljit_s32 sljit_emit_bitwise_imm(struct sljit_compiler *compiler, sljit_s
|
|||
sljit_gpr dst_r = tmp0;
|
||||
sljit_s32 needs_move = 1;
|
||||
|
||||
if (IS_GPR_REG(dst)) {
|
||||
if (FAST_IS_REG(dst)) {
|
||||
dst_r = gpr(dst & REG_MASK);
|
||||
if (dst == src1)
|
||||
needs_move = 0;
|
||||
|
|
@ -3119,6 +3145,75 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *
|
|||
return push_inst(compiler, 0xb9810000 /* ogr */ | R4A(dst_r) | R0A(tmp0));
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2_shift(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_sw shift_arg)
|
||||
{
|
||||
sljit_gpr dst_r, tmp_r, src_r;
|
||||
struct addr addr;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_op2_shift(compiler, op, dst, dstw, src1, src1w, src2, src2w, shift_arg));
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
ADJUST_LOCAL_OFFSET(src1, src1w);
|
||||
ADJUST_LOCAL_OFFSET(src2, src2w);
|
||||
|
||||
shift_arg &= 0x3f;
|
||||
|
||||
if (src2 == SLJIT_IMM) {
|
||||
src2w = src2w << shift_arg;
|
||||
shift_arg = 0;
|
||||
}
|
||||
|
||||
if (shift_arg == 0) {
|
||||
SLJIT_SKIP_CHECKS(compiler);
|
||||
return sljit_emit_op2(compiler, GET_OPCODE(op), dst, dstw, src1, src1w, src2, src2w);
|
||||
}
|
||||
|
||||
tmp_r = FAST_IS_REG(dst) && (dst != src1) ? gpr(dst) : tmp0;
|
||||
|
||||
if (src2 & SLJIT_MEM) {
|
||||
FAIL_IF(load_word(compiler, tmp_r, src2, src2w, 0 /* 64-bit */));
|
||||
src_r = tmp_r;
|
||||
} else {
|
||||
src_r = gpr(src2);
|
||||
}
|
||||
|
||||
FAIL_IF(push_inst(compiler, 0xeb000000000d /* sllg */ | R36A(tmp_r) | R32A(src_r) | ((sljit_ins)shift_arg << 16)));
|
||||
|
||||
if (src1 & SLJIT_MEM) {
|
||||
FAIL_IF(make_addr_bxy(compiler, &addr, src1, src1w, tmp1));
|
||||
FAIL_IF(push_inst(compiler, 0xe30000000008 /* ag */ | R36A(tmp_r) | R32A(addr.index) | R28A(addr.base) | disp_s20(addr.offset)));
|
||||
src_r = tmp_r;
|
||||
} else if (src1 == SLJIT_IMM) {
|
||||
if (is_s32(src1w)) {
|
||||
FAIL_IF(push_inst(compiler, 0xc20800000000 /* agfi */ | R36A(tmp_r) | (sljit_u32)src1w));
|
||||
src_r = tmp_r;
|
||||
} else {
|
||||
src_r = tmp_r != tmp0 ? tmp0 : tmp1;
|
||||
FAIL_IF(push_load_imm_inst(compiler, src_r, src1w));
|
||||
}
|
||||
} else {
|
||||
src_r = gpr(src1);
|
||||
}
|
||||
|
||||
dst_r = (FAST_IS_REG(dst) ? gpr(dst) : tmp0);
|
||||
|
||||
if (src_r != tmp_r) {
|
||||
if (src_r == dst_r) {
|
||||
FAIL_IF(push_inst(compiler, 0xb9080000 /* agr */ | R4A(dst_r) | R0A(tmp_r)));
|
||||
} else {
|
||||
FAIL_IF(push_inst(compiler, 0xb9e80000 /* agrk */ | R12A(tmp_r) | R4A(dst_r) | R0A(src_r)));
|
||||
}
|
||||
}
|
||||
|
||||
if (dst & SLJIT_MEM)
|
||||
return store_word(compiler, dst_r, dst, dstw, 0 /* 64-bit */);
|
||||
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)
|
||||
{
|
||||
|
|
@ -3131,11 +3226,14 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *comp
|
|||
|
||||
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));
|
||||
if (FAST_IS_REG(src)) {
|
||||
src_r = gpr(src);
|
||||
if (src_r != link_r)
|
||||
FAIL_IF(push_inst(compiler, lgr(link_r, src_r)));
|
||||
} else
|
||||
FAIL_IF(load_word(compiler, link_r, src, srcw, 0));
|
||||
|
||||
return push_inst(compiler, br(src_r));
|
||||
return push_inst(compiler, br(link_r));
|
||||
case SLJIT_SKIP_FRAMES_BEFORE_FAST_RETURN:
|
||||
return SLJIT_SUCCESS;
|
||||
case SLJIT_PREFETCH_L1:
|
||||
|
|
@ -3163,8 +3261,13 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_dst(struct sljit_compiler *comp
|
|||
|
||||
switch (op) {
|
||||
case SLJIT_FAST_ENTER:
|
||||
if (FAST_IS_REG(dst))
|
||||
return push_inst(compiler, lgr(gpr(dst), link_r));
|
||||
if (FAST_IS_REG(dst)) {
|
||||
dst_r = gpr(dst);
|
||||
|
||||
if (dst_r == link_r)
|
||||
return SLJIT_SUCCESS;
|
||||
return push_inst(compiler, lgr(dst_r, link_r));
|
||||
}
|
||||
break;
|
||||
case SLJIT_GET_RETURN_ADDRESS:
|
||||
dst_r = FAST_IS_REG(dst) ? gpr(dst) : tmp0;
|
||||
|
|
@ -3591,6 +3694,60 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compi
|
|||
return label;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_aligned_label(struct sljit_compiler *compiler,
|
||||
sljit_s32 alignment, struct sljit_read_only_buffer *buffers)
|
||||
{
|
||||
sljit_uw mask, i;
|
||||
struct sljit_label *label;
|
||||
struct sljit_label *next_label;
|
||||
struct sljit_extended_label *ext_label;
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_PTR(check_sljit_emit_aligned_label(compiler, alignment, buffers));
|
||||
|
||||
sljit_reset_read_only_buffers(buffers);
|
||||
|
||||
if (alignment <= SLJIT_LABEL_ALIGN_2) {
|
||||
SLJIT_SKIP_CHECKS(compiler);
|
||||
label = sljit_emit_label(compiler);
|
||||
PTR_FAIL_IF(!label);
|
||||
} else {
|
||||
/* The used space is filled with NOPs. */
|
||||
mask = ((sljit_uw)1 << alignment) - sizeof(sljit_u16);
|
||||
|
||||
for (i = (mask >> 1); i != 0; i--)
|
||||
PTR_FAIL_IF(push_inst(compiler, 0x0700 /* 2-byte nop */));
|
||||
|
||||
ext_label = (struct sljit_extended_label*)ensure_abuf(compiler, sizeof(struct sljit_extended_label));
|
||||
PTR_FAIL_IF(!ext_label);
|
||||
set_extended_label(ext_label, compiler, SLJIT_LABEL_ALIGNED, mask);
|
||||
label = &ext_label->label;
|
||||
}
|
||||
|
||||
if (buffers == NULL)
|
||||
return label;
|
||||
|
||||
next_label = label;
|
||||
|
||||
while (1) {
|
||||
buffers->u.label = next_label;
|
||||
|
||||
for (i = (buffers->size + 1) >> 1; i > 0; i--)
|
||||
PTR_FAIL_IF(push_inst(compiler, 0x0700 /* 2-byte nop */));
|
||||
|
||||
buffers = buffers->next;
|
||||
|
||||
if (buffers == NULL)
|
||||
break;
|
||||
|
||||
SLJIT_SKIP_CHECKS(compiler);
|
||||
next_label = sljit_emit_label(compiler);
|
||||
PTR_FAIL_IF(!next_label);
|
||||
}
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type)
|
||||
{
|
||||
struct sljit_jump *jump;
|
||||
|
|
@ -3633,25 +3790,36 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_call(struct sljit_compile
|
|||
|
||||
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;
|
||||
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 */));
|
||||
if (src != SLJIT_IMM) {
|
||||
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));
|
||||
}
|
||||
|
||||
/* emit jump instruction */
|
||||
jump = (struct sljit_jump *)ensure_abuf(compiler, sizeof(struct sljit_jump));
|
||||
FAIL_IF(!jump);
|
||||
set_jump(jump, compiler, JUMP_ADDR);
|
||||
jump->addr = compiler->size;
|
||||
jump->u.target = (sljit_uw)srcw;
|
||||
|
||||
type &= 0xff;
|
||||
if (type >= SLJIT_FAST_CALL)
|
||||
return push_inst(compiler, basr(link_r, src_r));
|
||||
return push_inst(compiler, brasl(link_r, 0));
|
||||
|
||||
return push_inst(compiler, br(src_r));
|
||||
return push_inst(compiler, brcl(0xf, 0));
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compiler, sljit_s32 type,
|
||||
|
|
@ -3711,7 +3879,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co
|
|||
break;
|
||||
case SLJIT_MOV32:
|
||||
op |= SLJIT_32;
|
||||
/* fallthrough */
|
||||
SLJIT_FALLTHROUGH
|
||||
case SLJIT_MOV:
|
||||
/* can write straight into destination */
|
||||
loc_r = dst_r;
|
||||
|
|
@ -3766,6 +3934,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *comp
|
|||
sljit_ins mask;
|
||||
sljit_gpr src_r;
|
||||
sljit_gpr dst_r = gpr(dst_reg);
|
||||
sljit_s32 is_32bit = (type & SLJIT_32) != 0;
|
||||
sljit_ins ins;
|
||||
|
||||
CHECK_ERROR();
|
||||
|
|
@ -3773,6 +3942,43 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *comp
|
|||
|
||||
ADJUST_LOCAL_OFFSET(src1, src1w);
|
||||
|
||||
type &= ~SLJIT_32;
|
||||
if (src1 == SLJIT_IMM && is_32bit)
|
||||
src1w = (sljit_s32)src1w;
|
||||
|
||||
if (type & SLJIT_COMPARE_SELECT) {
|
||||
type ^= SLJIT_COMPARE_SELECT;
|
||||
compiler->status_flags_state = SLJIT_CURRENT_FLAGS_SUB | SLJIT_CURRENT_FLAGS_COMPARE;
|
||||
|
||||
if (src1 & SLJIT_MEM) {
|
||||
FAIL_IF(load_word(compiler, tmp0, src1, src1w, is_32bit));
|
||||
src1 = TMP_REG1;
|
||||
src1w = 0;
|
||||
} else if (src1 == SLJIT_IMM) {
|
||||
if (type >= SLJIT_LESS && type <= SLJIT_LESS_EQUAL && src1w >= 0 && src1w <= 0x7fff) {
|
||||
ins = is_32bit ? 0xc20f00000000 /* clfi */ : 0xc20e00000000 /* clgfi */;
|
||||
FAIL_IF(push_inst(compiler, ins | R36A(gpr(src2_reg)) | (sljit_ins)src1w));
|
||||
type ^= 0x1;
|
||||
} else if (type >= SLJIT_SIG_LESS && type <= SLJIT_SIG_LESS_EQUAL && is_s20(src1w)) {
|
||||
ins = is_32bit ? 0xc20d00000000 /* cfi */ : 0xc20c00000000 /* cgfi */;
|
||||
FAIL_IF(push_inst(compiler, ins | R36A(gpr(src2_reg)) | ((sljit_ins)src1w & 0xffffffff)));
|
||||
type ^= 0x1;
|
||||
} else {
|
||||
FAIL_IF(push_load_imm_inst(compiler, tmp0, src1w));
|
||||
src1 = TMP_REG1;
|
||||
src1w = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (FAST_IS_REG(src1)) {
|
||||
if (type >= SLJIT_LESS && type <= SLJIT_LESS_EQUAL)
|
||||
ins = is_32bit ? 0x1500 /* clr */ : 0xb9210000 /* clgr */;
|
||||
else
|
||||
ins = is_32bit ? 0x1900 /* cr */ : 0xb9200000 /* cgr */;
|
||||
FAIL_IF(push_inst(compiler, ins | R4A(gpr(src1)) | R0A(gpr(src2_reg))));
|
||||
}
|
||||
}
|
||||
|
||||
if (dst_reg != src2_reg) {
|
||||
if (src1 == dst_reg) {
|
||||
src1 = src2_reg;
|
||||
|
|
@ -3780,16 +3986,16 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *comp
|
|||
type ^= 0x1;
|
||||
} else {
|
||||
if (ADDRESSING_DEPENDS_ON(src1, dst_reg)) {
|
||||
FAIL_IF(load_word(compiler, dst_r, src1, src1w, type & SLJIT_32));
|
||||
FAIL_IF(load_word(compiler, dst_r, src1, src1w, is_32bit));
|
||||
src1 = src2_reg;
|
||||
src1w = 0;
|
||||
type ^= 0x1;
|
||||
} else
|
||||
FAIL_IF(push_inst(compiler, ((type & SLJIT_32) ? 0x1800 /* lr */ : 0xb9040000 /* lgr */) | R4A(dst_r) | R0A(gpr(src2_reg))));
|
||||
FAIL_IF(push_inst(compiler, (is_32bit ? 0x1800 /* lr */ : 0xb9040000 /* lgr */) | R4A(dst_r) | R0A(gpr(src2_reg))));
|
||||
}
|
||||
}
|
||||
|
||||
mask = get_cc(compiler, type & ~SLJIT_32);
|
||||
mask = get_cc(compiler, type);
|
||||
|
||||
if (src1 & SLJIT_MEM) {
|
||||
if (src1 & OFFS_REG_MASK) {
|
||||
|
|
@ -3807,23 +4013,20 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *comp
|
|||
FAIL_IF(push_load_imm_inst(compiler, tmp1, src1w));
|
||||
|
||||
if (src1 & REG_MASK)
|
||||
FAIL_IF(push_inst(compiler, 0xb9e80000 /* agrk */ | R12A(tmp1) | R4A(tmp1) | R0A(gpr(src1 & REG_MASK))));
|
||||
FAIL_IF(push_inst(compiler, 0xb9080000 /* agr */ | R4A(tmp1) | R0A(gpr(src1 & REG_MASK))));
|
||||
|
||||
src_r = tmp1;
|
||||
src1w = 0;
|
||||
} else
|
||||
src_r = gpr(src1 & REG_MASK);
|
||||
|
||||
ins = (type & SLJIT_32) ? 0xeb00000000f2 /* loc */ : 0xeb00000000e2 /* locg */;
|
||||
ins = is_32bit ? 0xeb00000000f2 /* loc */ : 0xeb00000000e2 /* locg */;
|
||||
return push_inst(compiler, ins | R36A(dst_r) | (mask << 32) | R28A(src_r) | disp_s20((sljit_s32)src1w));
|
||||
}
|
||||
|
||||
if (src1 == SLJIT_IMM) {
|
||||
if (type & SLJIT_32)
|
||||
src1w = (sljit_s32)src1w;
|
||||
|
||||
if (have_lscond2() && is_s16(src1w)) {
|
||||
ins = (type & SLJIT_32) ? 0xec0000000042 /* lochi */ : 0xec0000000046 /* locghi */;
|
||||
ins = is_32bit ? 0xec0000000042 /* lochi */ : 0xec0000000046 /* locghi */;
|
||||
return push_inst(compiler, ins | R36A(dst_r) | (mask << 32) | (sljit_ins)(src1w & 0xffff) << 16);
|
||||
}
|
||||
|
||||
|
|
@ -3832,7 +4035,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *comp
|
|||
} else
|
||||
src_r = gpr(src1);
|
||||
|
||||
ins = (type & SLJIT_32) ? 0xb9f20000 /* locr */ : 0xb9e20000 /* locgr */;
|
||||
ins = is_32bit ? 0xb9f20000 /* locr */ : 0xb9e20000 /* locgr */;
|
||||
return push_inst(compiler, ins | (mask << 12) | R4A(dst_r) | R0A(src_r));
|
||||
}
|
||||
|
||||
|
|
@ -4461,40 +4664,52 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_atomic_store(struct sljit_compiler
|
|||
/* 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)
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 op,
|
||||
sljit_s32 dst, sljit_sw dstw,
|
||||
sljit_sw init_value)
|
||||
{
|
||||
struct sljit_s390x_const *const_;
|
||||
struct sljit_const *const_;
|
||||
sljit_gpr dst_r;
|
||||
int is_32 = 0;
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_PTR(check_sljit_emit_const(compiler, dst, dstw, init_value));
|
||||
CHECK_PTR(check_sljit_emit_const(compiler, op, dst, dstw, init_value));
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
|
||||
const_ = (struct sljit_s390x_const*)ensure_abuf(compiler,
|
||||
sizeof(struct sljit_s390x_const));
|
||||
const_ = (struct sljit_const*)ensure_abuf(compiler, sizeof(struct sljit_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, 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)));
|
||||
|
||||
switch (GET_OPCODE(op)) {
|
||||
case SLJIT_MOV_U8:
|
||||
if (init_value & 0x100)
|
||||
init_value |= 0xff00;
|
||||
else
|
||||
init_value &= 0xff;
|
||||
|
||||
PTR_FAIL_IF(push_inst(compiler, 0xa7090000 /* lghi */ | R20A(dst_r) | (sljit_ins)(init_value & 0xffff)));
|
||||
|
||||
if (dst & SLJIT_MEM)
|
||||
PTR_FAIL_IF(store_byte(compiler, dst_r, dst, dstw));
|
||||
return (struct sljit_const*)const_;
|
||||
|
||||
case SLJIT_MOV32:
|
||||
is_32 = 1;
|
||||
SLJIT_FALLTHROUGH
|
||||
case SLJIT_MOV_S32:
|
||||
PTR_FAIL_IF(push_inst(compiler, 0xc00100000000 /* lgfi */ | R36A(dst_r) | (sljit_ins)(init_value & 0xffffffff)));
|
||||
break;
|
||||
|
||||
default:
|
||||
PTR_FAIL_IF(push_inst(compiler, 0xc00f00000000 /* llilf */ | R36A(dst_r) | (sljit_ins)(init_value & 0xffffffff)));
|
||||
PTR_FAIL_IF(push_inst(compiler, 0xc00800000000 /* iihf */ | R36A(dst_r) | (sljit_ins)((init_value >> 32) & 0xffffffff)));
|
||||
break;
|
||||
}
|
||||
|
||||
if (dst & SLJIT_MEM)
|
||||
PTR_FAIL_IF(store_word(compiler, dst_r, dst, dstw, 0 /* always 64-bit */));
|
||||
PTR_FAIL_IF(store_word(compiler, dst_r, dst, dstw, is_32));
|
||||
|
||||
return (struct sljit_const*)const_;
|
||||
}
|
||||
|
|
@ -4511,32 +4726,85 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_ta
|
|||
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_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_s32 op, sljit_sw new_constant, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_set_jump_addr(addr, (sljit_uw)new_constant, executable_offset);
|
||||
sljit_u16 *inst = (sljit_u16*)addr;
|
||||
SLJIT_UNUSED_ARG(executable_offset);
|
||||
|
||||
switch (GET_OPCODE(op)) {
|
||||
case SLJIT_MOV_U8:
|
||||
SLJIT_ASSERT((inst[0] & 0xff0f) == 0xa709 /* lghi */);
|
||||
|
||||
if (new_constant & 0x100)
|
||||
new_constant |= 0xff00;
|
||||
else
|
||||
new_constant &= 0xff;
|
||||
|
||||
SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 0);
|
||||
inst[1] = (sljit_u16)new_constant;
|
||||
SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 1);
|
||||
inst = (sljit_u16*)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 2);
|
||||
return;
|
||||
|
||||
case SLJIT_MOV32:
|
||||
case SLJIT_MOV_S32:
|
||||
SLJIT_ASSERT((inst[0] & 0xff0f) == 0xc001 /* lgfi */);
|
||||
|
||||
SLJIT_UPDATE_WX_FLAGS(inst, inst + 3, 0);
|
||||
inst[1] = (sljit_u16)(new_constant >> 16);
|
||||
inst[2] = (sljit_u16)new_constant;
|
||||
SLJIT_UPDATE_WX_FLAGS(inst, inst + 3, 1);
|
||||
inst = (sljit_u16*)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 3);
|
||||
return;
|
||||
|
||||
default:
|
||||
SLJIT_ASSERT((inst[0] & 0xff0f) == 0xc00f /* llilf */ && (inst[3] & 0xff0f) == 0xc008 /* iihf */);
|
||||
|
||||
SLJIT_UPDATE_WX_FLAGS(inst, inst + 6, 0);
|
||||
inst[1] = (sljit_u16)(new_constant >> 16);
|
||||
inst[2] = (sljit_u16)new_constant;
|
||||
inst[4] = (sljit_u16)(new_constant >> 48);
|
||||
inst[5] = (sljit_u16)(new_constant >> 32);
|
||||
SLJIT_UPDATE_WX_FLAGS(inst, inst + 6, 1);
|
||||
inst = (sljit_u16*)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 6);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_mov_addr(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_op_addr(struct sljit_compiler *compiler, sljit_s32 op,
|
||||
sljit_s32 dst, sljit_sw dstw)
|
||||
{
|
||||
struct sljit_jump *jump;
|
||||
sljit_gpr dst_r;
|
||||
sljit_gpr dst_r, target_r;
|
||||
SLJIT_UNUSED_ARG(op);
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_PTR(check_sljit_emit_mov_addr(compiler, dst, dstw));
|
||||
CHECK_PTR(check_sljit_emit_op_addr(compiler, op, dst, dstw));
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
|
||||
dst_r = FAST_IS_REG(dst) ? gpr(dst & REG_MASK) : tmp0;
|
||||
|
||||
if (op != SLJIT_ADD_ABS_ADDR)
|
||||
target_r = dst_r;
|
||||
else {
|
||||
target_r = tmp1;
|
||||
|
||||
if (dst & SLJIT_MEM)
|
||||
PTR_FAIL_IF(load_word(compiler, dst_r, dst, dstw, 0));
|
||||
}
|
||||
|
||||
jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
|
||||
PTR_FAIL_IF(!jump);
|
||||
set_mov_addr(jump, compiler, 0);
|
||||
|
||||
dst_r = FAST_IS_REG(dst) ? gpr(dst & REG_MASK) : tmp0;
|
||||
/* Might be converted to lgrl. */
|
||||
PTR_FAIL_IF(push_inst(compiler, 0xc00000000000 /* larl */ | R36A(target_r)));
|
||||
|
||||
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 (op == SLJIT_ADD_ABS_ADDR)
|
||||
PTR_FAIL_IF(push_inst(compiler, 0xb90a0000 /* algr */ | R4A(dst_r) | R0A(tmp1)));
|
||||
|
||||
if (dst & SLJIT_MEM)
|
||||
PTR_FAIL_IF(store_word(compiler, dst_r, dst, dstw, 0));
|
||||
|
|
|
|||
|
|
@ -105,20 +105,20 @@ static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_uw
|
|||
if (a == SLJIT_IMM) {
|
||||
if (flags & EX86_BIN_INS) {
|
||||
if (imma <= 127 && imma >= -128) {
|
||||
inst_size += 1;
|
||||
inst_size += sizeof(sljit_s8);
|
||||
flags |= EX86_BYTE_ARG;
|
||||
} else
|
||||
inst_size += 4;
|
||||
inst_size += sizeof(sljit_sw);
|
||||
} else if (flags & EX86_SHIFT_INS) {
|
||||
SLJIT_ASSERT(imma <= 0x1f);
|
||||
if (imma != 1) {
|
||||
inst_size++;
|
||||
inst_size += sizeof(sljit_s8);
|
||||
flags |= EX86_BYTE_ARG;
|
||||
}
|
||||
} else if (flags & EX86_BYTE_ARG)
|
||||
inst_size++;
|
||||
inst_size += sizeof(sljit_s8);
|
||||
else if (flags & EX86_HALF_ARG)
|
||||
inst_size += sizeof(short);
|
||||
inst_size += sizeof(sljit_s16);
|
||||
else
|
||||
inst_size += sizeof(sljit_sw);
|
||||
} else
|
||||
|
|
@ -1268,41 +1268,59 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *comp
|
|||
CHECK_EXTRA_REGS(src1, src1w, (void)0);
|
||||
CHECK_EXTRA_REGS(src2_reg, src2w, (void)0);
|
||||
|
||||
type &= ~SLJIT_32;
|
||||
|
||||
if (dst & SLJIT_MEM) {
|
||||
if (src1 == SLJIT_IMM || (!(src1 & SLJIT_MEM) && (src2_reg & SLJIT_MEM))) {
|
||||
EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w);
|
||||
src1 = src2_reg;
|
||||
src1w = src2w;
|
||||
type ^= 0x1;
|
||||
if (!(type & SLJIT_COMPARE_SELECT))
|
||||
type ^= 0x1;
|
||||
} else
|
||||
EMIT_MOV(compiler, TMP_REG1, 0, src2_reg, src2w);
|
||||
|
||||
dst_reg = TMP_REG1;
|
||||
} else {
|
||||
if (dst_reg != src2_reg) {
|
||||
if (dst_reg == src1) {
|
||||
src1 = src2_reg;
|
||||
src1w = src2w;
|
||||
} else if (dst_reg != src2_reg) {
|
||||
if (dst_reg == src1) {
|
||||
src1 = src2_reg;
|
||||
src1w = src2w;
|
||||
if (!(type & SLJIT_COMPARE_SELECT))
|
||||
type ^= 0x1;
|
||||
} else if (ADDRESSING_DEPENDS_ON(src1, dst_reg)) {
|
||||
EMIT_MOV(compiler, dst_reg, 0, src1, src1w);
|
||||
src1 = src2_reg;
|
||||
src1w = src2w;
|
||||
} else if (ADDRESSING_DEPENDS_ON(src1, dst_reg)) {
|
||||
EMIT_MOV(compiler, dst_reg, 0, src1, src1w);
|
||||
src1 = src2_reg;
|
||||
src1w = src2w;
|
||||
if (!(type & SLJIT_COMPARE_SELECT))
|
||||
type ^= 0x1;
|
||||
} else
|
||||
EMIT_MOV(compiler, dst_reg, 0, src2_reg, src2w);
|
||||
}
|
||||
} else
|
||||
EMIT_MOV(compiler, dst_reg, 0, src2_reg, src2w);
|
||||
}
|
||||
|
||||
if (sljit_has_cpu_feature(SLJIT_HAS_CMOV) && (src1 != SLJIT_IMM || dst_reg != TMP_REG1)) {
|
||||
if (SLJIT_UNLIKELY(src1 == SLJIT_IMM)) {
|
||||
if (type & SLJIT_COMPARE_SELECT) {
|
||||
if (dst_reg != TMP_REG1 && !FAST_IS_REG(src1)) {
|
||||
EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w);
|
||||
src1 = TMP_REG1;
|
||||
src1w = 0;
|
||||
}
|
||||
|
||||
type ^= 0x1;
|
||||
FAIL_IF(emit_cmp_binary(compiler, dst_reg, 0, src1, src1w));
|
||||
}
|
||||
|
||||
type &= ~(SLJIT_32 | SLJIT_COMPARE_SELECT);
|
||||
|
||||
if (sljit_has_cpu_feature(SLJIT_HAS_CMOV)) {
|
||||
if (SLJIT_UNLIKELY(src1 == SLJIT_IMM)) {
|
||||
if (dst_reg != TMP_REG1) {
|
||||
EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_IMM, src1w);
|
||||
src1 = TMP_REG1;
|
||||
src1w = 0;
|
||||
} else {
|
||||
EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_SP), 0, SLJIT_IMM, src1w);
|
||||
src1 = SLJIT_MEM1(SLJIT_SP);
|
||||
src1w = 0;
|
||||
}
|
||||
}
|
||||
|
||||
FAIL_IF(emit_groupf(compiler, U8(get_jump_code((sljit_uw)type) - 0x40), dst_reg, src1, src1w));
|
||||
} else
|
||||
FAIL_IF(emit_cmov_generic(compiler, type, dst_reg, src1, src1w));
|
||||
|
|
|
|||
|
|
@ -152,20 +152,20 @@ static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_uw
|
|||
if (a == SLJIT_IMM) {
|
||||
if (flags & EX86_BIN_INS) {
|
||||
if (imma <= 127 && imma >= -128) {
|
||||
inst_size += 1;
|
||||
inst_size += sizeof(sljit_s8);
|
||||
flags |= EX86_BYTE_ARG;
|
||||
} else
|
||||
inst_size += 4;
|
||||
inst_size += sizeof(sljit_s32);
|
||||
} else if (flags & EX86_SHIFT_INS) {
|
||||
SLJIT_ASSERT(imma <= (compiler->mode32 ? 0x1f : 0x3f));
|
||||
if (imma != 1) {
|
||||
inst_size++;
|
||||
inst_size += sizeof(sljit_s8);
|
||||
flags |= EX86_BYTE_ARG;
|
||||
}
|
||||
} else if (flags & EX86_BYTE_ARG)
|
||||
inst_size++;
|
||||
inst_size += sizeof(sljit_s8);
|
||||
else if (flags & EX86_HALF_ARG)
|
||||
inst_size += sizeof(short);
|
||||
inst_size += sizeof(sljit_s16);
|
||||
else
|
||||
inst_size += sizeof(sljit_s32);
|
||||
} else {
|
||||
|
|
@ -362,7 +362,7 @@ static sljit_u8* detect_far_jump_type(struct sljit_jump *jump, sljit_u8 *code_pt
|
|||
{
|
||||
sljit_uw type = jump->flags >> TYPE_SHIFT;
|
||||
|
||||
int short_addr = !(jump->flags & SLJIT_REWRITABLE_JUMP) && (jump->flags & JUMP_ADDR) && (jump->u.target <= 0xffffffff);
|
||||
int short_addr = ((jump->flags & (SLJIT_REWRITABLE_JUMP | JUMP_ADDR)) == JUMP_ADDR) && (jump->u.target <= 0xffffffff);
|
||||
|
||||
/* The relative jump below specialized for this case. */
|
||||
SLJIT_ASSERT(reg_map[TMP_REG2] >= 8 && TMP_REG2 != SLJIT_TMP_DEST_REG);
|
||||
|
|
@ -805,7 +805,7 @@ static sljit_s32 call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_t
|
|||
if (word_arg_count == 0)
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
if (word_arg_count >= 3) {
|
||||
if (word_arg_count >= 3 || src == SLJIT_R2) {
|
||||
if (src == SLJIT_R2)
|
||||
*src_ptr = TMP_REG1;
|
||||
EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_R2, 0);
|
||||
|
|
@ -1029,13 +1029,28 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *comp
|
|||
sljit_s32 src1, sljit_sw src1w,
|
||||
sljit_s32 src2_reg)
|
||||
{
|
||||
sljit_u8* inst;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_select(compiler, type, dst_reg, src1, src1w, src2_reg));
|
||||
|
||||
ADJUST_LOCAL_OFFSET(src1, src1w);
|
||||
|
||||
compiler->mode32 = type & SLJIT_32;
|
||||
type &= ~SLJIT_32;
|
||||
|
||||
if (type & SLJIT_COMPARE_SELECT) {
|
||||
if (!FAST_IS_REG(src1)) {
|
||||
EMIT_MOV(compiler, TMP_REG2, 0, src1, src1w);
|
||||
src1 = TMP_REG2;
|
||||
src1w = 0;
|
||||
}
|
||||
|
||||
inst = emit_x86_instruction(compiler, 1, src1, 0, src2_reg, 0);
|
||||
FAIL_IF(!inst);
|
||||
*inst = CMP_r_rm;
|
||||
}
|
||||
|
||||
type &= ~(SLJIT_32 | SLJIT_COMPARE_SELECT);
|
||||
|
||||
if (dst_reg != src2_reg) {
|
||||
if (dst_reg == src1) {
|
||||
|
|
|
|||
|
|
@ -780,6 +780,22 @@ static void generate_jump_or_mov_addr(struct sljit_jump *jump, sljit_sw executab
|
|||
}
|
||||
}
|
||||
|
||||
static sljit_u8 *process_extended_label(sljit_u8 *code_ptr, struct sljit_extended_label *ext_label)
|
||||
{
|
||||
sljit_uw mask;
|
||||
sljit_u8 *ptr = code_ptr;
|
||||
|
||||
SLJIT_ASSERT(ext_label->label.u.index == SLJIT_LABEL_ALIGNED);
|
||||
mask = ext_label->data;
|
||||
|
||||
code_ptr = (sljit_u8*)(((sljit_uw)code_ptr + mask) & ~mask);
|
||||
|
||||
while (ptr < code_ptr)
|
||||
*ptr++ = NOP;
|
||||
|
||||
return code_ptr;
|
||||
}
|
||||
|
||||
static void reduce_code_size(struct sljit_compiler *compiler)
|
||||
{
|
||||
struct sljit_label *label;
|
||||
|
|
@ -914,7 +930,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
|||
struct sljit_const *const_;
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_PTR(check_sljit_generate_code(compiler));
|
||||
CHECK_PTR(check_sljit_generate_code(compiler, options));
|
||||
|
||||
reduce_code_size(compiler);
|
||||
|
||||
|
|
@ -944,6 +960,9 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
|||
} else {
|
||||
switch (len) {
|
||||
case SLJIT_INST_LABEL:
|
||||
if (label->u.index >= SLJIT_LABEL_ALIGNED)
|
||||
code_ptr = process_extended_label(code_ptr, (struct sljit_extended_label*)label);
|
||||
|
||||
label->u.addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
|
||||
label->size = (sljit_uw)(code_ptr - code);
|
||||
label = label->next;
|
||||
|
|
@ -962,7 +981,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
|||
#endif /* SLJIT_CONFIG_X86_32 */
|
||||
}
|
||||
|
||||
SLJIT_ASSERT((sljit_uw)code_ptr - addr <= ((jump->flags >> JUMP_SIZE_SHIFT) & 0x1f));
|
||||
SLJIT_ASSERT((sljit_uw)code_ptr - addr <= ((jump->flags >> JUMP_SIZE_SHIFT) & 0xff));
|
||||
jump = jump->next;
|
||||
break;
|
||||
case SLJIT_INST_MOV_ADDR:
|
||||
|
|
@ -974,7 +993,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
|
|||
break;
|
||||
default:
|
||||
SLJIT_ASSERT(len == SLJIT_INST_CONST);
|
||||
const_->addr = ((sljit_uw)code_ptr) - sizeof(sljit_sw);
|
||||
const_->addr = (sljit_uw)code_ptr;
|
||||
const_ = const_->next;
|
||||
break;
|
||||
}
|
||||
|
|
@ -2998,6 +3017,125 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *
|
|||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2_shift(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_sw shift_arg)
|
||||
{
|
||||
sljit_s32 dst_r;
|
||||
int use_lea = 0;
|
||||
sljit_u8* inst;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_op2_shift(compiler, op, dst, dstw, src1, src1w, src2, src2w, shift_arg));
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
ADJUST_LOCAL_OFFSET(src1, src1w);
|
||||
ADJUST_LOCAL_OFFSET(src2, src2w);
|
||||
|
||||
shift_arg &= (sljit_sw)((sizeof(sljit_sw) * 8) - 1);
|
||||
|
||||
if (src2 == SLJIT_IMM) {
|
||||
src2w = src2w << shift_arg;
|
||||
shift_arg = 0;
|
||||
}
|
||||
|
||||
if (shift_arg == 0) {
|
||||
SLJIT_SKIP_CHECKS(compiler);
|
||||
return sljit_emit_op2(compiler, GET_OPCODE(op), dst, dstw, src1, src1w, 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 = 0;
|
||||
#endif
|
||||
|
||||
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
|
||||
if (shift_arg <= 3) {
|
||||
use_lea = 1;
|
||||
if (!FAST_IS_REG(src2)) {
|
||||
EMIT_MOV(compiler, TMP_REG1, 0, src2, src2w);
|
||||
src2 = TMP_REG1;
|
||||
}
|
||||
|
||||
if (!FAST_IS_REG(src1)) {
|
||||
EMIT_MOV(compiler, src2 == TMP_REG1 ? TMP_REG2 : TMP_REG1, 0, src1, src1w);
|
||||
src1 = src2 == TMP_REG1 ? TMP_REG2 : TMP_REG1;
|
||||
}
|
||||
}
|
||||
#else /* !SLJIT_CONFIG_X86_64 */
|
||||
if (shift_arg <= 3 && (FAST_IS_REG(src1) || (FAST_IS_REG(src2) && src2 != TMP_REG1))) {
|
||||
use_lea = 1;
|
||||
if (!FAST_IS_REG(src2)) {
|
||||
EMIT_MOV(compiler, TMP_REG1, 0, src2, src2w);
|
||||
src2 = TMP_REG1;
|
||||
}
|
||||
|
||||
if (!FAST_IS_REG(src1)) {
|
||||
EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w);
|
||||
src1 = TMP_REG1;
|
||||
}
|
||||
}
|
||||
#endif /* SLJIT_CONFIG_X86_64 */
|
||||
|
||||
if (use_lea) {
|
||||
dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
|
||||
|
||||
inst = emit_x86_instruction(compiler, 1, dst_r, 0, SLJIT_MEM2(src1, src2), shift_arg);
|
||||
FAIL_IF(!inst);
|
||||
*inst = LEA_r_m;
|
||||
|
||||
if (!FAST_IS_REG(dst))
|
||||
return emit_mov(compiler, dst, dstw, dst_r, 0);
|
||||
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
if ((op & SLJIT_SRC2_UNDEFINED) != 0 && FAST_IS_REG(src2) && src1 != src2)
|
||||
dst_r = src2;
|
||||
else {
|
||||
dst_r = FAST_IS_REG(dst) && (dst != src1) ? dst : TMP_REG1;
|
||||
|
||||
if (src2 != dst_r) {
|
||||
EMIT_MOV(compiler, dst_r, 0, src2, src2w);
|
||||
}
|
||||
}
|
||||
|
||||
inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_IMM, shift_arg, dst_r, 0);
|
||||
FAIL_IF(!inst);
|
||||
inst[1] |= SHL;
|
||||
|
||||
if (dst == src1 && dstw == src1w) {
|
||||
inst = emit_x86_instruction(compiler, 1, dst_r, 0, dst, dstw);
|
||||
FAIL_IF(!inst);
|
||||
*inst = ADD_rm_r;
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
if (FAST_IS_REG(dst) && FAST_IS_REG(src1)) {
|
||||
inst = emit_x86_instruction(compiler, 1, dst, 0, SLJIT_MEM2(src1, dst_r), 0);
|
||||
FAIL_IF(!inst);
|
||||
*inst = LEA_r_m;
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
if (src1 == SLJIT_IMM) {
|
||||
BINARY_IMM(ADD, ADD_rm_r, src1w, dst_r, 0);
|
||||
} else {
|
||||
inst = emit_x86_instruction(compiler, 1, dst_r, 0, src1, src1w);
|
||||
FAIL_IF(!inst);
|
||||
*inst = ADD_r_rm;
|
||||
}
|
||||
|
||||
if (dst != dst_r)
|
||||
return emit_mov(compiler, dst, dstw, dst_r, 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)
|
||||
{
|
||||
|
|
@ -3438,6 +3576,82 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compi
|
|||
return label;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_aligned_label(struct sljit_compiler *compiler,
|
||||
sljit_s32 alignment, struct sljit_read_only_buffer *buffers)
|
||||
{
|
||||
sljit_uw mask, size;
|
||||
sljit_u8 *inst;
|
||||
struct sljit_label *label;
|
||||
struct sljit_label *next_label;
|
||||
struct sljit_extended_label *ext_label;
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_PTR(check_sljit_emit_aligned_label(compiler, alignment, buffers));
|
||||
|
||||
sljit_reset_read_only_buffers(buffers);
|
||||
|
||||
if (alignment <= SLJIT_LABEL_ALIGN_1) {
|
||||
SLJIT_SKIP_CHECKS(compiler);
|
||||
label = sljit_emit_label(compiler);
|
||||
PTR_FAIL_IF(!label);
|
||||
} else {
|
||||
/* The used space is filled with NOPs. */
|
||||
mask = ((sljit_uw)1 << alignment) - 1;
|
||||
compiler->size += mask;
|
||||
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1);
|
||||
PTR_FAIL_IF(!inst);
|
||||
inst[0] = SLJIT_INST_LABEL;
|
||||
|
||||
ext_label = (struct sljit_extended_label*)ensure_abuf(compiler, sizeof(struct sljit_extended_label));
|
||||
PTR_FAIL_IF(!ext_label);
|
||||
set_extended_label(ext_label, compiler, SLJIT_LABEL_ALIGNED, mask);
|
||||
label = &ext_label->label;
|
||||
}
|
||||
|
||||
if (buffers == NULL)
|
||||
return label;
|
||||
|
||||
next_label = label;
|
||||
|
||||
while (1) {
|
||||
buffers->u.label = next_label;
|
||||
size = buffers->size;
|
||||
|
||||
while (size >= 4) {
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 4);
|
||||
PTR_FAIL_IF(!inst);
|
||||
INC_SIZE(4);
|
||||
inst[0] = NOP;
|
||||
inst[1] = NOP;
|
||||
inst[2] = NOP;
|
||||
inst[3] = NOP;
|
||||
size -= 4;
|
||||
}
|
||||
|
||||
if (size > 0) {
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
|
||||
PTR_FAIL_IF(!inst);
|
||||
INC_SIZE(size);
|
||||
|
||||
do {
|
||||
*inst++ = NOP;
|
||||
} while (--size != 0);
|
||||
}
|
||||
|
||||
buffers = buffers->next;
|
||||
|
||||
if (buffers == NULL)
|
||||
break;
|
||||
|
||||
SLJIT_SKIP_CHECKS(compiler);
|
||||
next_label = sljit_emit_label(compiler);
|
||||
PTR_FAIL_IF(!next_label);
|
||||
}
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type)
|
||||
{
|
||||
sljit_u8 *inst;
|
||||
|
|
@ -3965,7 +4179,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_replicate(struct sljit_compil
|
|||
else
|
||||
FAIL_IF(emit_groupf(compiler, PSHUFLW_x_xm | EX86_PREF_F2 | EX86_SSE2, vreg, vreg, 0));
|
||||
FAIL_IF(emit_byte(compiler, 0));
|
||||
/* fallthrough */
|
||||
SLJIT_FALLTHROUGH
|
||||
default:
|
||||
if (use_vex)
|
||||
FAIL_IF(emit_vex_instruction(compiler, PSHUFD_x_xm | EX86_PREF_66 | EX86_SSE2, vreg, 0, vreg, 0));
|
||||
|
|
@ -4539,7 +4753,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_replicate(struct sljit_c
|
|||
return emit_vex_instruction(compiler, VPBROADCASTD_x_xm | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2, vreg, 0, vreg, 0);
|
||||
|
||||
src = vreg;
|
||||
/* fallthrough */
|
||||
SLJIT_FALLTHROUGH
|
||||
case 2:
|
||||
byte = U8(src_lane_index);
|
||||
byte = U8(byte | (byte << 2));
|
||||
|
|
@ -5002,6 +5216,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_local_base(struct sljit_compiler *c
|
|||
CHECK_ERROR();
|
||||
CHECK(check_sljit_get_local_base(compiler, dst, dstw, offset));
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
ADJUST_LOCAL_OFFSET(SLJIT_MEM1(SLJIT_SP), offset);
|
||||
|
||||
CHECK_EXTRA_REGS(dst, dstw, (void)0);
|
||||
|
||||
|
|
@ -5009,8 +5224,6 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_local_base(struct sljit_compiler *c
|
|||
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));
|
||||
|
|
@ -5028,59 +5241,105 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_local_base(struct sljit_compiler *c
|
|||
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_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 op,
|
||||
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
|
||||
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
|
||||
sljit_s32 dst_is_ereg = 0;
|
||||
#endif /* !SLJIT_CONFIG_X86_32 */
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_PTR(check_sljit_emit_const(compiler, dst, dstw, init_value));
|
||||
CHECK_PTR(check_sljit_emit_const(compiler, op, dst, dstw, init_value));
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
|
||||
CHECK_EXTRA_REGS(dst, dstw, (void)0);
|
||||
CHECK_EXTRA_REGS(dst, dstw, dst_is_ereg = 1);
|
||||
|
||||
const_ = (struct sljit_const*)ensure_abuf(compiler, sizeof(struct sljit_const));
|
||||
PTR_FAIL_IF(!const_);
|
||||
set_const(const_, compiler);
|
||||
|
||||
switch (GET_OPCODE(op)) {
|
||||
case SLJIT_MOV_U8:
|
||||
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
|
||||
compiler->mode32 = 0;
|
||||
reg = FAST_IS_REG(dst) ? dst : TMP_REG1;
|
||||
compiler->mode32 = (op & SLJIT_32);
|
||||
#endif /* SLJIT_CONFIG_X86_64 */
|
||||
|
||||
if (emit_load_imm64(compiler, reg, init_value))
|
||||
return NULL;
|
||||
#else
|
||||
if (emit_mov(compiler, dst, dstw, SLJIT_IMM, init_value))
|
||||
return NULL;
|
||||
#endif
|
||||
if ((init_value & 0x100) != 0)
|
||||
init_value = init_value | -(sljit_sw)0x100;
|
||||
else
|
||||
init_value = (sljit_u8)init_value;
|
||||
|
||||
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
|
||||
if (dst_is_ereg) {
|
||||
if (emit_mov(compiler, dst, dstw, SLJIT_IMM, (sljit_s32)init_value))
|
||||
return NULL;
|
||||
dst = 0;
|
||||
break;
|
||||
}
|
||||
#endif /* !SLJIT_CONFIG_X86_32 */
|
||||
|
||||
reg = FAST_IS_REG(dst) ? dst : TMP_REG1;
|
||||
|
||||
if (emit_mov(compiler, reg, 0, SLJIT_IMM, init_value))
|
||||
return NULL;
|
||||
break;
|
||||
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
|
||||
case SLJIT_MOV:
|
||||
compiler->mode32 = 0;
|
||||
reg = FAST_IS_REG(dst) ? dst : TMP_REG1;
|
||||
|
||||
if (emit_load_imm64(compiler, reg, init_value))
|
||||
return NULL;
|
||||
break;
|
||||
#endif /* SLJIT_CONFIG_X86_64 */
|
||||
default:
|
||||
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
|
||||
compiler->mode32 = (op == SLJIT_MOV32);
|
||||
#endif /* SLJIT_CONFIG_X86_64 */
|
||||
|
||||
if (emit_mov(compiler, dst, dstw, SLJIT_IMM, (sljit_s32)init_value))
|
||||
return NULL;
|
||||
dst = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1);
|
||||
PTR_FAIL_IF(!inst);
|
||||
|
||||
inst[0] = SLJIT_INST_CONST;
|
||||
|
||||
if (dst & SLJIT_MEM) {
|
||||
#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;
|
||||
if (op == SLJIT_MOV) {
|
||||
if (emit_mov(compiler, dst, dstw, TMP_REG1, 0))
|
||||
return NULL;
|
||||
return const_;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (emit_mov_byte(compiler, 0, dst, dstw, TMP_REG1, 0))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return const_;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_mov_addr(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_op_addr(struct sljit_compiler *compiler, sljit_s32 op,
|
||||
sljit_s32 dst, sljit_sw dstw)
|
||||
{
|
||||
struct sljit_jump *jump;
|
||||
sljit_u8 *inst;
|
||||
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
|
||||
sljit_s32 reg;
|
||||
#endif /* SLJIT_CONFIG_X86_64 */
|
||||
SLJIT_UNUSED_ARG(op);
|
||||
|
||||
CHECK_ERROR_PTR();
|
||||
CHECK_PTR(check_sljit_emit_mov_addr(compiler, dst, dstw));
|
||||
CHECK_PTR(check_sljit_emit_op_addr(compiler, op, dst, dstw));
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
|
||||
CHECK_EXTRA_REGS(dst, dstw, (void)0);
|
||||
|
|
@ -5091,7 +5350,10 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_mov_addr(struct sljit_com
|
|||
|
||||
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
|
||||
compiler->mode32 = 0;
|
||||
reg = FAST_IS_REG(dst) ? dst : TMP_REG1;
|
||||
if (dst & SLJIT_MEM)
|
||||
reg = TMP_REG1;
|
||||
else
|
||||
reg = (op != SLJIT_ADD_ABS_ADDR) ? dst : TMP_REG2;
|
||||
|
||||
PTR_FAIL_IF(emit_load_imm64(compiler, reg, 0));
|
||||
jump->addr = compiler->size;
|
||||
|
|
@ -5099,7 +5361,17 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_mov_addr(struct sljit_com
|
|||
if (reg_map[reg] >= 8)
|
||||
jump->flags |= MOV_ADDR_HI;
|
||||
#else /* !SLJIT_CONFIG_X86_64 */
|
||||
PTR_FAIL_IF(emit_mov(compiler, dst, dstw, SLJIT_IMM, 0));
|
||||
if (op == SLJIT_ADD_ABS_ADDR) {
|
||||
if (dst != SLJIT_R0) {
|
||||
/* Must not be a signed byte argument. */
|
||||
inst = emit_x86_instruction(compiler, 1 | EX86_BIN_INS, SLJIT_IMM, 0x100, dst, dstw);
|
||||
PTR_FAIL_IF(!inst);
|
||||
*(inst + 1) |= ADD;
|
||||
} else
|
||||
PTR_FAIL_IF(emit_do_imm(compiler, ADD_EAX_i32, 0));
|
||||
} else {
|
||||
PTR_FAIL_IF(emit_mov(compiler, dst, dstw, SLJIT_IMM, 0));
|
||||
}
|
||||
#endif /* SLJIT_CONFIG_X86_64 */
|
||||
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1);
|
||||
|
|
@ -5108,7 +5380,11 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_mov_addr(struct sljit_com
|
|||
inst[0] = SLJIT_INST_MOV_ADDR;
|
||||
|
||||
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
|
||||
if (dst & SLJIT_MEM)
|
||||
if (op == SLJIT_ADD_ABS_ADDR) {
|
||||
inst = emit_x86_instruction(compiler, 1, reg, 0, dst, dstw);
|
||||
PTR_FAIL_IF(!inst);
|
||||
*inst = ADD_rm_r;
|
||||
} else if (dst & SLJIT_MEM)
|
||||
PTR_FAIL_IF(emit_mov(compiler, dst, dstw, TMP_REG1, 0));
|
||||
#endif /* SLJIT_CONFIG_X86_64 */
|
||||
|
||||
|
|
@ -5128,11 +5404,31 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_ta
|
|||
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_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_s32 op, sljit_sw new_constant, sljit_sw executable_offset)
|
||||
{
|
||||
void *start_addr;
|
||||
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);
|
||||
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
|
||||
if (op == SLJIT_MOV) {
|
||||
start_addr = (void*)(addr - sizeof(sljit_sw));
|
||||
SLJIT_UPDATE_WX_FLAGS(start_addr, (void*)addr, 0);
|
||||
sljit_unaligned_store_sw(start_addr, new_constant);
|
||||
SLJIT_UPDATE_WX_FLAGS(start_addr, (void*)addr, 1);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
start_addr = (void*)(addr - sizeof(sljit_s32));
|
||||
|
||||
if ((op | SLJIT_32) == SLJIT_MOV32_U8) {
|
||||
if ((new_constant & 0x100) != 0)
|
||||
new_constant = new_constant | -(sljit_sw)0x100;
|
||||
else
|
||||
new_constant = (sljit_u8)new_constant;
|
||||
}
|
||||
|
||||
SLJIT_UPDATE_WX_FLAGS(start_addr, (void*)addr, 0);
|
||||
sljit_unaligned_store_s32(start_addr, (sljit_s32)new_constant);
|
||||
SLJIT_UPDATE_WX_FLAGS(start_addr, (void*)addr, 1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,14 @@
|
|||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#define SLJIT_GET_LABEL_INDEX(label) \
|
||||
((label)->u.index < SLJIT_LABEL_ALIGNED ? (label)->u.index : ((struct sljit_extended_label*)(label))->index)
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_uw sljit_get_label_index(struct sljit_label *label)
|
||||
{
|
||||
return SLJIT_GET_LABEL_INDEX(label);
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_jump_has_label(struct sljit_jump *jump)
|
||||
{
|
||||
return !(jump->flags & JUMP_ADDR) && (jump->u.label != NULL);
|
||||
|
|
@ -48,6 +56,7 @@ struct sljit_serialized_compiler {
|
|||
|
||||
sljit_uw buf_segment_count;
|
||||
sljit_uw label_count;
|
||||
sljit_uw aligned_label_count;
|
||||
sljit_uw jump_count;
|
||||
sljit_uw const_count;
|
||||
|
||||
|
|
@ -94,6 +103,11 @@ struct sljit_serialized_label {
|
|||
sljit_uw size;
|
||||
};
|
||||
|
||||
struct sljit_serialized_aligned_label {
|
||||
sljit_uw size;
|
||||
sljit_uw data;
|
||||
};
|
||||
|
||||
struct sljit_serialized_jump {
|
||||
sljit_uw addr;
|
||||
sljit_uw flags;
|
||||
|
|
@ -122,6 +136,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_uw* sljit_serialize_compiler(struct sljit_compile
|
|||
struct sljit_const *const_;
|
||||
struct sljit_serialized_compiler *serialized_compiler;
|
||||
struct sljit_serialized_label *serialized_label;
|
||||
struct sljit_serialized_aligned_label *serialized_aligned_label;
|
||||
struct sljit_serialized_jump *serialized_jump;
|
||||
struct sljit_serialized_const *serialized_const;
|
||||
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) \
|
||||
|
|
@ -155,7 +170,16 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_uw* sljit_serialize_compiler(struct sljit_compile
|
|||
buf = buf->next;
|
||||
}
|
||||
|
||||
serialized_size += compiler->label_count * sizeof(struct sljit_serialized_label);
|
||||
label = compiler->labels;
|
||||
while (label != NULL) {
|
||||
used_size = sizeof(struct sljit_serialized_label);
|
||||
|
||||
if (label->u.index >= SLJIT_LABEL_ALIGNED)
|
||||
used_size += sizeof(struct sljit_serialized_aligned_label);
|
||||
|
||||
serialized_size += used_size;
|
||||
label = label->next;
|
||||
}
|
||||
|
||||
jump = compiler->jumps;
|
||||
while (jump != NULL) {
|
||||
|
|
@ -229,12 +253,23 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_uw* sljit_serialize_compiler(struct sljit_compile
|
|||
serialized_compiler->buf_segment_count = counter;
|
||||
|
||||
label = compiler->labels;
|
||||
counter = 0;
|
||||
while (label != NULL) {
|
||||
serialized_label = (struct sljit_serialized_label*)ptr;
|
||||
serialized_label->size = label->size;
|
||||
serialized_label->size = (label->u.index < SLJIT_LABEL_ALIGNED) ? label->size : label->u.index;
|
||||
ptr += sizeof(struct sljit_serialized_label);
|
||||
|
||||
if (label->u.index >= SLJIT_LABEL_ALIGNED) {
|
||||
serialized_aligned_label = (struct sljit_serialized_aligned_label*)ptr;
|
||||
serialized_aligned_label->size = label->size;
|
||||
serialized_aligned_label->data = ((struct sljit_extended_label*)label)->data;
|
||||
ptr += sizeof(struct sljit_serialized_aligned_label);
|
||||
counter++;
|
||||
}
|
||||
|
||||
label = label->next;
|
||||
}
|
||||
serialized_compiler->aligned_label_count = counter;
|
||||
|
||||
jump = compiler->jumps;
|
||||
counter = 0;
|
||||
|
|
@ -246,7 +281,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_uw* sljit_serialize_compiler(struct sljit_compile
|
|||
if (jump->flags & JUMP_ADDR)
|
||||
serialized_jump->value = jump->u.target;
|
||||
else if (jump->u.label != NULL)
|
||||
serialized_jump->value = jump->u.label->u.index;
|
||||
serialized_jump->value = SLJIT_GET_LABEL_INDEX(jump->u.label);
|
||||
else
|
||||
serialized_jump->value = SLJIT_MAX_ADDRESS;
|
||||
|
||||
|
|
@ -291,6 +326,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_compiler *sljit_deserialize_compiler(sljit
|
|||
struct sljit_compiler *compiler;
|
||||
struct sljit_serialized_compiler *serialized_compiler;
|
||||
struct sljit_serialized_label *serialized_label;
|
||||
struct sljit_serialized_aligned_label *serialized_aligned_label;
|
||||
struct sljit_serialized_jump *serialized_jump;
|
||||
struct sljit_serialized_const *serialized_const;
|
||||
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) \
|
||||
|
|
@ -302,13 +338,15 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_compiler *sljit_deserialize_compiler(sljit
|
|||
struct sljit_label *label;
|
||||
struct sljit_label *last_label;
|
||||
struct sljit_label **label_list = NULL;
|
||||
struct sljit_label **label_list_ptr = NULL;
|
||||
struct sljit_jump *jump;
|
||||
struct sljit_jump *last_jump;
|
||||
struct sljit_const *const_;
|
||||
struct sljit_const *last_const;
|
||||
sljit_u8 *ptr = (sljit_u8*)buffer;
|
||||
sljit_u8 *end = ptr + size;
|
||||
sljit_uw i, used_size, aligned_size, label_count;
|
||||
sljit_uw i, type, used_size, aligned_size;
|
||||
sljit_uw label_count, aligned_label_count;
|
||||
SLJIT_UNUSED_ARG(options);
|
||||
|
||||
if (size < sizeof(struct sljit_serialized_compiler) || (size & (sizeof(sljit_uw) - 1)) != 0)
|
||||
|
|
@ -403,22 +441,31 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_compiler *sljit_deserialize_compiler(sljit
|
|||
|
||||
last_label = NULL;
|
||||
label_count = serialized_compiler->label_count;
|
||||
if ((sljit_uw)(end - ptr) < label_count * sizeof(struct sljit_serialized_label))
|
||||
aligned_label_count = serialized_compiler->aligned_label_count;
|
||||
i = (label_count * sizeof(struct sljit_serialized_label)) + (aligned_label_count * sizeof(struct sljit_serialized_aligned_label));
|
||||
|
||||
if ((sljit_uw)(end - ptr) < i)
|
||||
goto error;
|
||||
|
||||
label_list = (struct sljit_label **)SLJIT_MALLOC(label_count * sizeof(struct sljit_label*), allocator_data);
|
||||
if (label_list == NULL)
|
||||
goto error;
|
||||
|
||||
label_list_ptr = label_list;
|
||||
for (i = 0; i < label_count; i++) {
|
||||
label = (struct sljit_label*)ensure_abuf(compiler, sizeof(struct sljit_label));
|
||||
serialized_label = (struct sljit_serialized_label*)ptr;
|
||||
type = serialized_label->size;
|
||||
|
||||
if (type < SLJIT_LABEL_ALIGNED) {
|
||||
label = (struct sljit_label*)ensure_abuf(compiler, sizeof(struct sljit_label));
|
||||
} else {
|
||||
label = (struct sljit_label*)ensure_abuf(compiler, sizeof(struct sljit_extended_label));
|
||||
}
|
||||
|
||||
if (label == NULL)
|
||||
goto error;
|
||||
|
||||
serialized_label = (struct sljit_serialized_label*)ptr;
|
||||
label->next = NULL;
|
||||
label->u.index = i;
|
||||
label->size = serialized_label->size;
|
||||
|
||||
if (last_label != NULL)
|
||||
last_label->next = label;
|
||||
|
|
@ -426,11 +473,33 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_compiler *sljit_deserialize_compiler(sljit
|
|||
compiler->labels = label;
|
||||
last_label = label;
|
||||
|
||||
label_list[i] = label;
|
||||
*label_list_ptr++ = label;
|
||||
|
||||
ptr += sizeof(struct sljit_serialized_label);
|
||||
|
||||
if (type < SLJIT_LABEL_ALIGNED) {
|
||||
label->u.index = i;
|
||||
label->size = type;
|
||||
} else {
|
||||
if (aligned_label_count == 0)
|
||||
goto error;
|
||||
|
||||
aligned_label_count--;
|
||||
|
||||
serialized_aligned_label = (struct sljit_serialized_aligned_label*)ptr;
|
||||
label->u.index = type;
|
||||
label->size = serialized_aligned_label->size;
|
||||
|
||||
((struct sljit_extended_label*)label)->index = i;
|
||||
((struct sljit_extended_label*)label)->data = serialized_aligned_label->data;
|
||||
ptr += sizeof(struct sljit_serialized_aligned_label);
|
||||
}
|
||||
}
|
||||
compiler->last_label = last_label;
|
||||
|
||||
if (aligned_label_count != 0)
|
||||
goto error;
|
||||
|
||||
last_jump = NULL;
|
||||
i = serialized_compiler->jump_count;
|
||||
if ((sljit_uw)(end - ptr) < i * sizeof(struct sljit_serialized_jump))
|
||||
|
|
|
|||
|
|
@ -22,11 +22,7 @@ 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. */
|
||||
surrounded by #ifndef/#endif lines so that the value can be overridden by -D. */
|
||||
|
||||
/* By default, the \R escape sequence matches any Unicode line ending
|
||||
character or sequence of characters. If BSR_ANYCRLF is defined (to any
|
||||
|
|
@ -44,9 +40,14 @@ sure both macros are undefined; an emulation function will then be used. */
|
|||
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. */
|
||||
ASCII or UTF-8/16/32. */
|
||||
/* #undef EBCDIC */
|
||||
|
||||
/* To force an EBCDIC environment, define this macro to make the core PCRE2
|
||||
library functions use EBCDIC codepage 1047, regardless of whether the
|
||||
compiler supports it using C character literals. */
|
||||
/* #undef EBCDIC_IGNORING_COMPILER */
|
||||
|
||||
/* 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. */
|
||||
|
|
@ -58,9 +59,6 @@ sure both macros are undefined; an emulation function will then be used. */
|
|||
/* 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 this if your compiler provides __assume() */
|
||||
/* #undef HAVE_BUILTIN_ASSUME */
|
||||
|
||||
|
|
@ -94,9 +92,6 @@ sure both macros are undefined; an emulation function will then be used. */
|
|||
/* 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 <minix/config.h> header file. */
|
||||
/* #undef HAVE_MINIX_CONFIG_H */
|
||||
|
||||
|
|
@ -133,9 +128,6 @@ sure both macros are undefined; an emulation function will then be used. */
|
|||
/* Define to 1 if you have the <stdlib.h> 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 <strings.h> header file. */
|
||||
/* #undef HAVE_STRINGS_H */
|
||||
|
||||
|
|
@ -255,7 +247,7 @@ sure both macros are undefined; an emulation function will then be used. */
|
|||
#define PACKAGE_NAME "PCRE2"
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#define PACKAGE_STRING "PCRE2 10.45"
|
||||
#define PACKAGE_STRING "PCRE2 10.47"
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#define PACKAGE_TARNAME "pcre2"
|
||||
|
|
@ -264,7 +256,7 @@ sure both macros are undefined; an emulation function will then be used. */
|
|||
#define PACKAGE_URL ""
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#define PACKAGE_VERSION "10.45"
|
||||
#define PACKAGE_VERSION "10.47"
|
||||
|
||||
/* 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
|
||||
|
|
@ -291,10 +283,24 @@ sure both macros are undefined; an emulation function will then be used. */
|
|||
#define PCRE2GREP_MAX_BUFSIZE 1048576
|
||||
#endif
|
||||
|
||||
/* See PCRE2_EXP_DEFN; but this is applied to functions in the libpcre2-posix
|
||||
library. */
|
||||
/* #undef PCRE2POSIX_EXP_DEFN */
|
||||
|
||||
/* Define to any value if linking libpcre2-posix dynamically. Ideally, if both
|
||||
static and shared libraries are being built, then PCRE2POSIX_SHARED would
|
||||
be defined only for the shared build. Indeed, this is a requirement on
|
||||
Windows. However, when building with Autoconf and libtool, we compile the
|
||||
sources once only to create both the static and shared library, so in this
|
||||
case, PCRE2POSIX_SHARED should only be defined if the shared library is
|
||||
being built, regardless of whether or not the static library is also being
|
||||
built. */
|
||||
/* #undef PCRE2POSIX_SHARED */
|
||||
|
||||
/* Define to any value to include debugging code. */
|
||||
/* #undef PCRE2_DEBUG */
|
||||
|
||||
/* to make a symbol visible */
|
||||
/* Define to the annotation for making a symbol visible. */
|
||||
#define PCRE2_EXPORT
|
||||
|
||||
/* If you are compiling for a system other than a Unix-like system or
|
||||
|
|
@ -309,7 +315,12 @@ sure both macros are undefined; an emulation function will then be used. */
|
|||
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) */
|
||||
/* Define to any value if linking statically. Ideally, if both static and
|
||||
shared libraries are being built, then PCRE2_STATIC would be defined only
|
||||
for the static build. Indeed, this is a requirement on Windows. With
|
||||
Autoconf and libtool however, it is idiomatic to compile the sources once
|
||||
to create both the static and shared library, so in this case, PCRE2_STATIC
|
||||
should only be defined if no shared library is being built. */
|
||||
/* #undef PCRE2_STATIC */
|
||||
|
||||
/* Define to necessary symbol if this constant uses a non-standard name on
|
||||
|
|
@ -464,7 +475,7 @@ sure both macros are undefined; an emulation function will then be used. */
|
|||
#endif
|
||||
|
||||
/* Version number of package */
|
||||
#define VERSION "10.45"
|
||||
#define VERSION "10.47"
|
||||
|
||||
/* Number of bits in a file offset, on hosts where this is settable. */
|
||||
/* #undef _FILE_OFFSET_BITS */
|
||||
|
|
|
|||
|
|
@ -42,25 +42,21 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
/* The current PCRE version information. */
|
||||
|
||||
#define PCRE2_MAJOR 10
|
||||
#define PCRE2_MINOR 45
|
||||
#define PCRE2_MINOR 47
|
||||
#define PCRE2_PRERELEASE
|
||||
#define PCRE2_DATE 2025-02-05
|
||||
#define PCRE2_DATE 2025-10-21
|
||||
|
||||
/* When an application links to a PCRE DLL in Windows, the symbols that are
|
||||
/* When an application links to a PCRE2 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. */
|
||||
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. */
|
||||
By default, we use the standard "extern" declarations. */
|
||||
|
||||
#ifndef PCRE2_EXP_DECL
|
||||
# ifdef __cplusplus
|
||||
# if defined(_WIN32) && !defined(PCRE2_STATIC)
|
||||
# define PCRE2_EXP_DECL extern __declspec(dllimport)
|
||||
# elif defined __cplusplus
|
||||
# define PCRE2_EXP_DECL extern "C"
|
||||
# else
|
||||
# define PCRE2_EXP_DECL extern
|
||||
|
|
@ -68,14 +64,15 @@ don't change existing definitions of PCRE2_EXP_DECL. */
|
|||
#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
|
||||
a "calling convention" before exported function names. For example:
|
||||
|
||||
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. */
|
||||
might be needed. In order to make this easy, all the exported functions have
|
||||
PCRE2_CALL_CONVENTION just before their names.
|
||||
|
||||
PCRE2 normally uses the platform's standard calling convention, so this should
|
||||
not be set unless you know you need it. */
|
||||
|
||||
#ifndef PCRE2_CALL_CONVENTION
|
||||
#define PCRE2_CALL_CONVENTION
|
||||
|
|
@ -343,6 +340,10 @@ pcre2_pattern_convert(). */
|
|||
#define PCRE2_ERROR_PERL_ECLASS_EMPTY_EXPR 214
|
||||
#define PCRE2_ERROR_PERL_ECLASS_MISSING_CLOSE 215
|
||||
#define PCRE2_ERROR_PERL_ECLASS_UNEXPECTED_CHAR 216
|
||||
#define PCRE2_ERROR_EXPECTED_CAPTURE_GROUP 217
|
||||
#define PCRE2_ERROR_MISSING_OPENING_PARENTHESIS 218
|
||||
#define PCRE2_ERROR_MISSING_NUMBER_TERMINATOR 219
|
||||
#define PCRE2_ERROR_NULL_ERROROFFSET 220
|
||||
|
||||
/* "Expected" matching error codes: no match and partial match. */
|
||||
|
||||
|
|
@ -432,6 +433,11 @@ released, the numbers must not be changed. */
|
|||
#define PCRE2_ERROR_JIT_UNSUPPORTED (-68)
|
||||
#define PCRE2_ERROR_REPLACECASE (-69)
|
||||
#define PCRE2_ERROR_TOOLARGEREPLACE (-70)
|
||||
#define PCRE2_ERROR_DIFFSUBSPATTERN (-71)
|
||||
#define PCRE2_ERROR_DIFFSUBSSUBJECT (-72)
|
||||
#define PCRE2_ERROR_DIFFSUBSOFFSET (-73)
|
||||
#define PCRE2_ERROR_DIFFSUBSOPTIONS (-74)
|
||||
#define PCRE2_ERROR_BAD_BACKSLASH_K (-75)
|
||||
|
||||
|
||||
/* Request types for pcre2_pattern_info() */
|
||||
|
|
@ -484,6 +490,7 @@ released, the numbers must not be changed. */
|
|||
#define PCRE2_CONFIG_NEVER_BACKSLASH_C 13
|
||||
#define PCRE2_CONFIG_COMPILED_WIDTHS 14
|
||||
#define PCRE2_CONFIG_TABLES_LENGTH 15
|
||||
#define PCRE2_CONFIG_EFFECTIVE_LINKSIZE 16
|
||||
|
||||
/* Optimization directives for pcre2_set_optimize().
|
||||
For binary compatibility, only add to this list; do not renumber. */
|
||||
|
|
@ -743,14 +750,14 @@ PCRE2_EXP_DECL pcre2_match_data *PCRE2_CALL_CONVENTION \
|
|||
PCRE2_EXP_DECL pcre2_match_data *PCRE2_CALL_CONVENTION \
|
||||
pcre2_match_data_create_from_pattern(const pcre2_code *, \
|
||||
pcre2_general_context *); \
|
||||
PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \
|
||||
pcre2_match_data_free(pcre2_match_data *); \
|
||||
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 \
|
||||
|
|
@ -762,7 +769,9 @@ PCRE2_EXP_DECL uint32_t PCRE2_CALL_CONVENTION \
|
|||
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 *);
|
||||
pcre2_get_startchar(pcre2_match_data *); \
|
||||
PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
|
||||
pcre2_next_match(pcre2_match_data *, PCRE2_SIZE *, uint32_t *);
|
||||
|
||||
|
||||
/* Convenience functions for handling matched substrings. */
|
||||
|
|
@ -942,6 +951,7 @@ pcre2_compile are called by application code. */
|
|||
#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_next_match PCRE2_SUFFIX(pcre2_next_match_)
|
||||
#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_)
|
||||
|
|
|
|||
|
|
@ -38,17 +38,15 @@ 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"
|
||||
|
||||
|
||||
|
||||
/* This macro represents the max size of list[] and that is used to keep
|
||||
track of UCD info in several places, it should be kept on sync with the
|
||||
value used by GenerateUcd.py */
|
||||
|
|
@ -264,8 +262,10 @@ switch(ptype)
|
|||
if (c < *p) return !negated;
|
||||
if (c == *p++) return negated;
|
||||
}
|
||||
/* LCOV_EXCL_START */
|
||||
PCRE2_DEBUG_UNREACHABLE(); /* Control should never reach here */
|
||||
break;
|
||||
/* LCOV_EXCL_STOP */
|
||||
|
||||
/* Haven't yet thought these through. */
|
||||
|
||||
|
|
@ -806,21 +806,21 @@ for(;;)
|
|||
|
||||
case OP_NOT_DIGIT:
|
||||
invert_bits = TRUE;
|
||||
/* Fall through */
|
||||
PCRE2_FALLTHROUGH /* Fall through */
|
||||
case OP_DIGIT:
|
||||
set2 = (const uint8_t *)(cb->cbits + cbit_digit);
|
||||
break;
|
||||
|
||||
case OP_NOT_WHITESPACE:
|
||||
invert_bits = TRUE;
|
||||
/* Fall through */
|
||||
PCRE2_FALLTHROUGH /* Fall through */
|
||||
case OP_WHITESPACE:
|
||||
set2 = (const uint8_t *)(cb->cbits + cbit_space);
|
||||
break;
|
||||
|
||||
case OP_NOT_WORDCHAR:
|
||||
invert_bits = TRUE;
|
||||
/* Fall through */
|
||||
PCRE2_FALLTHROUGH /* Fall through */
|
||||
case OP_WORDCHAR:
|
||||
set2 = (const uint8_t *)(cb->cbits + cbit_word);
|
||||
break;
|
||||
|
|
@ -1103,7 +1103,7 @@ for(;;)
|
|||
|
||||
case OP_NCLASS:
|
||||
if (chr > 255) return FALSE;
|
||||
/* Fall through */
|
||||
PCRE2_FALLTHROUGH /* Fall through */
|
||||
|
||||
case OP_CLASS:
|
||||
if (chr > 255) break;
|
||||
|
|
@ -1141,8 +1141,10 @@ for(;;)
|
|||
if (list[1] == 0) return TRUE;
|
||||
}
|
||||
|
||||
/* LCOV_EXCL_START */
|
||||
PCRE2_DEBUG_UNREACHABLE(); /* Control should never reach here */
|
||||
return FALSE; /* Avoid compiler warnings */
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1181,11 +1183,13 @@ for (;;)
|
|||
{
|
||||
c = *code;
|
||||
|
||||
/* LCOV_EXCL_START */
|
||||
if (c >= OP_TABLE_LENGTH)
|
||||
{
|
||||
PCRE2_DEBUG_UNREACHABLE();
|
||||
return -1; /* Something gone wrong */
|
||||
}
|
||||
/* LCOV_EXCL_STOP */
|
||||
|
||||
if (c >= OP_STAR && c <= OP_TYPEPOSUPTO)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -19,10 +19,6 @@ 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. */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "pcre2_internal.h"
|
||||
|
||||
const uint8_t PRIV(default_tables)[] = {
|
||||
|
|
|
|||
|
|
@ -37,16 +37,16 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
/* This file contains functions to implement checked integer operation */
|
||||
|
||||
#ifndef PCRE2_PCRE2TEST
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifndef PCRE2_PCRE2TEST
|
||||
#include "pcre2_internal.h"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*************************************************
|
||||
* Checked Integer Multiplication *
|
||||
*************************************************/
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -51,18 +51,18 @@ 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, ERR100,
|
||||
ERR101,ERR102,ERR103,ERR104,ERR105,ERR106,ERR107,ERR108,ERR109,ERR110,
|
||||
ERR111,ERR112,ERR113,ERR114,ERR115,ERR116 };
|
||||
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, ERR100,
|
||||
ERR101, ERR102, ERR103, ERR104, ERR105, ERR106, ERR107, ERR108, ERR109, ERR110,
|
||||
ERR111, ERR112, ERR113, ERR114, ERR115, ERR116, ERR117, ERR118, ERR119, ERR120 };
|
||||
|
||||
/* 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
|
||||
|
|
@ -96,11 +96,11 @@ code (meta_extra_lengths) must be updated to remain in step. */
|
|||
#define META_COND_RNAME 0x80130000u /* (?(R&name)... */
|
||||
#define META_COND_RNUMBER 0x80140000u /* (?(Rdigits)... */
|
||||
#define META_COND_VERSION 0x80150000u /* (?(VERSION<op>x.y)... */
|
||||
#define META_OFFSET 0x80160000u /* Setting offset for various
|
||||
META codes (e.g. META_SCS_NAME) */
|
||||
#define META_OFFSET 0x80160000u /* Setting offset for various META
|
||||
codes (e.g. META_CAPTURE_NAME) */
|
||||
#define META_SCS 0x80170000u /* (*scan_substring:... */
|
||||
#define META_SCS_NAME 0x80180000u /* Next <name> of scan_substring */
|
||||
#define META_SCS_NUMBER 0x80190000u /* Next digits of scan_substring */
|
||||
#define META_CAPTURE_NAME 0x80180000u /* Next <name> in capture lists */
|
||||
#define META_CAPTURE_NUMBER 0x80190000u /* Next digits in capture lists */
|
||||
#define META_DOLLAR 0x801a0000u /* $ metacharacter */
|
||||
#define META_DOT 0x801b0000u /* . metacharacter */
|
||||
#define META_ESCAPE 0x801c0000u /* \d and friends */
|
||||
|
|
@ -186,6 +186,36 @@ therefore no need for it to have a length entry, so use a high value. */
|
|||
#define META_DATA(x) (x & 0x0000ffffu)
|
||||
#define META_DIFF(x,y) ((x-y)>>16)
|
||||
|
||||
/* 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
|
||||
|
||||
#ifdef PCRE2_DEBUG
|
||||
/* Compile data types. */
|
||||
#define CDATA_RECURSE_ARGS 0 /* Argument list for recurse */
|
||||
#define CDATA_CRANGE 1 /* Character range list */
|
||||
#endif
|
||||
|
||||
/* Extended class management flags. */
|
||||
|
||||
#define CLASS_IS_ECLASS 0x1
|
||||
|
|
@ -236,10 +266,16 @@ typedef struct {
|
|||
|
||||
/* Macros for the definitions below, to prevent name collisions. */
|
||||
|
||||
#define _pcre2_posix_class_maps PCRE2_SUFFIX(_pcre2_posix_class_maps)
|
||||
#define _pcre2_update_classbits PCRE2_SUFFIX(_pcre2_update_classbits_)
|
||||
#define _pcre2_compile_class_nested PCRE2_SUFFIX(_pcre2_compile_class_nested_)
|
||||
#define _pcre2_compile_class_not_nested PCRE2_SUFFIX(_pcre2_compile_class_not_nested_)
|
||||
#define _pcre2_posix_class_maps PCRE2_SUFFIX(_pcre2_posix_class_maps)
|
||||
#define _pcre2_update_classbits PCRE2_SUFFIX(_pcre2_update_classbits_)
|
||||
#define _pcre2_compile_class_nested PCRE2_SUFFIX(_pcre2_compile_class_nested_)
|
||||
#define _pcre2_compile_class_not_nested PCRE2_SUFFIX(_pcre2_compile_class_not_nested_)
|
||||
#define _pcre2_compile_get_hash_from_name PCRE2_SUFFIX(_pcre2_compile_get_hash_from_name)
|
||||
#define _pcre2_compile_find_named_group PCRE2_SUFFIX(_pcre2_compile_find_named_group)
|
||||
#define _pcre2_compile_find_dupname_details PCRE2_SUFFIX(_pcre2_compile_find_dupname_details)
|
||||
#define _pcre2_compile_add_name_to_table PCRE2_SUFFIX(_pcre2_compile_add_name_to_table)
|
||||
#define _pcre2_compile_parse_scan_substr_args PCRE2_SUFFIX(_pcre2_compile_parse_scan_substr_args)
|
||||
#define _pcre2_compile_parse_recurse_args PCRE2_SUFFIX(_pcre2_compile_parse_recurse_args)
|
||||
|
||||
|
||||
/* Indices of the POSIX classes in posix_names, posix_name_lengths,
|
||||
|
|
@ -253,6 +289,14 @@ posix_class_maps, and posix_substitutes. They must be kept in sync. */
|
|||
|
||||
extern const int PRIV(posix_class_maps)[];
|
||||
|
||||
/* Defines for hash_dup member in named_group structure. */
|
||||
|
||||
#define NAMED_GROUP_HASH_MASK ((uint16_t)0x7fff)
|
||||
#define NAMED_GROUP_IS_DUPNAME ((uint16_t)0x8000)
|
||||
|
||||
#define NAMED_GROUP_GET_HASH(ng) ((ng)->hash_dup & NAMED_GROUP_HASH_MASK)
|
||||
|
||||
/* Exported functions from pcre2_compile_class.c file: */
|
||||
|
||||
/* Set bits in classbits according to the property type */
|
||||
|
||||
|
|
@ -275,6 +319,38 @@ BOOL PRIV(compile_class_nested)(uint32_t options, uint32_t xoptions,
|
|||
uint32_t **pptr, PCRE2_UCHAR **pcode, int *errorcodeptr,
|
||||
compile_block *cb, PCRE2_SIZE *lengthptr);
|
||||
|
||||
/* Exported functions from pcre2_compile_cgroup.c file: */
|
||||
|
||||
/* Compute hash from a capture name. */
|
||||
|
||||
uint16_t PRIV(compile_get_hash_from_name)(PCRE2_SPTR name, uint32_t length);
|
||||
|
||||
/* Get the descriptor of a known named capture. */
|
||||
|
||||
named_group *PRIV(compile_find_named_group)(PCRE2_SPTR name,
|
||||
uint32_t length, compile_block *cb);
|
||||
|
||||
/* Add entires to name table in alphabetical order. */
|
||||
|
||||
uint32_t PRIV(compile_add_name_to_table)(compile_block *cb,
|
||||
named_group *ng, uint32_t tablecount);
|
||||
|
||||
/* Searches the properties of duplicated names, and returns them
|
||||
in indexptr and countptr. */
|
||||
|
||||
BOOL PRIV(compile_find_dupname_details)(PCRE2_SPTR name, uint32_t length,
|
||||
int *indexptr, int *countptr, int *errorcodeptr, compile_block *cb);
|
||||
|
||||
/* Parse the arguments of recurse operations. */
|
||||
|
||||
uint32_t * PRIV(compile_parse_scan_substr_args)(uint32_t *pptr,
|
||||
int *errorcodeptr, compile_block *cb, PCRE2_SIZE *lengthptr);
|
||||
|
||||
/* Parse the arguments of recurse operations. */
|
||||
|
||||
BOOL PRIV(compile_parse_recurse_args)(uint32_t *pptr_start,
|
||||
PCRE2_SIZE offset, int *errorcodeptr, compile_block *cb);
|
||||
|
||||
#endif /* PCRE2_COMPILE_H_IDEMPOTENT_GUARD */
|
||||
|
||||
/* End of pcre2_compile.h */
|
||||
|
|
|
|||
|
|
@ -0,0 +1,632 @@
|
|||
/*************************************************
|
||||
* 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-2024 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.
|
||||
-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
#include "pcre2_compile.h"
|
||||
|
||||
/*************************************************
|
||||
* Compute the hash code from a capture name *
|
||||
*************************************************/
|
||||
|
||||
/* This function returns with a simple hash code
|
||||
computed from the name of a capture group.
|
||||
|
||||
Arguments:
|
||||
name name of the capture group
|
||||
length the length of the name
|
||||
|
||||
Returns: hash code
|
||||
*/
|
||||
|
||||
uint16_t
|
||||
PRIV(compile_get_hash_from_name)(PCRE2_SPTR name, uint32_t length)
|
||||
{
|
||||
uint16_t hash;
|
||||
|
||||
PCRE2_ASSERT(length > 0);
|
||||
|
||||
hash = (uint16_t)((name[0] & 0x7f) | ((name[length - 1] & 0xff) << 7));
|
||||
PCRE2_ASSERT(hash <= NAMED_GROUP_HASH_MASK);
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************
|
||||
* Get the descriptor of a known named capture *
|
||||
*************************************************/
|
||||
|
||||
/* This function returns the descriptor in the
|
||||
named group list of a known capture group.
|
||||
|
||||
Arguments:
|
||||
name name of the capture group
|
||||
length the length of the name
|
||||
|
||||
Returns: pointer to the descriptor when found,
|
||||
NULL otherwise
|
||||
*/
|
||||
|
||||
named_group *
|
||||
PRIV(compile_find_named_group)(PCRE2_SPTR name,
|
||||
uint32_t length, compile_block *cb)
|
||||
{
|
||||
uint16_t hash = PRIV(compile_get_hash_from_name)(name, length);
|
||||
named_group *ng;
|
||||
named_group *end = cb->named_groups + cb->names_found;
|
||||
|
||||
for (ng = cb->named_groups; ng < end; ng++)
|
||||
if (length == ng->length && hash == NAMED_GROUP_GET_HASH(ng) &&
|
||||
PRIV(strncmp)(name, ng->name, length) == 0) return ng;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************
|
||||
* 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
|
||||
nb named group entry
|
||||
tablecount the count of names in the table so far
|
||||
|
||||
Returns: new tablecount
|
||||
*/
|
||||
|
||||
uint32_t
|
||||
PRIV(compile_add_name_to_table)(compile_block *cb,
|
||||
named_group *ng, uint32_t tablecount)
|
||||
{
|
||||
uint32_t i;
|
||||
PCRE2_SPTR name = ng->name;
|
||||
int length = ng->length;
|
||||
uint32_t duplicate_count = 1;
|
||||
|
||||
PCRE2_UCHAR *slot = cb->name_table;
|
||||
|
||||
PCRE2_ASSERT(length > 0);
|
||||
|
||||
if ((ng->hash_dup & NAMED_GROUP_IS_DUPNAME) != 0)
|
||||
{
|
||||
named_group *ng_it;
|
||||
named_group *end = cb->named_groups + cb->names_found;
|
||||
|
||||
for (ng_it = ng + 1; ng_it < end; ng_it++)
|
||||
if (ng_it->name == name) duplicate_count++;
|
||||
}
|
||||
|
||||
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 * duplicate_count, slot,
|
||||
CU2BYTES((tablecount - i) * cb->name_entry_size));
|
||||
break;
|
||||
}
|
||||
|
||||
/* Continue the loop for a later or duplicate name */
|
||||
|
||||
slot += cb->name_entry_size;
|
||||
}
|
||||
|
||||
tablecount += duplicate_count;
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
PUT2(slot, 0, ng->number);
|
||||
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));
|
||||
|
||||
if (--duplicate_count == 0) break;
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
++ng;
|
||||
if (ng->name == name) break;
|
||||
}
|
||||
|
||||
slot += cb->name_entry_size;
|
||||
}
|
||||
|
||||
return tablecount;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************
|
||||
* 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
|
||||
*/
|
||||
|
||||
BOOL
|
||||
PRIV(compile_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. */
|
||||
|
||||
/* LCOV_EXCL_START */
|
||||
if (i >= cb->names_found)
|
||||
{
|
||||
PCRE2_DEBUG_UNREACHABLE();
|
||||
*errorcodeptr = ERR53;
|
||||
cb->erroroffset = name - cb->start_pattern;
|
||||
return FALSE;
|
||||
}
|
||||
/* LCOV_EXCL_STOP */
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
|
||||
/* Process the capture list of scan substring and recurse
|
||||
operations. Since at least one argument must be present,
|
||||
a 0 return value represents error. */
|
||||
|
||||
static size_t
|
||||
PRIV(compile_process_capture_list)(uint32_t *pptr, PCRE2_SIZE offset,
|
||||
int *errorcodeptr, compile_block *cb)
|
||||
{
|
||||
size_t i, size = 0;
|
||||
named_group *ng;
|
||||
PCRE2_SPTR name;
|
||||
uint32_t length;
|
||||
named_group *end = cb->named_groups + cb->names_found;
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
++pptr;
|
||||
|
||||
switch (META_CODE(*pptr))
|
||||
{
|
||||
case META_OFFSET:
|
||||
GETPLUSOFFSET(offset, pptr);
|
||||
continue;
|
||||
|
||||
case META_CAPTURE_NAME:
|
||||
offset += META_DATA(*pptr);
|
||||
length = *(++pptr);
|
||||
name = cb->start_pattern + offset;
|
||||
|
||||
ng = PRIV(compile_find_named_group)(name, length, cb);
|
||||
|
||||
if (ng == NULL)
|
||||
{
|
||||
*errorcodeptr = ERR15;
|
||||
cb->erroroffset = offset;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((ng->hash_dup & NAMED_GROUP_IS_DUPNAME) == 0)
|
||||
{
|
||||
pptr[-1] = META_CAPTURE_NUMBER;
|
||||
pptr[0] = ng->number;
|
||||
size++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Remains only for duplicated names. */
|
||||
pptr[-1] = META_CAPTURE_NAME;
|
||||
pptr[0] = (uint32_t)(ng - cb->named_groups);
|
||||
size++;
|
||||
name = ng->name;
|
||||
|
||||
while (++ng < end)
|
||||
if (ng->name == name) size++;
|
||||
continue;
|
||||
|
||||
case META_CAPTURE_NUMBER:
|
||||
offset += META_DATA(*pptr);
|
||||
|
||||
i = *(++pptr);
|
||||
if (i > cb->bracount)
|
||||
{
|
||||
*errorcodeptr = ERR15;
|
||||
cb->erroroffset = offset;
|
||||
return 0;
|
||||
}
|
||||
if (i > cb->top_backref) cb->top_backref = (uint16_t)i;
|
||||
size++;
|
||||
continue;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
PCRE2_ASSERT(size > 0);
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************
|
||||
* Parse the arguments of scan substring operations *
|
||||
********************************************************/
|
||||
|
||||
/* This function parses the arguments of scan substring operations.
|
||||
|
||||
Arguments:
|
||||
pptr_start points to the current parsed pattern pointer
|
||||
offset argument starting offset in the pattern
|
||||
errorcodeptr where to put an error code
|
||||
cb the compile block
|
||||
lengthptr NULL during the real compile phase
|
||||
points to length accumulator during pre-compile phase
|
||||
|
||||
Returns: TRUE if OK, FALSE if not, error code set
|
||||
*/
|
||||
|
||||
uint32_t *
|
||||
PRIV(compile_parse_scan_substr_args)(uint32_t *pptr,
|
||||
int *errorcodeptr, compile_block *cb, PCRE2_SIZE *lengthptr)
|
||||
{
|
||||
uint8_t *captures;
|
||||
uint8_t *capture_ptr;
|
||||
uint8_t bit;
|
||||
PCRE2_SPTR name;
|
||||
named_group *ng;
|
||||
named_group *end = cb->named_groups + cb->names_found;
|
||||
BOOL all_found;
|
||||
size_t size;
|
||||
|
||||
PCRE2_ASSERT(*pptr == META_OFFSET);
|
||||
if (PRIV(compile_process_capture_list)(pptr - 1, 0, errorcodeptr, cb) == 0)
|
||||
return NULL;
|
||||
|
||||
/* Align to bytes. Since the highest capture can
|
||||
be equal to bracount, +1 is added before the aligning. */
|
||||
size = (cb->bracount + 1 + 7) >> 3;
|
||||
captures = (uint8_t*)cb->cx->memctl.malloc(size, cb->cx->memctl.memory_data);
|
||||
if (captures == NULL)
|
||||
{
|
||||
*errorcodeptr = ERR21;
|
||||
READPLUSOFFSET(cb->erroroffset, pptr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(captures, 0, size);
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
switch (META_CODE(*pptr))
|
||||
{
|
||||
case META_OFFSET:
|
||||
pptr++;
|
||||
SKIPOFFSET(pptr);
|
||||
continue;
|
||||
|
||||
case META_CAPTURE_NAME:
|
||||
ng = cb->named_groups + pptr[1];
|
||||
PCRE2_ASSERT((ng->hash_dup & NAMED_GROUP_IS_DUPNAME) != 0);
|
||||
pptr += 2;
|
||||
name = ng->name;
|
||||
|
||||
all_found = TRUE;
|
||||
do
|
||||
{
|
||||
if (ng->name != name) continue;
|
||||
|
||||
capture_ptr = captures + (ng->number >> 3);
|
||||
PCRE2_ASSERT(capture_ptr < captures + size);
|
||||
bit = (uint8_t)(1 << (ng->number & 0x7));
|
||||
|
||||
if ((*capture_ptr & bit) == 0)
|
||||
{
|
||||
*capture_ptr |= bit;
|
||||
all_found = FALSE;
|
||||
}
|
||||
}
|
||||
while (++ng < end);
|
||||
|
||||
if (!all_found)
|
||||
{
|
||||
*lengthptr += 1 + 2 * IMM2_SIZE;
|
||||
continue;
|
||||
}
|
||||
|
||||
pptr[-2] = META_CAPTURE_NUMBER;
|
||||
pptr[-1] = 0;
|
||||
continue;
|
||||
|
||||
case META_CAPTURE_NUMBER:
|
||||
pptr += 2;
|
||||
|
||||
capture_ptr = captures + (pptr[-1] >> 3);
|
||||
PCRE2_ASSERT(capture_ptr < captures + size);
|
||||
bit = (uint8_t)(1 << (pptr[-1] & 0x7));
|
||||
|
||||
if ((*capture_ptr & bit) != 0)
|
||||
{
|
||||
pptr[-1] = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
*capture_ptr |= bit;
|
||||
*lengthptr += 1 + IMM2_SIZE;
|
||||
continue;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
cb->cx->memctl.free(captures, cb->cx->memctl.memory_data);
|
||||
return pptr - 1;
|
||||
}
|
||||
|
||||
|
||||
/* Implement heapsort heapify algorithm. */
|
||||
|
||||
static void do_heapify_u16(uint16_t *captures, size_t size, size_t i)
|
||||
{
|
||||
size_t max;
|
||||
size_t left;
|
||||
size_t right;
|
||||
uint16_t tmp;
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
max = i;
|
||||
left = (i << 1) + 1;
|
||||
right = left + 1;
|
||||
|
||||
if (left < size && captures[left] > captures[max]) max = left;
|
||||
if (right < size && captures[right] > captures[max]) max = right;
|
||||
if (i == max) return;
|
||||
|
||||
tmp = captures[i];
|
||||
captures[i] = captures[max];
|
||||
captures[max] = tmp;
|
||||
i = max;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*************************************************
|
||||
* Parse the arguments of recurse operations *
|
||||
*************************************************/
|
||||
|
||||
/* This function parses the arguments of recurse operations.
|
||||
|
||||
Arguments:
|
||||
pptr_start the current parsed pattern pointer
|
||||
offset argument starting offset in the pattern
|
||||
errorcodeptr where to put an error code
|
||||
cb the compile block
|
||||
lengthptr NULL during the real compile phase
|
||||
points to length accumulator during pre-compile phase
|
||||
|
||||
Returns: TRUE if OK, FALSE if not, error code set
|
||||
*/
|
||||
|
||||
BOOL
|
||||
PRIV(compile_parse_recurse_args)(uint32_t *pptr_start,
|
||||
PCRE2_SIZE offset, int *errorcodeptr, compile_block *cb)
|
||||
{
|
||||
uint32_t *pptr = pptr_start;
|
||||
size_t i, size;
|
||||
PCRE2_SPTR name;
|
||||
named_group *ng;
|
||||
named_group *end = cb->named_groups + cb->names_found;
|
||||
recurse_arguments *args;
|
||||
uint16_t *captures;
|
||||
uint16_t *current;
|
||||
uint16_t *captures_end;
|
||||
uint16_t tmp;
|
||||
|
||||
/* Process all arguments, compute the required size. */
|
||||
|
||||
size = PRIV(compile_process_capture_list)(pptr, offset, errorcodeptr, cb);
|
||||
if (size == 0) return FALSE;
|
||||
|
||||
args = cb->cx->memctl.malloc(
|
||||
sizeof(recurse_arguments) + size * sizeof(uint16_t), cb->cx->memctl.memory_data);
|
||||
|
||||
if (args == NULL)
|
||||
{
|
||||
*errorcodeptr = ERR21;
|
||||
cb->erroroffset = offset;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
args->header.next = NULL;
|
||||
#ifdef PCRE2_DEBUG
|
||||
args->header.type = CDATA_RECURSE_ARGS;
|
||||
#endif
|
||||
args->size = size;
|
||||
|
||||
/* Caching the pre-processed capture list. */
|
||||
if (cb->last_data != NULL)
|
||||
cb->last_data->next = &args->header;
|
||||
else
|
||||
cb->first_data = &args->header;
|
||||
|
||||
cb->last_data = &args->header;
|
||||
|
||||
/* Create the capture list size. */
|
||||
|
||||
captures = (uint16_t*)(args + 1);
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
++pptr;
|
||||
|
||||
switch (META_CODE(*pptr))
|
||||
{
|
||||
case META_OFFSET:
|
||||
SKIPOFFSET(pptr);
|
||||
continue;
|
||||
|
||||
case META_CAPTURE_NAME:
|
||||
ng = cb->named_groups + *(++pptr);
|
||||
PCRE2_ASSERT((ng->hash_dup & NAMED_GROUP_IS_DUPNAME) != 0);
|
||||
*captures++ = (uint16_t)(ng->number);
|
||||
|
||||
name = ng->name;
|
||||
|
||||
while (++ng < end)
|
||||
if (ng->name == name) *captures++ = (uint16_t)(ng->number);
|
||||
continue;
|
||||
|
||||
case META_CAPTURE_NUMBER:
|
||||
*captures++ = *(++pptr);
|
||||
continue;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
PCRE2_ASSERT(size == (size_t)(captures - (uint16_t*)(args + 1)));
|
||||
args->skip_size = (size_t)(pptr - pptr_start) - 1;
|
||||
|
||||
if (size == 1) return TRUE;
|
||||
|
||||
/* Sort captures. */
|
||||
|
||||
captures = (uint16_t*)(args + 1);
|
||||
i = (size >> 1) - 1;
|
||||
while (TRUE)
|
||||
{
|
||||
do_heapify_u16(captures, size, i);
|
||||
if (i == 0) break;
|
||||
i--;
|
||||
}
|
||||
|
||||
for (i = size - 1; i > 0; i--)
|
||||
{
|
||||
tmp = captures[0];
|
||||
captures[0] = captures[i];
|
||||
captures[i] = tmp;
|
||||
|
||||
do_heapify_u16(captures, i, 0);
|
||||
}
|
||||
|
||||
/* Remove duplicates. */
|
||||
|
||||
captures_end = captures + size;
|
||||
tmp = *captures++;
|
||||
current = captures;
|
||||
|
||||
while (current < captures_end)
|
||||
{
|
||||
if (*current != tmp)
|
||||
{
|
||||
tmp = *current;
|
||||
*captures++ = tmp;
|
||||
}
|
||||
|
||||
current++;
|
||||
}
|
||||
|
||||
args->size = (size_t)(captures - (uint16_t*)(args + 1));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* End of pcre2_compile_cgroup.c */
|
||||
|
|
@ -38,12 +38,11 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "pcre2_compile.h"
|
||||
|
||||
|
||||
|
||||
typedef struct {
|
||||
/* Option bits for eclass. */
|
||||
uint32_t options;
|
||||
|
|
@ -66,7 +65,7 @@ b) none of the cases here:
|
|||
#define CLASS_END_CASES(meta) \
|
||||
default: \
|
||||
PCRE2_ASSERT((meta) <= META_END); \
|
||||
/* Fall through */ \
|
||||
PCRE2_FALLTHROUGH /* Fall through */ \
|
||||
case META_CLASS: \
|
||||
case META_CLASS_NOT: \
|
||||
case META_CLASS_EMPTY: \
|
||||
|
|
@ -525,6 +524,9 @@ if (xoptions & PCRE2_EXTRA_CASELESS_RESTRICT)
|
|||
|
||||
if (xoptions & PCRE2_EXTRA_TURKISH_CASING)
|
||||
class_options |= PARSE_CLASS_TURKISH_UTF;
|
||||
#else
|
||||
(void)options; /* Avoid compiler warning. */
|
||||
(void)xoptions; /* Avoid compiler warning. */
|
||||
#endif
|
||||
|
||||
/* Compute required space for the range. */
|
||||
|
|
@ -543,7 +545,10 @@ cranges = cb->cx->memctl.malloc(
|
|||
|
||||
if (cranges == NULL) return NULL;
|
||||
|
||||
cranges->next = NULL;
|
||||
cranges->header.next = NULL;
|
||||
#ifdef PCRE2_DEBUG
|
||||
cranges->header.type = CDATA_CRANGE;
|
||||
#endif
|
||||
cranges->range_list_size = (uint16_t)range_list_size;
|
||||
cranges->char_lists_types = 0;
|
||||
cranges->char_lists_size = 0;
|
||||
|
|
@ -905,6 +910,10 @@ uint8_t *classbits = cb->classbits.classbits;
|
|||
uint32_t c, byte_start, byte_end;
|
||||
uint32_t classbits_end = (end <= 0xff ? end : 0xff);
|
||||
|
||||
#ifndef SUPPORT_UNICODE
|
||||
(void)xoptions; /* Avoid compiler warning. */
|
||||
#endif
|
||||
|
||||
/* 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 (though these may be ignored if caseless
|
||||
|
|
@ -1080,6 +1089,10 @@ BOOL utf = FALSE;
|
|||
uint32_t xclass_props;
|
||||
PCRE2_UCHAR *class_uchardata;
|
||||
class_ranges* cranges;
|
||||
#else
|
||||
(void)has_bitmap; /* Avoid compiler warning. */
|
||||
(void)errorcodeptr; /* Avoid compiler warning. */
|
||||
(void)lengthptr; /* Avoid compiler warning. */
|
||||
#endif
|
||||
|
||||
/* If an XClass contains a negative special such as \S, we need to flip the
|
||||
|
|
@ -1112,19 +1125,19 @@ if (utf)
|
|||
}
|
||||
|
||||
/* Caching the pre-processed character ranges. */
|
||||
if (cb->next_cranges != NULL)
|
||||
cb->next_cranges->next = cranges;
|
||||
if (cb->last_data != NULL)
|
||||
cb->last_data->next = &cranges->header;
|
||||
else
|
||||
cb->cranges = cranges;
|
||||
cb->first_data = &cranges->header;
|
||||
|
||||
cb->next_cranges = cranges;
|
||||
cb->last_data = &cranges->header;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Reuse the pre-processed character ranges. */
|
||||
cranges = cb->cranges;
|
||||
PCRE2_ASSERT(cranges != NULL);
|
||||
cb->cranges = cranges->next;
|
||||
cranges = (class_ranges*)cb->first_data;
|
||||
PCRE2_ASSERT(cranges != NULL && cranges->header.type == CDATA_CRANGE);
|
||||
cb->first_data = cranges->header.next;
|
||||
}
|
||||
|
||||
if (cranges->range_list_size > 0)
|
||||
|
|
@ -1270,8 +1283,23 @@ while (TRUE)
|
|||
value of 1 removes vertical space and 2 removes underscore. */
|
||||
|
||||
if (tabopt < 0) tabopt = -tabopt;
|
||||
#ifdef EBCDIC
|
||||
{
|
||||
uint8_t posix_vertical[4] = { CHAR_LF, CHAR_VT, CHAR_FF, CHAR_CR };
|
||||
uint8_t posix_underscore = CHAR_UNDERSCORE;
|
||||
uint8_t *chars = NULL;
|
||||
int n = 0;
|
||||
|
||||
if (tabopt == 1) { chars = posix_vertical; n = 4; }
|
||||
else if (tabopt == 2) { chars = &posix_underscore; n = 1; }
|
||||
|
||||
for (; n > 0; ++chars, --n)
|
||||
pbits.classbits[*chars/8] &= ~(1u << (*chars&7));
|
||||
}
|
||||
#else
|
||||
if (tabopt == 1) pbits.classbits[1] &= ~0x3c;
|
||||
else if (tabopt == 2) pbits.classbits[11] &= 0x7f;
|
||||
else if (tabopt == 2) pbits.classbits[11] &= 0x7f;
|
||||
#endif
|
||||
|
||||
/* Add the POSIX table or its complement into the main table that is
|
||||
being built and we are done. */
|
||||
|
|
@ -2079,9 +2107,11 @@ switch (op)
|
|||
lhs_op_info->bits.classwords[i] ^= rhs_op_info->bits.classwords[i];
|
||||
break;
|
||||
|
||||
/* LCOV_EXCL_START */
|
||||
default:
|
||||
PCRE2_DEBUG_UNREACHABLE();
|
||||
break;
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2141,7 +2171,7 @@ switch (meta)
|
|||
}
|
||||
|
||||
ptr++;
|
||||
/* Fall through */
|
||||
PCRE2_FALLTHROUGH /* Fall through */
|
||||
|
||||
default:
|
||||
/* Scan forward characters, ranges, and properties.
|
||||
|
|
@ -2158,11 +2188,13 @@ switch (meta)
|
|||
/* We must have a 100% guarantee that ptr increases when
|
||||
compile_class_operand() returns, even on Release builds, so that we can
|
||||
statically prove our loops terminate. */
|
||||
/* LCOV_EXCL_START */
|
||||
if (ptr <= prev_ptr)
|
||||
{
|
||||
PCRE2_DEBUG_UNREACHABLE();
|
||||
return FALSE;
|
||||
}
|
||||
/* LCOV_EXCL_STOP */
|
||||
|
||||
/* If we fell through above, consume the closing ']'. */
|
||||
if (meta == META_CLASS || meta == META_CLASS_NOT)
|
||||
|
|
|
|||
|
|
@ -38,18 +38,11 @@ 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. */
|
||||
|
|
@ -79,7 +72,7 @@ pcre2_config(uint32_t what, void *where)
|
|||
{
|
||||
if (where == NULL) /* Requests a length */
|
||||
{
|
||||
switch(what)
|
||||
switch (what)
|
||||
{
|
||||
default:
|
||||
return PCRE2_ERROR_BADOPTION;
|
||||
|
|
@ -87,6 +80,7 @@ if (where == NULL) /* Requests a length */
|
|||
case PCRE2_CONFIG_BSR:
|
||||
case PCRE2_CONFIG_COMPILED_WIDTHS:
|
||||
case PCRE2_CONFIG_DEPTHLIMIT:
|
||||
case PCRE2_CONFIG_EFFECTIVE_LINKSIZE:
|
||||
case PCRE2_CONFIG_HEAPLIMIT:
|
||||
case PCRE2_CONFIG_JIT:
|
||||
case PCRE2_CONFIG_LINKSIZE:
|
||||
|
|
@ -124,13 +118,13 @@ switch (what)
|
|||
case PCRE2_CONFIG_COMPILED_WIDTHS:
|
||||
*((uint32_t *)where) = 0
|
||||
#ifdef SUPPORT_PCRE2_8
|
||||
+ 1
|
||||
+ (1 << 0)
|
||||
#endif
|
||||
#ifdef SUPPORT_PCRE2_16
|
||||
+ 2
|
||||
+ (1 << 1)
|
||||
#endif
|
||||
#ifdef SUPPORT_PCRE2_32
|
||||
+ 4
|
||||
+ (1 << 2)
|
||||
#endif
|
||||
;
|
||||
break;
|
||||
|
|
@ -139,6 +133,10 @@ switch (what)
|
|||
*((uint32_t *)where) = MATCH_LIMIT_DEPTH;
|
||||
break;
|
||||
|
||||
case PCRE2_CONFIG_EFFECTIVE_LINKSIZE:
|
||||
*((uint32_t *)where) = LINK_SIZE * sizeof(PCRE2_UCHAR);
|
||||
break;
|
||||
|
||||
case PCRE2_CONFIG_HEAPLIMIT:
|
||||
*((uint32_t *)where) = HEAP_LIMIT;
|
||||
break;
|
||||
|
|
@ -163,7 +161,7 @@ switch (what)
|
|||
#endif
|
||||
|
||||
case PCRE2_CONFIG_LINKSIZE:
|
||||
*((uint32_t *)where) = (uint32_t)configured_link_size;
|
||||
*((uint32_t *)where) = (uint32_t)CONFIGURED_LINK_SIZE;
|
||||
break;
|
||||
|
||||
case PCRE2_CONFIG_MATCHLIMIT:
|
||||
|
|
@ -206,8 +204,7 @@ switch (what)
|
|||
#endif
|
||||
return (int)(1 + ((where == NULL)?
|
||||
strlen(v) : PRIV(strcpy_c8)((PCRE2_UCHAR *)where, v)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PCRE2_CONFIG_UNICODE:
|
||||
#if defined SUPPORT_UNICODE
|
||||
|
|
@ -244,6 +241,7 @@ switch (what)
|
|||
return (int)(1 + ((where == NULL)?
|
||||
strlen(v) : PRIV(strcpy_c8)((PCRE2_UCHAR *)where, v)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -39,10 +39,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
*/
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "pcre2_internal.h"
|
||||
|
||||
|
||||
|
|
@ -506,10 +502,7 @@ 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 */
|
||||
synonym for backwards compatibility. The second now does nothing. */
|
||||
|
||||
PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
|
||||
pcre2_set_recursion_limit(pcre2_match_context *mcontext, uint32_t limit)
|
||||
|
|
@ -529,8 +522,6 @@ pcre2_set_recursion_memory_management(pcre2_match_context *mcontext,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* LCOV_EXCL_STOP */
|
||||
|
||||
|
||||
/* ------------ Convert context ------------ */
|
||||
|
||||
|
|
@ -543,10 +534,20 @@ ccontext->glob_separator = separator;
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const char *globpunct =
|
||||
STR_EXCLAMATION_MARK STR_QUOTATION_MARK STR_NUMBER_SIGN STR_DOLLAR_SIGN
|
||||
STR_PERCENT_SIGN STR_AMPERSAND STR_APOSTROPHE STR_LEFT_PARENTHESIS
|
||||
STR_RIGHT_PARENTHESIS STR_ASTERISK STR_PLUS STR_COMMA STR_MINUS STR_DOT
|
||||
STR_SLASH STR_COLON STR_SEMICOLON STR_LESS_THAN_SIGN STR_EQUALS_SIGN
|
||||
STR_GREATER_THAN_SIGN STR_QUESTION_MARK STR_COMMERCIAL_AT
|
||||
STR_LEFT_SQUARE_BRACKET STR_BACKSLASH STR_RIGHT_SQUARE_BRACKET
|
||||
STR_CIRCUMFLEX_ACCENT STR_UNDERSCORE STR_GRAVE_ACCENT STR_LEFT_CURLY_BRACKET
|
||||
STR_VERTICAL_LINE STR_RIGHT_CURLY_BRACKET STR_TILDE;
|
||||
|
||||
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)))
|
||||
if (escape > 255 || (escape != 0 && strchr(globpunct, escape) == NULL))
|
||||
return PCRE2_ERROR_BADDATA;
|
||||
ccontext->glob_escape = escape;
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -39,12 +39,10 @@ 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)
|
||||
|
||||
|
|
@ -81,6 +79,16 @@ enum { POSIX_START_REGEX, POSIX_ANCHORED, POSIX_NOT_BRACKET,
|
|||
} \
|
||||
}
|
||||
|
||||
/* Macro to check for lowercase characters. */
|
||||
|
||||
#ifdef EBCDIC
|
||||
#define ISLOWER(c) (((c) >= CHAR_a && (c) <= CHAR_i) || \
|
||||
((c) >= CHAR_j && (c) <= CHAR_r) || \
|
||||
((c) >= CHAR_s && (c) <= CHAR_z))
|
||||
#else
|
||||
#define ISLOWER(c) ((c) >= CHAR_a && (c) <= CHAR_z)
|
||||
#endif
|
||||
|
||||
/* Literals that must be escaped: \ ? * + | . ^ $ { } [ ] ( ) */
|
||||
|
||||
static const char *pcre2_escaped_literals =
|
||||
|
|
@ -97,6 +105,24 @@ static const char *posix_meta_escapes =
|
|||
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;
|
||||
|
||||
/* Recognized POSIX classes, colon-separated. */
|
||||
|
||||
static const char *posix_classes =
|
||||
STR_a STR_l STR_p STR_h STR_a STR_COLON
|
||||
STR_l STR_o STR_w STR_e STR_r STR_COLON
|
||||
STR_u STR_p STR_p STR_e STR_r STR_COLON
|
||||
STR_a STR_l STR_n STR_u STR_m STR_COLON
|
||||
STR_a STR_s STR_c STR_i STR_i STR_COLON
|
||||
STR_b STR_l STR_a STR_n STR_k STR_COLON
|
||||
STR_c STR_n STR_t STR_r STR_l STR_COLON
|
||||
STR_d STR_i STR_g STR_i STR_t STR_COLON
|
||||
STR_g STR_r STR_a STR_p STR_h STR_COLON
|
||||
STR_p STR_r STR_i STR_n STR_t STR_COLON
|
||||
STR_p STR_u STR_n STR_c STR_t STR_COLON
|
||||
STR_s STR_p STR_a STR_c STR_e STR_COLON
|
||||
STR_w STR_o STR_r STR_d STR_COLON
|
||||
STR_x STR_d STR_i STR_g STR_i STR_t STR_COLON;
|
||||
|
||||
|
||||
|
||||
/*************************************************
|
||||
|
|
@ -190,7 +216,7 @@ while (plength > 0)
|
|||
switch (posix_state)
|
||||
{
|
||||
case POSIX_CLASS_STARTED:
|
||||
if (c <= 127 && islower(c)) break; /* Remain in started state */
|
||||
if (ISLOWER(c)) break; /* Remain in started state */
|
||||
posix_state = POSIX_CLASS_NOT_STARTED;
|
||||
if (c == CHAR_COLON && plength > 0 &&
|
||||
*posix == CHAR_RIGHT_SQUARE_BRACKET)
|
||||
|
|
@ -200,7 +226,7 @@ while (plength > 0)
|
|||
posix++;
|
||||
continue; /* With next character after :] */
|
||||
}
|
||||
/* Fall through */
|
||||
PCRE2_FALLTHROUGH /* Fall through */
|
||||
|
||||
case POSIX_CLASS_NOT_STARTED:
|
||||
if (c == CHAR_LEFT_SQUARE_BRACKET)
|
||||
|
|
@ -277,9 +303,9 @@ while (plength > 0)
|
|||
if (plength == 0) return PCRE2_ERROR_END_BACKSLASH;
|
||||
if (extended) nextisliteral = TRUE; else
|
||||
{
|
||||
if (*posix < 127 && strchr(posix_meta_escapes, *posix) != NULL)
|
||||
if (*posix < 255 && strchr(posix_meta_escapes, *posix) != NULL)
|
||||
{
|
||||
if (isdigit(*posix)) PUTCHARS(STR_BACKSLASH);
|
||||
if (*posix >= CHAR_0 && *posix <= CHAR_9) PUTCHARS(STR_BACKSLASH);
|
||||
if (p + 1 > endp) return PCRE2_ERROR_NOMEMORY;
|
||||
lastspecial = *p++ = *posix++;
|
||||
plength--;
|
||||
|
|
@ -295,7 +321,7 @@ while (plength > 0)
|
|||
|
||||
case CHAR_LEFT_PARENTHESIS:
|
||||
bracount++;
|
||||
/* Fall through */
|
||||
PCRE2_FALLTHROUGH /* Fall through */
|
||||
|
||||
case CHAR_QUESTION_MARK:
|
||||
case CHAR_PLUS:
|
||||
|
|
@ -303,7 +329,7 @@ while (plength > 0)
|
|||
case CHAR_RIGHT_CURLY_BRACKET:
|
||||
case CHAR_VERTICAL_LINE:
|
||||
if (!extended) goto ESCAPE_LITERAL;
|
||||
/* Fall through */
|
||||
PCRE2_FALLTHROUGH /* Fall through */
|
||||
|
||||
case CHAR_DOT:
|
||||
case CHAR_DOLLAR_SIGN:
|
||||
|
|
@ -332,10 +358,10 @@ while (plength > 0)
|
|||
posix_state = POSIX_ANCHORED;
|
||||
goto COPY_SPECIAL;
|
||||
}
|
||||
/* Fall through */
|
||||
PCRE2_FALLTHROUGH /* Fall through */
|
||||
|
||||
default:
|
||||
if (c < 128 && strchr(pcre2_escaped_literals, c) != NULL)
|
||||
if (c < 255 && strchr(pcre2_escaped_literals, c) != NULL)
|
||||
{
|
||||
ESCAPE_LITERAL:
|
||||
PUTCHARS(STR_BACKSLASH);
|
||||
|
|
@ -474,8 +500,6 @@ 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;
|
||||
|
|
@ -500,7 +524,7 @@ class_index = 1;
|
|||
|
||||
while (TRUE)
|
||||
{
|
||||
if (*class_ptr == CHAR_NUL) return 0;
|
||||
if (*class_ptr == 0) return 0;
|
||||
|
||||
pattern = start;
|
||||
|
||||
|
|
@ -539,31 +563,61 @@ Returns: !0 => character is found in the class
|
|||
static BOOL
|
||||
convert_glob_char_in_class(int class_index, PCRE2_UCHAR c)
|
||||
{
|
||||
const uint8_t *cbits = PRIV(default_tables) + cbits_offset;
|
||||
int cbit;
|
||||
|
||||
#if PCRE2_CODE_UNIT_WIDTH != 8
|
||||
if (c > 0xff)
|
||||
{
|
||||
/* ctype functions are not sane for c > 0xff */
|
||||
return 0;
|
||||
/* Can't access the character tables for c > 0xff */
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* See posix_class_maps. This is a small local clone of that.
|
||||
Note that we don't know exactly what character tables will be used at
|
||||
match time, but, for the purposes of pattern conversion, it should be
|
||||
sufficient to use PCRE2's built-in default tables. */
|
||||
|
||||
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);
|
||||
case 1: /* alpha */
|
||||
if (c == CHAR_UNDERSCORE) return FALSE;
|
||||
if (((cbits + cbit_digit)[c/8] & (1u << (c&7))) != 0) return FALSE;
|
||||
cbit = cbit_word;
|
||||
break;
|
||||
|
||||
case 2: cbit = cbit_lower; break; /* lower */
|
||||
case 3: cbit = cbit_upper; break; /* upper */
|
||||
|
||||
case 4: /* alnum */
|
||||
if (c == CHAR_UNDERSCORE) return FALSE;
|
||||
cbit = cbit_word;
|
||||
break;
|
||||
|
||||
case 5: /* ascii */
|
||||
if (((cbits + cbit_cntrl)[c/8] & (1u << (c&7))) != 0) return TRUE;
|
||||
cbit = cbit_print;
|
||||
break;
|
||||
|
||||
case 6: /* blank */
|
||||
if (c == CHAR_LF || c == CHAR_VT || c == CHAR_FF || c == CHAR_CR)
|
||||
return FALSE;
|
||||
cbit = cbit_space;
|
||||
break;
|
||||
|
||||
case 7: cbit = cbit_cntrl; break; /* cntrl */
|
||||
case 8: cbit = cbit_digit; break; /* digit */
|
||||
case 9: cbit = cbit_graph; break; /* graph */
|
||||
case 10: cbit = cbit_print; break; /* print */
|
||||
case 11: cbit = cbit_punct; break; /* punct */
|
||||
case 12: cbit = cbit_space; break; /* space */
|
||||
case 13: cbit = cbit_word; break; /* word */
|
||||
case 14: cbit = cbit_xdigit; break; /* xdigit */
|
||||
default: return FALSE;
|
||||
}
|
||||
|
||||
return ((cbits + cbit)[c/8] & (1u << (c&7))) != 0;
|
||||
}
|
||||
|
||||
/* Parse a range of characters.
|
||||
|
|
@ -1005,7 +1059,7 @@ while (pattern < pattern_end)
|
|||
c = *pattern++;
|
||||
}
|
||||
|
||||
if (c < 128 && strchr(pcre2_escaped_literals, c) != NULL)
|
||||
if (c < 255 && strchr(pcre2_escaped_literals, c) != NULL)
|
||||
convert_glob_write(&out, CHAR_BACKSLASH);
|
||||
|
||||
convert_glob_write(&out, c);
|
||||
|
|
@ -1065,13 +1119,21 @@ pcre2_pattern_convert(PCRE2_SPTR pattern, PCRE2_SIZE plength, uint32_t options,
|
|||
pcre2_convert_context *ccontext)
|
||||
{
|
||||
int rc;
|
||||
PCRE2_UCHAR null_str[1] = { 0xcd };
|
||||
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 (pattern == NULL && plength == 0)
|
||||
pattern = null_str;
|
||||
|
||||
if (pattern == NULL || bufflenptr == NULL)
|
||||
{
|
||||
if (bufflenptr != NULL) *bufflenptr = 0; /* Error offset */
|
||||
return PCRE2_ERROR_NULL;
|
||||
}
|
||||
|
||||
if ((options & ~ALL_OPTIONS) != 0 || /* Undefined bit set */
|
||||
(pattype & (~pattype+1)) != pattype || /* More than one type set */
|
||||
|
|
@ -1136,8 +1198,13 @@ for (int i = 0; i < 2; i++)
|
|||
bufflenptr, dummyrun, ccontext);
|
||||
break;
|
||||
|
||||
/* We have already validated pattype. */
|
||||
/* LCOV_EXCL_START */
|
||||
default:
|
||||
goto EXIT;
|
||||
PCRE2_DEBUG_UNREACHABLE();
|
||||
*bufflenptr = 0; /* Error offset */
|
||||
return PCRE2_ERROR_INTERNAL;
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
if (rc != 0 || /* Error */
|
||||
|
|
@ -1150,20 +1217,23 @@ for (int i = 0; i < 2; i++)
|
|||
|
||||
allocated = PRIV(memctl_malloc)(sizeof(pcre2_memctl) +
|
||||
(*bufflenptr + 1)*PCRE2_CODE_UNIT_WIDTH, (pcre2_memctl *)ccontext);
|
||||
if (allocated == NULL) return PCRE2_ERROR_NOMEMORY;
|
||||
if (allocated == NULL)
|
||||
{
|
||||
*bufflenptr = 0; /* Error offset */
|
||||
return PCRE2_ERROR_NOMEMORY;
|
||||
}
|
||||
*buffptr = (PCRE2_UCHAR *)(((char *)allocated) + sizeof(pcre2_memctl));
|
||||
|
||||
use_buffer = *buffptr;
|
||||
use_length = *bufflenptr + 1;
|
||||
}
|
||||
|
||||
/* Something went terribly wrong. Trigger an assert and return an error */
|
||||
/* Running the loop above ought to have succeeded the second time. */
|
||||
/* LCOV_EXCL_START */
|
||||
PCRE2_DEBUG_UNREACHABLE();
|
||||
|
||||
EXIT:
|
||||
|
||||
*bufflenptr = 0; /* Error offset */
|
||||
return PCRE2_ERROR_INTERNAL;
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -72,16 +72,14 @@ 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
|
||||
#include "pcre2_internal.h"
|
||||
|
||||
|
||||
|
||||
#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| \
|
||||
|
|
@ -2330,7 +2328,7 @@ for (;;)
|
|||
case 0x2029:
|
||||
#endif /* Not EBCDIC */
|
||||
if (mb->bsr_convention == PCRE2_BSR_ANYCRLF) break;
|
||||
/* Fall through */
|
||||
PCRE2_FALLTHROUGH /* Fall through */
|
||||
|
||||
case CHAR_LF:
|
||||
ADD_NEW(state_offset + 1, 0);
|
||||
|
|
@ -2442,7 +2440,7 @@ for (;;)
|
|||
caseless = TRUE;
|
||||
codevalue -= OP_STARI - OP_STAR;
|
||||
|
||||
/* Fall through */
|
||||
PCRE2_FALLTHROUGH /* Fall through */
|
||||
case OP_PLUS:
|
||||
case OP_MINPLUS:
|
||||
case OP_POSPLUS:
|
||||
|
|
@ -2486,7 +2484,7 @@ for (;;)
|
|||
case OP_NOTPOSQUERYI:
|
||||
caseless = TRUE;
|
||||
codevalue -= OP_STARI - OP_STAR;
|
||||
/* Fall through */
|
||||
PCRE2_FALLTHROUGH /* Fall through */
|
||||
case OP_QUERY:
|
||||
case OP_MINQUERY:
|
||||
case OP_POSQUERY:
|
||||
|
|
@ -2527,7 +2525,7 @@ for (;;)
|
|||
case OP_NOTPOSSTARI:
|
||||
caseless = TRUE;
|
||||
codevalue -= OP_STARI - OP_STAR;
|
||||
/* Fall through */
|
||||
PCRE2_FALLTHROUGH /* Fall through */
|
||||
case OP_STAR:
|
||||
case OP_MINSTAR:
|
||||
case OP_POSSTAR:
|
||||
|
|
@ -2564,7 +2562,7 @@ for (;;)
|
|||
case OP_NOTEXACTI:
|
||||
caseless = TRUE;
|
||||
codevalue -= OP_STARI - OP_STAR;
|
||||
/* Fall through */
|
||||
PCRE2_FALLTHROUGH /* Fall through */
|
||||
case OP_EXACT:
|
||||
case OP_NOTEXACT:
|
||||
count = current_state->count; /* Number already matched */
|
||||
|
|
@ -2599,7 +2597,7 @@ for (;;)
|
|||
case OP_NOTPOSUPTOI:
|
||||
caseless = TRUE;
|
||||
codevalue -= OP_STARI - OP_STAR;
|
||||
/* Fall through */
|
||||
PCRE2_FALLTHROUGH /* Fall through */
|
||||
case OP_UPTO:
|
||||
case OP_MINUPTO:
|
||||
case OP_POSUPTO:
|
||||
|
|
@ -2941,6 +2939,9 @@ for (;;)
|
|||
uint32_t recno = (callpat == mb->start_code)? 0 :
|
||||
GET2(callpat, 1 + LINK_SIZE);
|
||||
|
||||
/* Argument list has not been supported yet. */
|
||||
if (code[1 + LINK_SIZE] == OP_CREF) return PCRE2_ERROR_DFA_UITEM;
|
||||
|
||||
if (rws->free < RWS_RSIZE + RWS_OVEC_RSIZE)
|
||||
{
|
||||
rc = more_workspace(&rws, RWS_OVEC_RSIZE, mb);
|
||||
|
|
@ -3341,10 +3342,12 @@ pcre2_dfa_match(const pcre2_code *code, PCRE2_SPTR subject, PCRE2_SIZE length,
|
|||
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;
|
||||
uint32_t original_options = options;
|
||||
|
||||
PCRE2_UCHAR null_str[1] = { 0xcd };
|
||||
PCRE2_SPTR original_subject = subject;
|
||||
PCRE2_SPTR start_match;
|
||||
PCRE2_SPTR end_subject;
|
||||
PCRE2_SPTR bumpalong_limit;
|
||||
|
|
@ -3386,44 +3389,46 @@ rws->free = RWS_BASE_SIZE - RWS_ANCHOR_SIZE;
|
|||
|
||||
/* Recognize NULL, length 0 as an empty string. */
|
||||
|
||||
if (subject == NULL && length == 0) subject = (PCRE2_SPTR)"";
|
||||
if (subject == NULL && length == 0) subject = null_str;
|
||||
|
||||
/* 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 (match_data == NULL) return PCRE2_ERROR_NULL;
|
||||
if (re == NULL || subject == NULL || workspace == NULL)
|
||||
{ rc = PCRE2_ERROR_NULL; goto EXIT; }
|
||||
if ((options & ~PUBLIC_DFA_MATCH_OPTIONS) != 0)
|
||||
{ rc = PCRE2_ERROR_BADOPTION; goto EXIT; }
|
||||
|
||||
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;
|
||||
if (wscount < 20) { rc = PCRE2_ERROR_DFA_WSSIZE; goto EXIT; }
|
||||
if (start_offset > length) { rc = PCRE2_ERROR_BADOFFSET; goto EXIT; }
|
||||
|
||||
/* 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;
|
||||
{ rc = PCRE2_ERROR_BADOPTION; goto EXIT; }
|
||||
|
||||
/* Invalid UTF support is not available for DFA matching. */
|
||||
|
||||
if ((re->overall_options & PCRE2_MATCH_INVALID_UTF) != 0)
|
||||
return PCRE2_ERROR_DFA_UINVALID_UTF;
|
||||
{ rc = PCRE2_ERROR_DFA_UINVALID_UTF; goto EXIT; }
|
||||
|
||||
/* 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;
|
||||
if (re->magic_number != MAGIC_NUMBER)
|
||||
{ rc = PCRE2_ERROR_BADMAGIC; goto EXIT; }
|
||||
|
||||
/* Check the code unit width. */
|
||||
|
||||
if ((re->flags & PCRE2_MODE_MASK) != PCRE2_CODE_UNIT_WIDTH/8)
|
||||
return PCRE2_ERROR_BADMODE;
|
||||
{ rc = PCRE2_ERROR_BADMODE; goto EXIT; }
|
||||
|
||||
/* 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
|
||||
|
|
@ -3449,8 +3454,8 @@ 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;
|
||||
workspace[1] > (int)((wscount - 2)/INTS_PER_STATEBLOCK))
|
||||
{ rc = PCRE2_ERROR_DFA_BADRESTART; goto EXIT; }
|
||||
}
|
||||
|
||||
/* Set some local values */
|
||||
|
|
@ -3498,7 +3503,7 @@ else
|
|||
if (mcontext->offset_limit != PCRE2_UNSET)
|
||||
{
|
||||
if ((re->overall_options & PCRE2_USE_OFFSET_LIMIT) == 0)
|
||||
return PCRE2_ERROR_BADOFFSETLIMIT;
|
||||
{ rc = PCRE2_ERROR_BADOFFSETLIMIT; goto EXIT; }
|
||||
bumpalong_limit = subject + mcontext->offset_limit;
|
||||
}
|
||||
mb->callout = mcontext->callout;
|
||||
|
|
@ -3565,9 +3570,12 @@ switch(re->newline_convention)
|
|||
mb->nltype = NLTYPE_ANYCRLF;
|
||||
break;
|
||||
|
||||
/* LCOV_EXCL_START */
|
||||
default:
|
||||
PCRE2_DEBUG_UNREACHABLE();
|
||||
return PCRE2_ERROR_INTERNAL;
|
||||
rc = PCRE2_ERROR_INTERNAL;
|
||||
goto EXIT;
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
/* Check a UTF string for validity if required. For 8-bit and 16-bit strings,
|
||||
|
|
@ -3588,7 +3596,7 @@ if (utf && (options & PCRE2_NO_UTF_CHECK) == 0)
|
|||
#if PCRE2_CODE_UNIT_WIDTH != 32
|
||||
unsigned int i;
|
||||
if (start_match < end_subject && NOT_FIRSTCU(*start_match))
|
||||
return PCRE2_ERROR_BADUTFOFFSET;
|
||||
{ rc = PCRE2_ERROR_BADUTFOFFSET; goto EXIT; }
|
||||
for (i = re->max_lookbehind; i > 0 && check_subject > subject; i--)
|
||||
{
|
||||
check_subject--;
|
||||
|
|
@ -3609,12 +3617,12 @@ if (utf && (options & PCRE2_NO_UTF_CHECK) == 0)
|
|||
/* 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,
|
||||
rc = PRIV(valid_utf)(check_subject,
|
||||
length - (PCRE2_SIZE)(check_subject - subject), &(match_data->startchar));
|
||||
if (match_data->rc != 0)
|
||||
if (rc != 0)
|
||||
{
|
||||
match_data->startchar += (PCRE2_SIZE)(check_subject - subject);
|
||||
return match_data->rc;
|
||||
goto EXIT;
|
||||
}
|
||||
}
|
||||
#endif /* SUPPORT_UNICODE */
|
||||
|
|
@ -3678,9 +3686,10 @@ if ((match_data->flags & PCRE2_MD_COPIED_SUBJECT) != 0)
|
|||
/* 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->subject = NULL; /* Default for match error */
|
||||
match_data->mark = NULL;
|
||||
match_data->matchedby = PCRE2_MATCHEDBY_DFA_INTERPRETER;
|
||||
match_data->options = original_options;
|
||||
|
||||
/* 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
|
||||
|
|
@ -4032,29 +4041,40 @@ for (;;)
|
|||
|
||||
if (rc != PCRE2_ERROR_NOMATCH || anchored)
|
||||
{
|
||||
if (rc == PCRE2_ERROR_NOMATCH) goto NOMATCH_EXIT;
|
||||
|
||||
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->subject_length = length;
|
||||
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)
|
||||
if (rc >= 0 || rc == PCRE2_ERROR_PARTIAL)
|
||||
{
|
||||
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->subject_length = length;
|
||||
match_data->start_offset = start_offset;
|
||||
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);
|
||||
}
|
||||
|
||||
if (rc >= 0 && (options & PCRE2_COPY_MATCHED_SUBJECT) != 0)
|
||||
{
|
||||
if (length != 0)
|
||||
{
|
||||
match_data->subject = match_data->memctl.malloc(CU2BYTES(length),
|
||||
match_data->memctl.memory_data);
|
||||
if (match_data->subject == NULL)
|
||||
{ rc = PCRE2_ERROR_NOMEMORY; goto EXIT; }
|
||||
memcpy((void *)match_data->subject, subject, CU2BYTES(length));
|
||||
}
|
||||
else
|
||||
match_data->subject = NULL;
|
||||
match_data->flags |= PCRE2_MD_COPIED_SUBJECT;
|
||||
}
|
||||
else
|
||||
else if (rc >= 0 || rc == PCRE2_ERROR_PARTIAL)
|
||||
{
|
||||
if (rc >= 0 || rc == PCRE2_ERROR_PARTIAL) match_data->subject = subject;
|
||||
match_data->subject = original_subject;
|
||||
}
|
||||
goto EXIT;
|
||||
}
|
||||
|
|
@ -4088,6 +4108,9 @@ for (;;)
|
|||
} /* "Bumpalong" loop */
|
||||
|
||||
NOMATCH_EXIT:
|
||||
match_data->subject = original_subject;
|
||||
match_data->subject_length = length;
|
||||
match_data->start_offset = start_offset;
|
||||
rc = PCRE2_ERROR_NOMATCH;
|
||||
|
||||
EXIT:
|
||||
|
|
@ -4098,6 +4121,7 @@ while (rws->next != NULL)
|
|||
mb->memctl.free(next, mb->memctl.memory_data);
|
||||
}
|
||||
|
||||
match_data->rc = rc;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,12 +39,10 @@ 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)
|
||||
|
||||
|
|
@ -97,7 +95,7 @@ static const unsigned char compile_error_texts[] =
|
|||
"a relative value of zero is not allowed\0"
|
||||
"conditional subpattern contains more than two branches\0"
|
||||
"atomic assertion expected after (?( or (?(?C)\0"
|
||||
"digit expected after (?+ or (?-\0"
|
||||
"digit expected after (?+\0"
|
||||
/* 30 */
|
||||
"unknown POSIX class name\0"
|
||||
"internal error in pcre2_study(): should not occur\0"
|
||||
|
|
@ -148,7 +146,7 @@ static const unsigned char compile_error_texts[] =
|
|||
#ifndef EBCDIC
|
||||
"\\c must be followed by a printable ASCII character\0"
|
||||
#else
|
||||
"\\c must be followed by a letter or one of [\\]^_?\0"
|
||||
"\\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 */
|
||||
|
|
@ -208,6 +206,11 @@ static const unsigned char compile_error_texts[] =
|
|||
/* 115 */
|
||||
"terminating ] with no following closing parenthesis in (?[...]\0"
|
||||
"unexpected character in (?[...]) extended character class\0"
|
||||
"expected capture group number or name\0"
|
||||
"missing opening parenthesis\0"
|
||||
"syntax error in subpattern number (missing terminator?)\0"
|
||||
/* 120 */
|
||||
"erroroffset passed as NULL\0"
|
||||
;
|
||||
|
||||
/* Match-time and UTF error texts are in the same format. */
|
||||
|
|
@ -291,13 +294,18 @@ static const unsigned char match_error_texts[] =
|
|||
"heap limit exceeded\0"
|
||||
"invalid syntax\0"
|
||||
/* 65 */
|
||||
"internal error - duplicate substitution match\0"
|
||||
"internal error: duplicate substitution match\0"
|
||||
"PCRE2_MATCH_INVALID_UTF is not supported for DFA matching\0"
|
||||
"INTERNAL ERROR: invalid substring offset\0"
|
||||
"internal error: invalid substring offset\0"
|
||||
"feature is not supported by the JIT compiler\0"
|
||||
"error performing replacement case transformation\0"
|
||||
/* 70 */
|
||||
"replacement too large (longer than PCRE2_SIZE)\0"
|
||||
"substitute pattern differs from prior match call\0"
|
||||
"substitute subject differs from prior match call\0"
|
||||
"substitute start offset differs from prior match call\0"
|
||||
"substitute options differ from prior match call\0"
|
||||
"disallowed use of \\K in lookaround\0"
|
||||
;
|
||||
|
||||
|
||||
|
|
@ -324,7 +332,7 @@ pcre2_get_error_message(int enumber, PCRE2_UCHAR *buffer, PCRE2_SIZE size)
|
|||
{
|
||||
const unsigned char *message;
|
||||
PCRE2_SIZE i;
|
||||
int n;
|
||||
int n, rc = 0;
|
||||
|
||||
if (size == 0) return PCRE2_ERROR_NOMEMORY;
|
||||
|
||||
|
|
@ -346,7 +354,7 @@ else /* Invalid error number */
|
|||
|
||||
for (; n > 0; n--)
|
||||
{
|
||||
while (*message++ != CHAR_NUL) {};
|
||||
while (*message++ != CHAR_NUL) {}
|
||||
if (*message == CHAR_NUL) return PCRE2_ERROR_BADDATA;
|
||||
}
|
||||
|
||||
|
|
@ -354,14 +362,23 @@ for (i = 0; *message != 0; i++)
|
|||
{
|
||||
if (i >= size - 1)
|
||||
{
|
||||
buffer[i] = 0; /* Terminate partial message */
|
||||
return PCRE2_ERROR_NOMEMORY;
|
||||
rc = PCRE2_ERROR_NOMEMORY;
|
||||
break;
|
||||
}
|
||||
buffer[i] = *message++;
|
||||
}
|
||||
|
||||
buffer[i] = 0;
|
||||
return (int)i;
|
||||
#if defined EBCDIC && 'a' != 0x81
|
||||
/* If compiling for EBCDIC, but the compiler's string literals are not EBCDIC,
|
||||
then we are in the "force EBCDIC 1047" mode. I have chosen to add a few lines
|
||||
here to translate the error strings on the fly, rather than require the string
|
||||
literals above to be written out arduously using the "STR_XYZ" macros. */
|
||||
for (PCRE2_SIZE j = 0; j < i; ++j)
|
||||
buffer[j] = PRIV(ascii_to_ebcdic_1047)[buffer[j]];
|
||||
#endif
|
||||
|
||||
buffer[i] = 0; /* Terminate message, even if truncated. */
|
||||
return rc? rc : (int)i;
|
||||
}
|
||||
|
||||
/* End of pcre2_error.c */
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ 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_dfa_match(). However, it is called only when Unicode support is being
|
||||
|
|
@ -45,14 +46,10 @@ 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
|
||||
|
|
|
|||
|
|
@ -46,13 +46,10 @@ 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 *
|
||||
*************************************************/
|
||||
|
|
|
|||
|
|
@ -41,6 +41,15 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#ifndef PCRE2_INTERNAL_H_IDEMPOTENT_GUARD
|
||||
#define PCRE2_INTERNAL_H_IDEMPOTENT_GUARD
|
||||
|
||||
/* We do not assume that the config.h file has an idempotent include guard,
|
||||
since it may well be written by clients. The standard Autoheader config.h does
|
||||
not have an include guard (although we could customise that). */
|
||||
|
||||
#if defined HAVE_CONFIG_H && !defined PCRE2_CONFIG_H_IDEMPOTENT_GUARD
|
||||
#define PCRE2_CONFIG_H_IDEMPOTENT_GUARD
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
/* 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
|
||||
|
|
@ -59,13 +68,12 @@ be including this file. There is no explicit way of forcing a compile to be
|
|||
abandoned, but trying to include a non-existent file seems cleanest. Otherwise
|
||||
there will be many irrelevant consequential errors. */
|
||||
|
||||
#if (!defined PCRE2_BUILDING_PCRE2TEST && !defined PCRE2_DFTABLES) && \
|
||||
#if (!defined PCRE2_PCRE2TEST && !defined PCRE2_DFTABLES) && \
|
||||
(!defined PCRE2_CODE_UNIT_WIDTH || \
|
||||
(PCRE2_CODE_UNIT_WIDTH != 8 && \
|
||||
PCRE2_CODE_UNIT_WIDTH != 16 && \
|
||||
PCRE2_CODE_UNIT_WIDTH != 32))
|
||||
#error PCRE2_CODE_UNIT_WIDTH must be defined as 8, 16, or 32.
|
||||
#include <AbandonCompile>
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -120,13 +128,12 @@ MSVC 10/2010. Except for VC6 (which is missing some fundamentals and fails). */
|
|||
#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:
|
||||
using some MS magic, as documented here:
|
||||
https://learn.microsoft.com/en-us/cpp/build/exporting-from-a-dll-using-declspec-dllexport
|
||||
|
||||
In pcre2.h (which is included below), we define only PCRE2_EXP_DECL,
|
||||
which is all that is needed for applications (they just import the symbols). To
|
||||
compile the library, we use:
|
||||
|
||||
PCRE2_EXP_DECL for declarations
|
||||
PCRE2_EXP_DEFN for definitions
|
||||
|
|
@ -140,24 +147,23 @@ 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. */
|
||||
|
||||
#if defined __cplusplus
|
||||
#error This project uses C99. C++ is not supported.
|
||||
#endif
|
||||
|
||||
#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 PCRE2_EXPORT
|
||||
# define PCRE2_EXP_DEFN
|
||||
# endif
|
||||
# if defined(_WIN32) && !defined(PCRE2_STATIC)
|
||||
# define PCRE2_EXP_DECL extern __declspec(dllexport)
|
||||
# else
|
||||
# ifdef __cplusplus
|
||||
# define PCRE2_EXP_DECL extern "C" PCRE2_EXPORT
|
||||
# else
|
||||
# define PCRE2_EXP_DECL extern PCRE2_EXPORT
|
||||
# endif
|
||||
# ifndef PCRE2_EXP_DEFN
|
||||
# define PCRE2_EXP_DEFN PCRE2_EXP_DECL
|
||||
# endif
|
||||
# define PCRE2_EXP_DECL extern PCRE2_EXPORT
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef PCRE2_EXP_DEFN
|
||||
# if defined(_WIN32) && !defined(PCRE2_STATIC)
|
||||
# define PCRE2_EXP_DEFN extern __declspec(dllexport)
|
||||
# else
|
||||
# define PCRE2_EXP_DEFN extern PCRE2_EXPORT
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
|
@ -167,19 +173,6 @@ 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, 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
|
||||
|
|
@ -201,28 +194,6 @@ code that a non-static object is being referenced. */
|
|||
#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. */
|
||||
|
||||
|
|
@ -406,7 +377,7 @@ 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, \
|
||||
0x2006, 0x2007, 0x2008, 0x2009, 0x200a, 0x202f, 0x205f, 0x3000, \
|
||||
NOTACHAR
|
||||
|
||||
#define HSPACE_MULTIBYTE_CASES \
|
||||
|
|
@ -422,7 +393,7 @@ PCRE (both APIs) for a long time. */
|
|||
case 0x2007: /* FIGURE SPACE */ \
|
||||
case 0x2008: /* PUNCTUATION SPACE */ \
|
||||
case 0x2009: /* THIN SPACE */ \
|
||||
case 0x200A: /* HAIR SPACE */ \
|
||||
case 0x200a: /* HAIR SPACE */ \
|
||||
case 0x202f: /* NARROW NO-BREAK SPACE */ \
|
||||
case 0x205f: /* MEDIUM MATHEMATICAL SPACE */ \
|
||||
case 0x3000 /* IDEOGRAPHIC SPACE */
|
||||
|
|
@ -552,6 +523,7 @@ bytes in a code unit in that mode. */
|
|||
#define PCRE2_DUPCAPUSED 0x00200000u /* contains (?| */
|
||||
#define PCRE2_HASBKC 0x00400000u /* contains \C */
|
||||
#define PCRE2_HASACCEPT 0x00800000u /* contains (*ACCEPT) */
|
||||
#define PCRE2_HASBSK 0x01000000u /* contains \K */
|
||||
|
||||
#define PCRE2_MODE_MASK (PCRE2_MODE8 | PCRE2_MODE16 | PCRE2_MODE32)
|
||||
|
||||
|
|
@ -698,6 +670,10 @@ same code point. */
|
|||
compatibility. NEL is the Unicode newline character; make sure it is
|
||||
a positive value. */
|
||||
|
||||
#if '\n' != 0x0a
|
||||
#error "ASCII character '\n' is not 0x0a"
|
||||
#endif
|
||||
|
||||
#define CHAR_LF '\n'
|
||||
#define CHAR_NL CHAR_LF
|
||||
#define CHAR_NEL ((unsigned char)'\x85')
|
||||
|
|
@ -713,7 +689,232 @@ a positive value. */
|
|||
|
||||
#endif /* EBCDIC */
|
||||
|
||||
/* The remaining definitions work in both environments. */
|
||||
/* When we want to use EBCDIC with an ASCII compiler, for testing EBCDIC on
|
||||
ASCII platforms, then we can hardcode an EBCDIC codepage (IBM-1047). */
|
||||
|
||||
#ifdef EBCDIC_IGNORING_COMPILER
|
||||
|
||||
#define CHAR_NUL '\000'
|
||||
#define CHAR_HT '\005'
|
||||
#define CHAR_VT '\013'
|
||||
#define CHAR_FF '\014'
|
||||
#define CHAR_CR '\015'
|
||||
#define CHAR_BS '\026'
|
||||
#define CHAR_BEL '\057'
|
||||
|
||||
#define CHAR_SPACE '\100'
|
||||
#define CHAR_EXCLAMATION_MARK '\132'
|
||||
#define CHAR_QUOTATION_MARK '\177'
|
||||
#define CHAR_NUMBER_SIGN '\173'
|
||||
#define CHAR_DOLLAR_SIGN '\133'
|
||||
#define CHAR_PERCENT_SIGN '\154'
|
||||
#define CHAR_AMPERSAND '\120'
|
||||
#define CHAR_APOSTROPHE '\175'
|
||||
#define CHAR_LEFT_PARENTHESIS '\115'
|
||||
#define CHAR_RIGHT_PARENTHESIS '\135'
|
||||
#define CHAR_ASTERISK '\134'
|
||||
#define CHAR_PLUS '\116'
|
||||
#define CHAR_COMMA '\153'
|
||||
#define CHAR_MINUS '\140'
|
||||
#define CHAR_DOT '\113'
|
||||
#define CHAR_SLASH '\141'
|
||||
#define CHAR_0 ((unsigned char)'\xf0')
|
||||
#define CHAR_1 ((unsigned char)'\xf1')
|
||||
#define CHAR_2 ((unsigned char)'\xf2')
|
||||
#define CHAR_3 ((unsigned char)'\xf3')
|
||||
#define CHAR_4 ((unsigned char)'\xf4')
|
||||
#define CHAR_5 ((unsigned char)'\xf5')
|
||||
#define CHAR_6 ((unsigned char)'\xf6')
|
||||
#define CHAR_7 ((unsigned char)'\xf7')
|
||||
#define CHAR_8 ((unsigned char)'\xf8')
|
||||
#define CHAR_9 ((unsigned char)'\xf9')
|
||||
#define CHAR_COLON '\172'
|
||||
#define CHAR_SEMICOLON '\136'
|
||||
#define CHAR_LESS_THAN_SIGN '\114'
|
||||
#define CHAR_EQUALS_SIGN '\176'
|
||||
#define CHAR_GREATER_THAN_SIGN '\156'
|
||||
#define CHAR_QUESTION_MARK '\157'
|
||||
#define CHAR_COMMERCIAL_AT '\174'
|
||||
#define CHAR_A ((unsigned char)'\xc1')
|
||||
#define CHAR_B ((unsigned char)'\xc2')
|
||||
#define CHAR_C ((unsigned char)'\xc3')
|
||||
#define CHAR_D ((unsigned char)'\xc4')
|
||||
#define CHAR_E ((unsigned char)'\xc5')
|
||||
#define CHAR_F ((unsigned char)'\xc6')
|
||||
#define CHAR_G ((unsigned char)'\xc7')
|
||||
#define CHAR_H ((unsigned char)'\xc8')
|
||||
#define CHAR_I ((unsigned char)'\xc9')
|
||||
#define CHAR_J ((unsigned char)'\xd1')
|
||||
#define CHAR_K ((unsigned char)'\xd2')
|
||||
#define CHAR_L ((unsigned char)'\xd3')
|
||||
#define CHAR_M ((unsigned char)'\xd4')
|
||||
#define CHAR_N ((unsigned char)'\xd5')
|
||||
#define CHAR_O ((unsigned char)'\xd6')
|
||||
#define CHAR_P ((unsigned char)'\xd7')
|
||||
#define CHAR_Q ((unsigned char)'\xd8')
|
||||
#define CHAR_R ((unsigned char)'\xd9')
|
||||
#define CHAR_S ((unsigned char)'\xe2')
|
||||
#define CHAR_T ((unsigned char)'\xe3')
|
||||
#define CHAR_U ((unsigned char)'\xe4')
|
||||
#define CHAR_V ((unsigned char)'\xe5')
|
||||
#define CHAR_W ((unsigned char)'\xe6')
|
||||
#define CHAR_X ((unsigned char)'\xe7')
|
||||
#define CHAR_Y ((unsigned char)'\xe8')
|
||||
#define CHAR_Z ((unsigned char)'\xe9')
|
||||
#define CHAR_LEFT_SQUARE_BRACKET ((unsigned char)'\xad')
|
||||
#define CHAR_BACKSLASH ((unsigned char)'\xe0')
|
||||
#define CHAR_RIGHT_SQUARE_BRACKET ((unsigned char)'\xbd')
|
||||
#define CHAR_CIRCUMFLEX_ACCENT '\137'
|
||||
#define CHAR_UNDERSCORE '\155'
|
||||
#define CHAR_GRAVE_ACCENT '\171'
|
||||
#define CHAR_a ((unsigned char)'\x81')
|
||||
#define CHAR_b ((unsigned char)'\x82')
|
||||
#define CHAR_c ((unsigned char)'\x83')
|
||||
#define CHAR_d ((unsigned char)'\x84')
|
||||
#define CHAR_e ((unsigned char)'\x85')
|
||||
#define CHAR_f ((unsigned char)'\x86')
|
||||
#define CHAR_g ((unsigned char)'\x87')
|
||||
#define CHAR_h ((unsigned char)'\x88')
|
||||
#define CHAR_i ((unsigned char)'\x89')
|
||||
#define CHAR_j ((unsigned char)'\x91')
|
||||
#define CHAR_k ((unsigned char)'\x92')
|
||||
#define CHAR_l ((unsigned char)'\x93')
|
||||
#define CHAR_m ((unsigned char)'\x94')
|
||||
#define CHAR_n ((unsigned char)'\x95')
|
||||
#define CHAR_o ((unsigned char)'\x96')
|
||||
#define CHAR_p ((unsigned char)'\x97')
|
||||
#define CHAR_q ((unsigned char)'\x98')
|
||||
#define CHAR_r ((unsigned char)'\x99')
|
||||
#define CHAR_s ((unsigned char)'\xa2')
|
||||
#define CHAR_t ((unsigned char)'\xa3')
|
||||
#define CHAR_u ((unsigned char)'\xa4')
|
||||
#define CHAR_v ((unsigned char)'\xa5')
|
||||
#define CHAR_w ((unsigned char)'\xa6')
|
||||
#define CHAR_x ((unsigned char)'\xa7')
|
||||
#define CHAR_y ((unsigned char)'\xa8')
|
||||
#define CHAR_z ((unsigned char)'\xa9')
|
||||
#define CHAR_LEFT_CURLY_BRACKET ((unsigned char)'\xc0')
|
||||
#define CHAR_VERTICAL_LINE '\117'
|
||||
#define CHAR_RIGHT_CURLY_BRACKET ((unsigned char)'\xd0')
|
||||
#define CHAR_TILDE ((unsigned char)'\xa1')
|
||||
|
||||
#define STR_HT "\005"
|
||||
#define STR_VT "\013"
|
||||
#define STR_FF "\014"
|
||||
#define STR_CR "\015"
|
||||
#define STR_BS "\026"
|
||||
#define STR_BEL "\057"
|
||||
|
||||
#define STR_SPACE "\100"
|
||||
#define STR_EXCLAMATION_MARK "\132"
|
||||
#define STR_QUOTATION_MARK "\177"
|
||||
#define STR_NUMBER_SIGN "\173"
|
||||
#define STR_DOLLAR_SIGN "\133"
|
||||
#define STR_PERCENT_SIGN "\154"
|
||||
#define STR_AMPERSAND "\120"
|
||||
#define STR_APOSTROPHE "\175"
|
||||
#define STR_LEFT_PARENTHESIS "\115"
|
||||
#define STR_RIGHT_PARENTHESIS "\135"
|
||||
#define STR_ASTERISK "\134"
|
||||
#define STR_PLUS "\116"
|
||||
#define STR_COMMA "\153"
|
||||
#define STR_MINUS "\140"
|
||||
#define STR_DOT "\113"
|
||||
#define STR_SLASH "\141"
|
||||
#define STR_0 "\360"
|
||||
#define STR_1 "\361"
|
||||
#define STR_2 "\362"
|
||||
#define STR_3 "\363"
|
||||
#define STR_4 "\364"
|
||||
#define STR_5 "\365"
|
||||
#define STR_6 "\366"
|
||||
#define STR_7 "\367"
|
||||
#define STR_8 "\370"
|
||||
#define STR_9 "\371"
|
||||
#define STR_COLON "\172"
|
||||
#define STR_SEMICOLON "\136"
|
||||
#define STR_LESS_THAN_SIGN "\114"
|
||||
#define STR_EQUALS_SIGN "\176"
|
||||
#define STR_GREATER_THAN_SIGN "\156"
|
||||
#define STR_QUESTION_MARK "\157"
|
||||
#define STR_COMMERCIAL_AT "\174"
|
||||
#define STR_A "\301"
|
||||
#define STR_B "\302"
|
||||
#define STR_C "\303"
|
||||
#define STR_D "\304"
|
||||
#define STR_E "\305"
|
||||
#define STR_F "\306"
|
||||
#define STR_G "\307"
|
||||
#define STR_H "\310"
|
||||
#define STR_I "\311"
|
||||
#define STR_J "\321"
|
||||
#define STR_K "\322"
|
||||
#define STR_L "\323"
|
||||
#define STR_M "\324"
|
||||
#define STR_N "\325"
|
||||
#define STR_O "\326"
|
||||
#define STR_P "\327"
|
||||
#define STR_Q "\330"
|
||||
#define STR_R "\331"
|
||||
#define STR_S "\342"
|
||||
#define STR_T "\343"
|
||||
#define STR_U "\344"
|
||||
#define STR_V "\345"
|
||||
#define STR_W "\346"
|
||||
#define STR_X "\347"
|
||||
#define STR_Y "\350"
|
||||
#define STR_Z "\351"
|
||||
#define STR_LEFT_SQUARE_BRACKET "\255"
|
||||
#define STR_BACKSLASH "\340"
|
||||
#define STR_RIGHT_SQUARE_BRACKET "\275"
|
||||
#define STR_CIRCUMFLEX_ACCENT "\137"
|
||||
#define STR_UNDERSCORE "\155"
|
||||
#define STR_GRAVE_ACCENT "\171"
|
||||
#define STR_a "\201"
|
||||
#define STR_b "\202"
|
||||
#define STR_c "\203"
|
||||
#define STR_d "\204"
|
||||
#define STR_e "\205"
|
||||
#define STR_f "\206"
|
||||
#define STR_g "\207"
|
||||
#define STR_h "\210"
|
||||
#define STR_i "\211"
|
||||
#define STR_j "\221"
|
||||
#define STR_k "\222"
|
||||
#define STR_l "\223"
|
||||
#define STR_m "\224"
|
||||
#define STR_n "\225"
|
||||
#define STR_o "\226"
|
||||
#define STR_p "\227"
|
||||
#define STR_q "\230"
|
||||
#define STR_r "\231"
|
||||
#define STR_s "\242"
|
||||
#define STR_t "\243"
|
||||
#define STR_u "\244"
|
||||
#define STR_v "\245"
|
||||
#define STR_w "\246"
|
||||
#define STR_x "\247"
|
||||
#define STR_y "\250"
|
||||
#define STR_z "\251"
|
||||
#define STR_LEFT_CURLY_BRACKET "\300"
|
||||
#define STR_VERTICAL_LINE "\117"
|
||||
#define STR_RIGHT_CURLY_BRACKET "\320"
|
||||
#define STR_TILDE "\241"
|
||||
|
||||
#else /* EBCDIC_IGNORING_COMPILER */
|
||||
|
||||
/* Otherwise, on a real EBCDIC compiler or an ASCII compiler, we can use simple
|
||||
string and character literals. */
|
||||
|
||||
#ifdef EBCDIC
|
||||
#if 'a' != 0x81
|
||||
#error "EBCDIC character 'a' is not 0x81"
|
||||
#endif
|
||||
#else
|
||||
#if 'a' != 0x61
|
||||
#error "ASCII character 'a' is not 0x61"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define CHAR_NUL '\0'
|
||||
#define CHAR_HT '\t'
|
||||
|
|
@ -922,88 +1123,7 @@ a positive value. */
|
|||
#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_scs0 "scs\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_scan_substring0 "scan_substring\0"
|
||||
|
||||
#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_CASELESS_RESTRICT_RIGHTPAR "CASELESS_RESTRICT)"
|
||||
#define STRING_TURKISH_CASING_RIGHTPAR "TURKISH_CASING)"
|
||||
#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"
|
||||
#endif /* EBCDIC_WITH_ASCII_COMPILER */
|
||||
|
||||
#else /* SUPPORT_UNICODE */
|
||||
|
||||
|
|
@ -1227,6 +1347,9 @@ only. */
|
|||
#define STR_RIGHT_CURLY_BRACKET "\175"
|
||||
#define STR_TILDE "\176"
|
||||
|
||||
#endif /* SUPPORT_UNICODE */
|
||||
|
||||
|
||||
#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"
|
||||
|
|
@ -1311,8 +1434,6 @@ only. */
|
|||
#define STRING_scx STR_s STR_c STR_x
|
||||
|
||||
|
||||
#endif /* SUPPORT_UNICODE */
|
||||
|
||||
/* -------------------- End of character and string names -------------------*/
|
||||
|
||||
/* -------------------- Definitions for compiled patterns -------------------*/
|
||||
|
|
@ -1791,7 +1912,7 @@ 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
|
||||
only in pcre2_printint_inc.h, 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 \
|
||||
|
|
@ -2075,7 +2196,7 @@ 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 unsigned PRIV(utf8_table1_size);
|
||||
extern const int PRIV(utf8_table2)[];
|
||||
extern const int PRIV(utf8_table3)[];
|
||||
extern const uint8_t PRIV(utf8_table4)[];
|
||||
|
|
@ -2110,6 +2231,8 @@ extern const uint8_t PRIV(utf8_table4)[];
|
|||
#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_)
|
||||
#define _pcre2_ebcdic_1047_to_ascii PCRE2_SUFFIX(_pcre2_ebcdic_1047_to_ascii_)
|
||||
#define _pcre2_ascii_to_ebcdic_1047 PCRE2_SUFFIX(_pcre2_ascii_to_ebcdic_1047_)
|
||||
|
||||
extern const uint8_t PRIV(OP_lengths)[];
|
||||
extern const uint32_t PRIV(callout_end_delims)[];
|
||||
|
|
@ -2142,6 +2265,8 @@ 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);
|
||||
extern const uint8_t PRIV(ebcdic_1047_to_ascii)[];
|
||||
extern const uint8_t PRIV(ascii_to_ebcdic_1047)[];
|
||||
|
||||
/* 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
|
||||
|
|
@ -2165,6 +2290,7 @@ is available. */
|
|||
|
||||
#define _pcre2_auto_possessify PCRE2_SUFFIX(_pcre2_auto_possessify_)
|
||||
#define _pcre2_check_escape PCRE2_SUFFIX(_pcre2_check_escape_)
|
||||
#define _pcre2_ckd_smul PCRE2_SUFFIX(_pcre2_ckd_smul_)
|
||||
#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_)
|
||||
|
|
@ -2191,6 +2317,7 @@ 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, uint32_t, BOOL, compile_block *);
|
||||
extern BOOL _pcre2_ckd_smul(PCRE2_SIZE *, int, int);
|
||||
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);
|
||||
|
|
@ -2217,17 +2344,8 @@ extern BOOL _pcre2_xclass(uint32_t, PCRE2_SPTR, const uint8_t *, BOOL);
|
|||
extern BOOL _pcre2_eclass(uint32_t, PCRE2_SPTR, PCRE2_SPTR,
|
||||
const uint8_t *, 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 */
|
||||
|
||||
extern BOOL PRIV(ckd_smul)(PCRE2_SIZE *, int, int);
|
||||
|
||||
#include "pcre2_util.h"
|
||||
|
||||
#endif /* PCRE2_INTERNAL_H_IDEMPOTENT_GUARD */
|
||||
|
|
|
|||
|
|
@ -47,9 +47,16 @@ 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
|
||||
pcre2_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. */
|
||||
pcre2_printint_inc.h 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.
|
||||
|
||||
You can also include pcre2_intmodedep.h with PCRE2_CODE_UNIT_WIDTH defined to
|
||||
zero in order to simply clear the previous macros. */
|
||||
|
||||
#ifndef PCRE2_CODE_UNIT_WIDTH
|
||||
#error PCRE2_CODE_UNIT_WIDTH must be defined
|
||||
#endif
|
||||
|
||||
#undef ACROSSCHAR
|
||||
#undef BACKCHAR
|
||||
|
|
@ -81,9 +88,14 @@ just to undefine them all. */
|
|||
#undef PUTINC
|
||||
#undef TABLE_GET
|
||||
|
||||
/*************************************************
|
||||
* MACROS *
|
||||
*************************************************/
|
||||
|
||||
/* Macros may be undefined and re-defined if the same file handles multiple
|
||||
bit-widths. */
|
||||
|
||||
/* -------------------------- MACROS ----------------------------- */
|
||||
#if PCRE2_CODE_UNIT_WIDTH != 0
|
||||
|
||||
/* 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,
|
||||
|
|
@ -97,11 +109,23 @@ 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. */
|
||||
|
||||
#ifndef CONFIGURED_LINK_SIZE
|
||||
#if LINK_SIZE == 2
|
||||
#define CONFIGURED_LINK_SIZE 2
|
||||
#elif LINK_SIZE == 3
|
||||
#define CONFIGURED_LINK_SIZE 3
|
||||
#elif LINK_SIZE == 4
|
||||
#define CONFIGURED_LINK_SIZE 4
|
||||
#else
|
||||
#error LINK_SIZE must be 2, 3, or 4
|
||||
#endif
|
||||
#endif /* CONFIGURED_LINK_SIZE */
|
||||
|
||||
/* ------------------- 8-bit support ------------------ */
|
||||
|
||||
#if PCRE2_CODE_UNIT_WIDTH == 8
|
||||
|
||||
#if LINK_SIZE == 2
|
||||
#if CONFIGURED_LINK_SIZE == 2
|
||||
#define PUT(a,n,d) \
|
||||
(a[n] = (PCRE2_UCHAR)((d) >> 8)), \
|
||||
(a[(n)+1] = (PCRE2_UCHAR)((d) & 255))
|
||||
|
|
@ -109,7 +133,7 @@ values of 3 or 4 are also supported. */
|
|||
(unsigned int)(((a)[n] << 8) | (a)[(n)+1])
|
||||
#define MAX_PATTERN_SIZE (1 << 16)
|
||||
|
||||
#elif LINK_SIZE == 3
|
||||
#elif CONFIGURED_LINK_SIZE == 3
|
||||
#define PUT(a,n,d) \
|
||||
(a[n] = (PCRE2_UCHAR)((d) >> 16)), \
|
||||
(a[(n)+1] = (PCRE2_UCHAR)((d) >> 8)), \
|
||||
|
|
@ -118,7 +142,7 @@ values of 3 or 4 are also supported. */
|
|||
(unsigned int)(((a)[n] << 16) | ((a)[(n)+1] << 8) | (a)[(n)+2])
|
||||
#define MAX_PATTERN_SIZE (1 << 24)
|
||||
|
||||
#elif LINK_SIZE == 4
|
||||
#elif CONFIGURED_LINK_SIZE == 4
|
||||
#define PUT(a,n,d) \
|
||||
(a[n] = (PCRE2_UCHAR)((d) >> 24)), \
|
||||
(a[(n)+1] = (PCRE2_UCHAR)((d) >> 16)), \
|
||||
|
|
@ -128,8 +152,6 @@ values of 3 or 4 are also supported. */
|
|||
(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
|
||||
|
||||
|
||||
|
|
@ -137,7 +159,7 @@ values of 3 or 4 are also supported. */
|
|||
|
||||
#elif PCRE2_CODE_UNIT_WIDTH == 16
|
||||
|
||||
#if LINK_SIZE == 2
|
||||
#if CONFIGURED_LINK_SIZE == 2
|
||||
#undef LINK_SIZE
|
||||
#define LINK_SIZE 1
|
||||
#define PUT(a,n,d) \
|
||||
|
|
@ -146,7 +168,7 @@ values of 3 or 4 are also supported. */
|
|||
(a[n])
|
||||
#define MAX_PATTERN_SIZE (1 << 16)
|
||||
|
||||
#elif LINK_SIZE == 3 || LINK_SIZE == 4
|
||||
#elif CONFIGURED_LINK_SIZE == 3 || CONFIGURED_LINK_SIZE == 4
|
||||
#undef LINK_SIZE
|
||||
#define LINK_SIZE 2
|
||||
#define PUT(a,n,d) \
|
||||
|
|
@ -156,8 +178,6 @@ values of 3 or 4 are also supported. */
|
|||
(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
|
||||
|
||||
|
||||
|
|
@ -194,7 +214,7 @@ arithmetic results in a signed value. Hence the cast. */
|
|||
#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 */
|
||||
#elif PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32
|
||||
#define IMM2_SIZE 1
|
||||
#define GET2(a,n) a[n]
|
||||
#define PUT2(a,n,d) a[n] = d
|
||||
|
|
@ -219,7 +239,7 @@ check is needed before accessing these tables. */
|
|||
#define CHMAX_255(c) TRUE
|
||||
#endif /* SUPPORT_UNICODE */
|
||||
|
||||
#else /* Code units are 16 or 32 bits */
|
||||
#elif PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32
|
||||
#define CHMAX_255(c) ((c) <= 255u)
|
||||
#define MAX_255(c) ((c) <= 255u)
|
||||
#define MAX_MARK ((1u << 16) - 1)
|
||||
|
|
@ -285,7 +305,7 @@ UTF support is omitted, we don't even define them. */
|
|||
|
||||
#define HAS_EXTRALEN(c) HASUTF8EXTRALEN(c)
|
||||
|
||||
/* Returns with the additional number of characters if IS_MULTICHAR(c) is TRUE.
|
||||
/* Returns with the additional number of characters if HAS_EXTRALEN(c) is TRUE.
|
||||
Otherwise it has an undefined behaviour. */
|
||||
|
||||
#define GET_EXTRALEN(c) (PRIV(utf8_table4)[(c) & 0x3fu])
|
||||
|
|
@ -371,7 +391,7 @@ because almost all calls are already within a block of UTF-8 only code. */
|
|||
|
||||
#define HAS_EXTRALEN(c) (((c) & 0xfc00u) == 0xd800u)
|
||||
|
||||
/* Returns with the additional number of characters if IS_MULTICHAR(c) is TRUE.
|
||||
/* Returns with the additional number of characters if HAS_EXTRALEN(c) is TRUE.
|
||||
Otherwise it has an undefined behaviour. */
|
||||
|
||||
#define GET_EXTRALEN(c) 1
|
||||
|
|
@ -466,7 +486,7 @@ code. */
|
|||
|
||||
/* ------------------- 32-bit support ------------------ */
|
||||
|
||||
#else
|
||||
#elif PCRE2_CODE_UNIT_WIDTH == 32
|
||||
|
||||
/* These are trivial for the 32-bit library, since all UTF-32 characters fit
|
||||
into one PCRE2_UCHAR unit. */
|
||||
|
|
@ -547,6 +567,32 @@ These are all no-ops since all UTF-32 characters fit into one PCRE2_UCHAR. */
|
|||
#define PUTINC(a,n,d) PUT(a,n,d), a += LINK_SIZE
|
||||
#define PUT2INC(a,n,d) PUT2(a,n,d), a += IMM2_SIZE
|
||||
|
||||
#endif /* PCRE2_CODE_UNIT_WIDTH != 0 */
|
||||
|
||||
|
||||
|
||||
/*************************************************
|
||||
* STRUCTURES *
|
||||
*************************************************/
|
||||
|
||||
/* We need a more complex include guard than usual, because the file can be
|
||||
included once for each bit-width to define the various structures. */
|
||||
|
||||
#if PCRE2_CODE_UNIT_WIDTH == 8 && !defined PCRE2_INTMODEDEP_IDEMPOTENT_GUARD_8
|
||||
#define PCRE2_INTMODEDEP_IDEMPOTENT_GUARD_8
|
||||
#define PCRE2_INTMODEDEP_CAN_DEFINE
|
||||
#endif
|
||||
#if PCRE2_CODE_UNIT_WIDTH == 16 && !defined PCRE2_INTMODEDEP_IDEMPOTENT_GUARD_16
|
||||
#define PCRE2_INTMODEDEP_IDEMPOTENT_GUARD_16
|
||||
#define PCRE2_INTMODEDEP_CAN_DEFINE
|
||||
#endif
|
||||
#if PCRE2_CODE_UNIT_WIDTH == 32 && !defined PCRE2_INTMODEDEP_IDEMPOTENT_GUARD_32
|
||||
#define PCRE2_INTMODEDEP_IDEMPOTENT_GUARD_32
|
||||
#define PCRE2_INTMODEDEP_CAN_DEFINE
|
||||
#endif
|
||||
|
||||
#ifdef PCRE2_INTMODEDEP_CAN_DEFINE
|
||||
#undef PCRE2_INTMODEDEP_CAN_DEFINE
|
||||
|
||||
/* ----------------------- HIDDEN STRUCTURES ----------------------------- */
|
||||
|
||||
|
|
@ -624,7 +670,7 @@ have 16-bit arguments in 8-bit and 16-bit modes, so we need no more than a
|
|||
#define CODE_BLOCKSIZE_TYPE PCRE2_SIZE
|
||||
|
||||
#undef LOOKBEHIND_MAX
|
||||
#define LOOKBEHIND_MAX UINT16_MAX
|
||||
#define LOOKBEHIND_MAX ((int)UINT16_MAX)
|
||||
|
||||
typedef struct pcre2_real_code {
|
||||
pcre2_memctl memctl; /* Memory control fields */
|
||||
|
|
@ -672,12 +718,14 @@ typedef struct pcre2_real_match_data {
|
|||
struct heapframe *heapframes; /* Backtracking frames heap memory */
|
||||
PCRE2_SIZE heapframes_size; /* Malloc-ed size */
|
||||
PCRE2_SIZE subject_length; /* Subject length */
|
||||
PCRE2_SIZE start_offset; /* Offset to start of search */
|
||||
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 */
|
||||
uint32_t options; /* Options passed in to the match call */
|
||||
int rc; /* The return code from the match */
|
||||
PCRE2_SIZE ovector[131072]; /* Must be last in the structure */
|
||||
} pcre2_real_match_data;
|
||||
|
|
@ -718,20 +766,31 @@ typedef struct branch_chain {
|
|||
} branch_chain;
|
||||
|
||||
/* Structure for building a list of named groups during the first pass of
|
||||
compiling. */
|
||||
compiling. When a duplicate name is stored in the list, its name is set to
|
||||
the name of the first entry with the same name, and its length is set to 0. */
|
||||
|
||||
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 */
|
||||
uint16_t hash_dup; /* A concatenation of a 15 bit hash code and
|
||||
a singe bit which represents duplication */
|
||||
} named_group;
|
||||
|
||||
/* Structure for storing compile time data. */
|
||||
|
||||
typedef struct compile_data {
|
||||
struct compile_data *next; /* Next compile data */
|
||||
#ifdef PCRE2_DEBUG
|
||||
uint8_t type; /* Debug only type of the data */
|
||||
#endif
|
||||
} compile_data;
|
||||
|
||||
/* Structure for caching sorted ranges. This improves the performance
|
||||
of translating META code to byte code. */
|
||||
|
||||
typedef struct class_ranges {
|
||||
struct class_ranges *next; /* Next class ranges */
|
||||
compile_data header; /* Common header */
|
||||
size_t char_lists_size; /* Total size of encoded char lists */
|
||||
size_t char_lists_start; /* Start offset of encoded char lists */
|
||||
uint16_t range_list_size; /* Size of ranges array */
|
||||
|
|
@ -739,6 +798,14 @@ typedef struct class_ranges {
|
|||
/* Followed by the list of ranges (start/end pairs) */
|
||||
} class_ranges;
|
||||
|
||||
/* Structure for sorted recurse arguments. */
|
||||
|
||||
typedef struct recurse_arguments {
|
||||
compile_data header; /* Common header */
|
||||
size_t size; /* Total size */
|
||||
size_t skip_size; /* Space consumed by arguments */
|
||||
} recurse_arguments;
|
||||
|
||||
typedef union class_bits_storage {
|
||||
uint8_t classbits[32];
|
||||
uint32_t classwords[8];
|
||||
|
|
@ -789,9 +856,9 @@ typedef struct compile_block {
|
|||
BOOL had_pruneorskip; /* (*PRUNE) or (*SKIP) encountered */
|
||||
BOOL had_recurse; /* Had a pattern recursion or subroutine call */
|
||||
BOOL dupnames; /* Duplicate names exist */
|
||||
compile_data *first_data; /* First item in the compile data list */
|
||||
compile_data *last_data; /* Last item in the compile data list */
|
||||
#ifdef SUPPORT_WIDE_CHARS
|
||||
class_ranges *cranges; /* First class range. */
|
||||
class_ranges *next_cranges; /* Next class range. */
|
||||
size_t char_lists_size; /* Current size of character lists */
|
||||
#endif
|
||||
} compile_block;
|
||||
|
|
@ -902,7 +969,9 @@ typedef struct match_block {
|
|||
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 hasbsk; /* Pattern contains \K */
|
||||
BOOL allowemptypartial; /* Allow empty hard partial */
|
||||
BOOL allowlookaroundbsk; /* Allow \K within lookarounds */
|
||||
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 */
|
||||
|
|
@ -970,4 +1039,6 @@ typedef struct dfa_match_block {
|
|||
|
||||
#endif /* PCRE2_PCRE2TEST */
|
||||
|
||||
#endif /* PCRE2_INTMODEDEP_CAN_DEFINE */
|
||||
|
||||
/* End of pcre2_intmodedep.h */
|
||||
|
|
|
|||
|
|
@ -519,6 +519,8 @@ BOOL has_cmov, last_range_set;
|
|||
sljit_u32 category_list = 0;
|
||||
sljit_u32 items;
|
||||
int typereg = TMP1;
|
||||
#else
|
||||
(void)c; /* Avoid compiler warning. */
|
||||
#endif /* SUPPORT_UNICODE */
|
||||
|
||||
SLJIT_ASSERT(common->locals_size >= SSIZE_OF(sw));
|
||||
|
|
@ -568,7 +570,7 @@ while (*cc == XCL_PROP || *cc == XCL_NOTPROP)
|
|||
break;
|
||||
}
|
||||
compares++;
|
||||
/* Fall through */
|
||||
PCRE2_FALLTHROUGH /* Fall through */
|
||||
|
||||
case PT_SC:
|
||||
status |= XCLASS_HAS_SCRIPT;
|
||||
|
|
@ -696,13 +698,11 @@ if (status & XCLASS_NEEDS_UCD)
|
|||
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);
|
||||
sljit_emit_op2_shift(compiler, SLJIT_ADD | SLJIT_SHL_IMM | SLJIT_SRC2_UNDEFINED, TMP1, 0, TMP1, 0, TMP2, 0, UCD_BLOCK_SHIFT);
|
||||
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);
|
||||
sljit_emit_op2_shift(compiler, SLJIT_ADD | SLJIT_SHL_IMM | SLJIT_SRC2_UNDEFINED, TMP2, 0, TMP2, 0, TMP2, 0, 1);
|
||||
OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 2);
|
||||
OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, TMP1, 0);
|
||||
|
||||
ccbegin = cc;
|
||||
|
||||
|
|
@ -768,7 +768,7 @@ if (status & XCLASS_NEEDS_UCD)
|
|||
case PT_SCX:
|
||||
if (cc[-1] == XCL_NOTPROP)
|
||||
break;
|
||||
/* Fall through */
|
||||
PCRE2_FALLTHROUGH /* Fall through */
|
||||
|
||||
case PT_SC:
|
||||
compares--;
|
||||
|
|
@ -1104,7 +1104,7 @@ if (ranges.range_count >= 6)
|
|||
|
||||
depth = 0;
|
||||
first_item = 0;
|
||||
last_item = ranges.range_count - 2;
|
||||
last_item = (sljit_u32)(ranges.range_count - 2);
|
||||
has_cmov = sljit_has_cpu_feature(SLJIT_HAS_CMOV) != 0;
|
||||
|
||||
while (TRUE)
|
||||
|
|
@ -1486,7 +1486,7 @@ 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;
|
||||
int lgb = 0, rgb, ricount;
|
||||
PCRE2_SPTR prevcc, endcc, bptr;
|
||||
BOOL first = TRUE;
|
||||
BOOL was_ep_ZWJ = FALSE;
|
||||
|
|
@ -1569,7 +1569,7 @@ static PCRE2_SPTR SLJIT_FUNC do_extuni_utf_invalid(jit_arguments *args, PCRE2_SP
|
|||
{
|
||||
PCRE2_SPTR start_subject = args->begin;
|
||||
PCRE2_SPTR end_subject = args->end;
|
||||
int lgb, rgb, ricount;
|
||||
int lgb = 0, rgb, ricount;
|
||||
PCRE2_SPTR prevcc, endcc, bptr;
|
||||
BOOL first = TRUE;
|
||||
BOOL was_ep_ZWJ = FALSE;
|
||||
|
|
@ -1964,9 +1964,9 @@ switch(type)
|
|||
detect_partial_match(common, backtracks);
|
||||
|
||||
if (type == OP_NOT_HSPACE)
|
||||
read_char(common, 0x9, 0x3000, backtracks, READ_CHAR_UPDATE_STR_PTR);
|
||||
read_char(common, 0x1, 0x3000, backtracks, READ_CHAR_UPDATE_STR_PTR);
|
||||
else
|
||||
read_char(common, 0x9, 0x3000, NULL, 0);
|
||||
read_char(common, 0x1, 0x3000, NULL, 0);
|
||||
|
||||
add_jump(compiler, &common->hspace, JUMP(SLJIT_FAST_CALL));
|
||||
sljit_set_current_flags(compiler, SLJIT_SET_Z);
|
||||
|
|
@ -1979,9 +1979,9 @@ switch(type)
|
|||
detect_partial_match(common, backtracks);
|
||||
|
||||
if (type == OP_NOT_VSPACE)
|
||||
read_char(common, 0xa, 0x2029, backtracks, READ_CHAR_UPDATE_STR_PTR);
|
||||
read_char(common, 0x1, 0x2029, backtracks, READ_CHAR_UPDATE_STR_PTR);
|
||||
else
|
||||
read_char(common, 0xa, 0x2029, NULL, 0);
|
||||
read_char(common, 0x1, 0x2029, NULL, 0);
|
||||
|
||||
add_jump(compiler, &common->vspace, JUMP(SLJIT_FAST_CALL));
|
||||
sljit_set_current_flags(compiler, SLJIT_SET_Z);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -99,9 +99,8 @@ pcre2_jit_match(const pcre2_code *code, PCRE2_SPTR subject, PCRE2_SIZE length,
|
|||
(void)length;
|
||||
(void)start_offset;
|
||||
(void)options;
|
||||
(void)match_data;
|
||||
(void)mcontext;
|
||||
return PCRE2_ERROR_JIT_BADOPTION;
|
||||
return match_data->rc = PCRE2_ERROR_JIT_BADOPTION;
|
||||
|
||||
#else /* SUPPORT_JIT */
|
||||
|
||||
|
|
@ -124,7 +123,7 @@ else if ((options & PCRE2_PARTIAL_SOFT) != 0)
|
|||
index = 1;
|
||||
|
||||
if (functions == NULL || functions->executable_funcs[index] == NULL)
|
||||
return PCRE2_ERROR_JIT_BADOPTION;
|
||||
return match_data->rc = PCRE2_ERROR_JIT_BADOPTION;
|
||||
|
||||
/* Sanity checks should be handled by pcre2_match. */
|
||||
arguments.str = subject + start_offset;
|
||||
|
|
@ -176,14 +175,17 @@ else
|
|||
if (rc > (int)oveccount)
|
||||
rc = 0;
|
||||
match_data->code = re;
|
||||
match_data->subject = (rc >= 0 || rc == PCRE2_ERROR_PARTIAL)? subject : NULL;
|
||||
match_data->subject =
|
||||
(rc >= 0 || rc == PCRE2_ERROR_NOMATCH || rc == PCRE2_ERROR_PARTIAL)? subject : NULL;
|
||||
match_data->subject_length = length;
|
||||
match_data->start_offset = start_offset;
|
||||
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;
|
||||
match_data->options = options;
|
||||
|
||||
#if defined(__has_feature)
|
||||
#if __has_feature(memory_sanitizer)
|
||||
|
|
@ -197,4 +199,4 @@ return match_data->rc;
|
|||
#endif /* SUPPORT_JIT */
|
||||
}
|
||||
|
||||
/* End of pcre2_jit_match.c */
|
||||
/* End of pcre2_jit_match_inc.h */
|
||||
|
|
@ -231,4 +231,4 @@ return executable_sizes[0] + executable_sizes[1] + executable_sizes[2];
|
|||
#endif
|
||||
}
|
||||
|
||||
/* End of pcre2_jit_misc.c */
|
||||
/* End of pcre2_jit_misc_inc.h */
|
||||
|
|
@ -1,354 +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
|
||||
|
||||
#if (defined(__GNUC__) && defined(__SANITIZE_ADDRESS__) && __SANITIZE_ADDRESS__ ) \
|
||||
|| (defined(__clang__) \
|
||||
&& ((__clang_major__ == 3 && __clang_minor__ >= 3) || (__clang_major__ > 3)))
|
||||
__attribute__((no_sanitize_address))
|
||||
#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;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -45,13 +45,13 @@ 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"
|
||||
#include "pcre2_internal.h"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*************************************************
|
||||
* Create PCRE2 character tables *
|
||||
*************************************************/
|
||||
|
|
@ -64,14 +64,15 @@ 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
|
||||
Arguments: pointers to character-transforming functions when PCRE2_DFTABLES is
|
||||
defined;
|
||||
else a PCRE2 general context or NULL
|
||||
Returns: pointer to the contiguous block of data
|
||||
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)
|
||||
static const uint8_t *maketables(int (*charfn_to)(int), int (*charfn_from)(int))
|
||||
{
|
||||
uint8_t *yield = (uint8_t *)malloc(TABLES_LENGTH);
|
||||
|
||||
|
|
@ -82,6 +83,9 @@ 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));
|
||||
|
||||
#define charfn_to(c) (c)
|
||||
#define charfn_from(c) (c)
|
||||
#endif /* PCRE2_DFTABLES */
|
||||
|
||||
int i;
|
||||
|
|
@ -92,13 +96,18 @@ p = yield;
|
|||
|
||||
/* First comes the lower casing table */
|
||||
|
||||
for (i = 0; i < 256; i++) *p++ = tolower(i);
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
int c = charfn_from(tolower(charfn_to(i)));
|
||||
*p++ = (c < 256)? c : i;
|
||||
}
|
||||
|
||||
/* Next the case-flipping table */
|
||||
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
int c = islower(i)? toupper(i) : tolower(i);
|
||||
int c = charfn_from(islower(charfn_to(i))? toupper(charfn_to(i))
|
||||
: tolower(charfn_to(i)));
|
||||
*p++ = (c < 256)? c : i;
|
||||
}
|
||||
|
||||
|
|
@ -118,17 +127,17 @@ 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);
|
||||
if (isdigit(charfn_to(i))) p[cbit_digit + i/8] |= 1u << (i&7);
|
||||
if (isupper(charfn_to(i))) p[cbit_upper + i/8] |= 1u << (i&7);
|
||||
if (islower(charfn_to(i))) p[cbit_lower + i/8] |= 1u << (i&7);
|
||||
if (isalnum(charfn_to(i))) p[cbit_word + i/8] |= 1u << (i&7);
|
||||
if (i == CHAR_UNDERSCORE) p[cbit_word + i/8] |= 1u << (i&7);
|
||||
if (isspace(charfn_to(i))) p[cbit_space + i/8] |= 1u << (i&7);
|
||||
if (isxdigit(charfn_to(i))) p[cbit_xdigit + i/8] |= 1u << (i&7);
|
||||
if (isgraph(charfn_to(i))) p[cbit_graph + i/8] |= 1u << (i&7);
|
||||
if (isprint(charfn_to(i))) p[cbit_print + i/8] |= 1u << (i&7);
|
||||
if (ispunct(charfn_to(i))) p[cbit_punct + i/8] |= 1u << (i&7);
|
||||
if (iscntrl(charfn_to(i))) p[cbit_cntrl + i/8] |= 1u << (i&7);
|
||||
}
|
||||
p += cbit_length;
|
||||
|
||||
|
|
@ -140,11 +149,11 @@ 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;
|
||||
if (isspace(charfn_to(i))) x += ctype_space;
|
||||
if (isalpha(charfn_to(i))) x += ctype_letter;
|
||||
if (islower(charfn_to(i))) x += ctype_lcletter;
|
||||
if (isdigit(charfn_to(i))) x += ctype_digit;
|
||||
if (isalnum(charfn_to(i)) || i == CHAR_UNDERSCORE) x += ctype_word;
|
||||
*p++ = x;
|
||||
}
|
||||
|
||||
|
|
@ -152,6 +161,9 @@ return yield;
|
|||
}
|
||||
|
||||
#ifndef PCRE2_DFTABLES /* Compiling the library */
|
||||
#undef charfn_to
|
||||
#undef charfn_from
|
||||
|
||||
PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION
|
||||
pcre2_maketables_free(pcre2_general_context *gcontext, const uint8_t *tables)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -39,12 +39,10 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
*/
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "pcre2_internal.h"
|
||||
|
||||
|
||||
|
||||
/* These defines enable debugging code */
|
||||
|
||||
/* #define DEBUG_FRAMES_DISPLAY */
|
||||
|
|
@ -367,6 +365,10 @@ PCRE2_SIZE length;
|
|||
PCRE2_SPTR eptr;
|
||||
PCRE2_SPTR eptr_start;
|
||||
|
||||
#ifndef SUPPORT_UNICODE
|
||||
(void)caseopts; /* Avoid compiler warning. */
|
||||
#endif
|
||||
|
||||
/* Deal with an unset group. The default is no match, but there is an option to
|
||||
match an empty string. */
|
||||
|
||||
|
|
@ -385,6 +387,7 @@ if (offset >= Foffset_top || Fovector[offset] == PCRE2_UNSET)
|
|||
eptr = eptr_start = Feptr;
|
||||
p = mb->start_subject + Fovector[offset];
|
||||
length = Fovector[offset+1] - Fovector[offset];
|
||||
PCRE2_ASSERT(eptr <= mb->end_subject);
|
||||
|
||||
if (caseless)
|
||||
{
|
||||
|
|
@ -404,7 +407,7 @@ if (caseless)
|
|||
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. */
|
||||
wrong). UCP uses Unicode properties but without UTF encoding. */
|
||||
|
||||
while (p < endptr)
|
||||
{
|
||||
|
|
@ -483,8 +486,8 @@ else
|
|||
|
||||
else
|
||||
{
|
||||
if ((PCRE2_SIZE)(mb->end_subject - eptr) < length) return 1; /* Partial */
|
||||
if (memcmp(p, eptr, CU2BYTES(length)) != 0) return -1; /* No match */
|
||||
if ((PCRE2_SIZE)(mb->end_subject - eptr) < length ||
|
||||
memcmp(p, eptr, CU2BYTES(length)) != 0) return -1; /* No match */
|
||||
eptr += length;
|
||||
}
|
||||
}
|
||||
|
|
@ -495,6 +498,75 @@ return 0; /* Match */
|
|||
|
||||
|
||||
|
||||
/*************************************************
|
||||
* Restore offsets after a recurse *
|
||||
*************************************************/
|
||||
|
||||
/* This function restores the ovector values when
|
||||
a recursive block reaches its end, and the triggering
|
||||
recurse has and argument list.
|
||||
|
||||
Arguments:
|
||||
F the current backtracking frame pointer
|
||||
P the previous backtracking frame pointer
|
||||
*/
|
||||
|
||||
static void
|
||||
recurse_update_offsets(heapframe *F, heapframe *P)
|
||||
{
|
||||
PCRE2_SIZE *dst = F->ovector;
|
||||
PCRE2_SIZE *src = P->ovector;
|
||||
/* The first bracket has offset 2, because
|
||||
offset 0 is reserved for the full match. */
|
||||
PCRE2_SIZE offset = 2;
|
||||
PCRE2_SIZE offset_top = Foffset_top + 2;
|
||||
PCRE2_SIZE diff;
|
||||
PCRE2_SPTR ecode = Fecode;
|
||||
|
||||
do
|
||||
{
|
||||
diff = (GET2(ecode, 1) << 1) - offset;
|
||||
ecode += 1 + IMM2_SIZE;
|
||||
|
||||
if (offset + diff >= offset_top)
|
||||
{
|
||||
/* Some OP_CREF opcodes are not
|
||||
processed, they must be skipped. */
|
||||
while (*ecode == OP_CREF) ecode += 1 + IMM2_SIZE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (diff == 2)
|
||||
{
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[1];
|
||||
}
|
||||
else if (diff >= 4)
|
||||
memcpy(dst, src, diff * sizeof(PCRE2_SIZE));
|
||||
|
||||
/* Skip the unmodified entry. */
|
||||
diff += 2;
|
||||
offset += diff;
|
||||
dst += diff;
|
||||
src += diff;
|
||||
}
|
||||
while (*ecode == OP_CREF);
|
||||
|
||||
diff = offset_top - offset;
|
||||
if (diff == 2)
|
||||
{
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[1];
|
||||
}
|
||||
else if (diff >= 4)
|
||||
memcpy(dst, src, diff * sizeof(PCRE2_SIZE));
|
||||
|
||||
Fecode = ecode;
|
||||
Foffset_top = (offset <= P->offset_top) ? P->offset_top : (offset - 2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*******************************************************************************
|
||||
"Recursion" in the match() function
|
||||
|
|
@ -898,7 +970,7 @@ fprintf(stderr, "++ %2ld op=%3d %s\n", Fecode - mb->start_code, *Fecode,
|
|||
Fecode += 1 + LINK_SIZE;
|
||||
continue;
|
||||
}
|
||||
/* Fall through */
|
||||
PCRE2_FALLTHROUGH /* Fall through */
|
||||
|
||||
/* OP_END itself can never be reached within a recursion because that is
|
||||
picked up when the OP_KET that always precedes OP_END is reached. */
|
||||
|
|
@ -938,11 +1010,28 @@ fprintf(stderr, "++ %2ld op=%3d %s\n", Fecode - mb->start_code, *Fecode,
|
|||
}
|
||||
|
||||
#ifdef DEBUG_SHOW_OPS
|
||||
fprintf(stderr, "++ Failed ACCEPT not at end (endanchnored set)\n");
|
||||
fprintf(stderr, "++ Failed ACCEPT not at end (endanchored set)\n");
|
||||
#endif
|
||||
return MATCH_NOMATCH; /* (*ACCEPT) */
|
||||
}
|
||||
|
||||
/* Fail if we detect that the start position was moved to be either after
|
||||
the end position (\K in lookahead) or before the start offset (\K in
|
||||
lookbehind). If this occurs, the pattern must have used \K in a somewhat
|
||||
sneaky way (e.g. by pattern recursion), because if the \K is actually
|
||||
syntactically inside the lookaround, it's blocked at compile-time. */
|
||||
|
||||
if (Fstart_match < mb->start_subject + mb->start_offset ||
|
||||
Fstart_match > Feptr)
|
||||
{
|
||||
/* The \K expression is fairly rare. We assert it was used so that we
|
||||
catch any unexpected invalid data in start_match. */
|
||||
PCRE2_ASSERT(mb->hasbsk);
|
||||
|
||||
if (!mb->allowlookaroundbsk)
|
||||
return PCRE2_ERROR_BAD_BACKSLASH_K;
|
||||
}
|
||||
|
||||
/* 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
|
||||
|
|
@ -982,7 +1071,7 @@ fprintf(stderr, "++ %2ld op=%3d %s\n", Fecode - mb->start_code, *Fecode,
|
|||
mb->hitend = TRUE;
|
||||
if (mb->partial > 1) return PCRE2_ERROR_PARTIAL;
|
||||
}
|
||||
/* Fall through */
|
||||
PCRE2_FALLTHROUGH /* Fall through */
|
||||
|
||||
/* Match any single character whatsoever. */
|
||||
|
||||
|
|
@ -2779,9 +2868,11 @@ fprintf(stderr, "++ %2ld op=%3d %s\n", Fecode - mb->start_code, *Fecode,
|
|||
|
||||
/* This should never occur */
|
||||
|
||||
/* LCOV_EXCL_START */
|
||||
default:
|
||||
PCRE2_DEBUG_UNREACHABLE();
|
||||
return PCRE2_ERROR_INTERNAL;
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
Fecode += 3;
|
||||
|
|
@ -3130,9 +3221,11 @@ fprintf(stderr, "++ %2ld op=%3d %s\n", Fecode - mb->start_code, *Fecode,
|
|||
|
||||
/* This should not occur */
|
||||
|
||||
/* LCOV_EXCL_START */
|
||||
default:
|
||||
PCRE2_DEBUG_UNREACHABLE();
|
||||
return PCRE2_ERROR_INTERNAL;
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3406,9 +3499,11 @@ fprintf(stderr, "++ %2ld op=%3d %s\n", Fecode - mb->start_code, *Fecode,
|
|||
}
|
||||
break;
|
||||
|
||||
/* LCOV_EXCL_START */
|
||||
default:
|
||||
PCRE2_DEBUG_UNREACHABLE();
|
||||
return PCRE2_ERROR_INTERNAL;
|
||||
/* LCOV_EXCL_STOP */
|
||||
} /* End switch(Lctype) */
|
||||
|
||||
else
|
||||
|
|
@ -3659,9 +3754,11 @@ fprintf(stderr, "++ %2ld op=%3d %s\n", Fecode - mb->start_code, *Fecode,
|
|||
}
|
||||
break;
|
||||
|
||||
/* LCOV_EXCL_START */
|
||||
default:
|
||||
PCRE2_DEBUG_UNREACHABLE();
|
||||
return PCRE2_ERROR_INTERNAL;
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3945,9 +4042,12 @@ fprintf(stderr, "++ %2ld op=%3d %s\n", Fecode - mb->start_code, *Fecode,
|
|||
PCRE2_UNREACHABLE(); /* Control never reaches here */
|
||||
|
||||
/* This should never occur */
|
||||
|
||||
/* LCOV_EXCL_START */
|
||||
default:
|
||||
PCRE2_DEBUG_UNREACHABLE();
|
||||
return PCRE2_ERROR_INTERNAL;
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4100,9 +4200,11 @@ fprintf(stderr, "++ %2ld op=%3d %s\n", Fecode - mb->start_code, *Fecode,
|
|||
RRETURN(MATCH_NOMATCH);
|
||||
break;
|
||||
|
||||
/* LCOV_EXCL_START */
|
||||
default:
|
||||
PCRE2_DEBUG_UNREACHABLE();
|
||||
return PCRE2_ERROR_INTERNAL;
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4245,9 +4347,11 @@ fprintf(stderr, "++ %2ld op=%3d %s\n", Fecode - mb->start_code, *Fecode,
|
|||
RRETURN(MATCH_NOMATCH);
|
||||
break;
|
||||
|
||||
/* LCOV_EXCL_START */
|
||||
default:
|
||||
PCRE2_DEBUG_UNREACHABLE();
|
||||
return PCRE2_ERROR_INTERNAL;
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4514,9 +4618,11 @@ fprintf(stderr, "++ %2ld op=%3d %s\n", Fecode - mb->start_code, *Fecode,
|
|||
}
|
||||
break;
|
||||
|
||||
/* LCOV_EXCL_START */
|
||||
default:
|
||||
PCRE2_DEBUG_UNREACHABLE();
|
||||
return PCRE2_ERROR_INTERNAL;
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
/* Feptr is now past the end of the maximum run */
|
||||
|
|
@ -4833,9 +4939,11 @@ fprintf(stderr, "++ %2ld op=%3d %s\n", Fecode - mb->start_code, *Fecode,
|
|||
}
|
||||
break;
|
||||
|
||||
/* LCOV_EXCL_START */
|
||||
default:
|
||||
PCRE2_DEBUG_UNREACHABLE();
|
||||
return PCRE2_ERROR_INTERNAL;
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
if (reptype == REPTYPE_POS) continue; /* No backtracking */
|
||||
|
|
@ -5091,9 +5199,11 @@ fprintf(stderr, "++ %2ld op=%3d %s\n", Fecode - mb->start_code, *Fecode,
|
|||
}
|
||||
break;
|
||||
|
||||
/* LCOV_EXCL_START */
|
||||
default:
|
||||
PCRE2_DEBUG_UNREACHABLE();
|
||||
return PCRE2_ERROR_INTERNAL;
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
if (reptype == REPTYPE_POS) continue; /* No backtracking */
|
||||
|
|
@ -5824,6 +5934,9 @@ fprintf(stderr, "++ %2ld op=%3d %s\n", Fecode - mb->start_code, *Fecode,
|
|||
assert_accept_frame->offset_top * sizeof(PCRE2_SIZE));
|
||||
Foffset_top = assert_accept_frame->offset_top;
|
||||
Fmark = assert_accept_frame->mark;
|
||||
mb->end_subject = Lsaved_end_subject;
|
||||
mb->true_end_subject = mb->end_subject + Ltrue_end_extra;
|
||||
mb->moptions = Lsaved_moptions;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -5987,7 +6100,7 @@ fprintf(stderr, "++ %2ld op=%3d %s\n", Fecode - mb->start_code, *Fecode,
|
|||
assert_accept_frame->offset_top * sizeof(PCRE2_SIZE));
|
||||
Foffset_top = assert_accept_frame->offset_top;
|
||||
|
||||
/* Fall through */
|
||||
PCRE2_FALLTHROUGH /* Fall through */
|
||||
/* In the case of a match, the captures have already been put into
|
||||
the current frame. */
|
||||
|
||||
|
|
@ -6260,12 +6373,18 @@ fprintf(stderr, "++ %2ld op=%3d %s\n", Fecode - mb->start_code, *Fecode,
|
|||
/* Reinstate the previous set of captures and then carry on after the
|
||||
recursion call. */
|
||||
|
||||
memcpy((char *)F + offsetof(heapframe, ovector), P->ovector,
|
||||
Foffset_top * sizeof(PCRE2_SIZE));
|
||||
Foffset_top = P->offset_top;
|
||||
Fecode = P->ecode + 1 + LINK_SIZE;
|
||||
|
||||
if (*Fecode != OP_CREF)
|
||||
{
|
||||
memcpy(F->ovector, P->ovector, Foffset_top * sizeof(PCRE2_SIZE));
|
||||
Foffset_top = P->offset_top;
|
||||
}
|
||||
else
|
||||
recurse_update_offsets(F, P);
|
||||
|
||||
Fcapture_last = P->capture_last;
|
||||
Fcurrent_recurse = P->current_recurse;
|
||||
Fecode = P->ecode + 1 + LINK_SIZE;
|
||||
continue; /* With next opcode */
|
||||
|
||||
case OP_COND: /* No need to do anything for these */
|
||||
|
|
@ -6279,7 +6398,7 @@ fprintf(stderr, "++ %2ld op=%3d %s\n", Fecode - mb->start_code, *Fecode,
|
|||
case OP_ASSERTBACK_NA:
|
||||
if (branch_start[1 + LINK_SIZE] == OP_VREVERSE && Feptr != P->eptr)
|
||||
RRETURN(MATCH_NOMATCH);
|
||||
/* Fall through */
|
||||
PCRE2_FALLTHROUGH /* Fall through */
|
||||
|
||||
case OP_ASSERT_NA:
|
||||
if (Feptr > mb->last_used_ptr) mb->last_used_ptr = Feptr;
|
||||
|
|
@ -6293,12 +6412,12 @@ fprintf(stderr, "++ %2ld op=%3d %s\n", Fecode - mb->start_code, *Fecode,
|
|||
case OP_ASSERTBACK:
|
||||
if (branch_start[1 + LINK_SIZE] == OP_VREVERSE && Feptr != P->eptr)
|
||||
RRETURN(MATCH_NOMATCH);
|
||||
/* Fall through */
|
||||
PCRE2_FALLTHROUGH /* Fall through */
|
||||
|
||||
case OP_ASSERT:
|
||||
if (Feptr > mb->last_used_ptr) mb->last_used_ptr = Feptr;
|
||||
Feptr = P->eptr;
|
||||
/* Fall through */
|
||||
PCRE2_FALLTHROUGH /* 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
|
||||
|
|
@ -6322,7 +6441,7 @@ fprintf(stderr, "++ %2ld op=%3d %s\n", Fecode - mb->start_code, *Fecode,
|
|||
case OP_ASSERTBACK_NOT:
|
||||
if (branch_start[1 + LINK_SIZE] == OP_VREVERSE && Feptr != P->eptr)
|
||||
RRETURN(MATCH_NOMATCH);
|
||||
/* Fall through */
|
||||
PCRE2_FALLTHROUGH /* Fall through */
|
||||
|
||||
case OP_ASSERT_NOT:
|
||||
RRETURN(MATCH_MATCH);
|
||||
|
|
@ -6367,12 +6486,18 @@ fprintf(stderr, "++ %2ld op=%3d %s\n", Fecode - mb->start_code, *Fecode,
|
|||
if (Fcurrent_recurse == number)
|
||||
{
|
||||
P = (heapframe *)((char *)N - frame_size);
|
||||
memcpy((char *)F + offsetof(heapframe, ovector), P->ovector,
|
||||
Foffset_top * sizeof(PCRE2_SIZE));
|
||||
Foffset_top = P->offset_top;
|
||||
Fecode = P->ecode + 1 + LINK_SIZE;
|
||||
|
||||
if (*Fecode != OP_CREF)
|
||||
{
|
||||
memcpy(F->ovector, P->ovector, Foffset_top * sizeof(PCRE2_SIZE));
|
||||
Foffset_top = P->offset_top;
|
||||
}
|
||||
else
|
||||
recurse_update_offsets(F, P);
|
||||
|
||||
Fcapture_last = P->capture_last;
|
||||
Fcurrent_recurse = P->current_recurse;
|
||||
Fecode = P->ecode + 1 + LINK_SIZE;
|
||||
continue; /* With next opcode */
|
||||
}
|
||||
|
||||
|
|
@ -6450,7 +6575,7 @@ fprintf(stderr, "++ %2ld op=%3d %s\n", Fecode - mb->start_code, *Fecode,
|
|||
if ((mb->moptions & PCRE2_NOTEOL) != 0) RRETURN(MATCH_NOMATCH);
|
||||
if ((mb->poptions & PCRE2_DOLLAR_ENDONLY) == 0) goto ASSERT_NL_OR_EOS;
|
||||
|
||||
/* Fall through */
|
||||
PCRE2_FALLTHROUGH /* Fall through */
|
||||
/* Unconditional end of subject assertion (\z). */
|
||||
|
||||
case OP_EOD:
|
||||
|
|
@ -6748,9 +6873,11 @@ fprintf(stderr, "++ %2ld op=%3d %s\n", Fecode - mb->start_code, *Fecode,
|
|||
/* 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. */
|
||||
|
||||
/* LCOV_EXCL_START */
|
||||
default:
|
||||
PCRE2_DEBUG_UNREACHABLE();
|
||||
return PCRE2_ERROR_INTERNAL;
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
/* Do not insert any code in here without much thought; it is assumed
|
||||
|
|
@ -6798,9 +6925,11 @@ switch (Freturn_id)
|
|||
LBL(221) LBL(222) LBL(223) LBL(224)
|
||||
#endif
|
||||
|
||||
/* LCOV_EXCL_START */
|
||||
default:
|
||||
PCRE2_DEBUG_UNREACHABLE();
|
||||
return PCRE2_ERROR_INTERNAL;
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
#undef LBL
|
||||
}
|
||||
|
|
@ -6836,9 +6965,9 @@ pcre2_match(const pcre2_code *code, PCRE2_SPTR subject, PCRE2_SIZE length,
|
|||
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;
|
||||
uint32_t original_options = options;
|
||||
|
||||
BOOL anchored;
|
||||
BOOL firstline;
|
||||
|
|
@ -6856,6 +6985,8 @@ PCRE2_UCHAR first_cu2 = 0;
|
|||
PCRE2_UCHAR req_cu = 0;
|
||||
PCRE2_UCHAR req_cu2 = 0;
|
||||
|
||||
PCRE2_UCHAR null_str[1] = { 0xcd };
|
||||
PCRE2_SPTR original_subject = subject;
|
||||
PCRE2_SPTR bumpalong_limit;
|
||||
PCRE2_SPTR end_subject;
|
||||
PCRE2_SPTR true_end_subject;
|
||||
|
|
@ -6894,33 +7025,35 @@ match_block *mb = &actual_match_block;
|
|||
|
||||
/* Recognize NULL, length 0 as an empty string. */
|
||||
|
||||
if (subject == NULL && length == 0) subject = (PCRE2_SPTR)"";
|
||||
if (subject == NULL && length == 0) subject = null_str;
|
||||
|
||||
/* Plausibility checks */
|
||||
|
||||
if ((options & ~PUBLIC_MATCH_OPTIONS) != 0) return PCRE2_ERROR_BADOPTION;
|
||||
if (code == NULL || subject == NULL || match_data == NULL)
|
||||
return PCRE2_ERROR_NULL;
|
||||
if (match_data == NULL) return PCRE2_ERROR_NULL;
|
||||
if (code == NULL || subject == NULL)
|
||||
return match_data->rc = PCRE2_ERROR_NULL;
|
||||
if ((options & ~PUBLIC_MATCH_OPTIONS) != 0)
|
||||
return match_data->rc = PCRE2_ERROR_BADOPTION;
|
||||
|
||||
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;
|
||||
if (start_offset > length) return match_data->rc = 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;
|
||||
if (re->magic_number != MAGIC_NUMBER)
|
||||
return match_data->rc = PCRE2_ERROR_BADMAGIC;
|
||||
|
||||
/* Check the code unit width. */
|
||||
|
||||
if ((re->flags & PCRE2_MODE_MASK) != PCRE2_CODE_UNIT_WIDTH/8)
|
||||
return PCRE2_ERROR_BADMODE;
|
||||
return match_data->rc = 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
|
||||
|
|
@ -6967,17 +7100,18 @@ time. */
|
|||
|
||||
if (mb->partial != 0 &&
|
||||
((re->overall_options | options) & PCRE2_ENDANCHORED) != 0)
|
||||
return PCRE2_ERROR_BADOPTION;
|
||||
return match_data->rc = 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;
|
||||
return match_data->rc = 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. */
|
||||
free the memory that was obtained. Set the field to NULL for match error
|
||||
cases. */
|
||||
|
||||
if ((match_data->flags & PCRE2_MD_COPIED_SUBJECT) != 0)
|
||||
{
|
||||
|
|
@ -7014,11 +7148,11 @@ if (use_jit)
|
|||
#if PCRE2_CODE_UNIT_WIDTH != 32
|
||||
if (start_match < end_subject && NOT_FIRSTCU(*start_match))
|
||||
{
|
||||
if (start_offset > 0) return PCRE2_ERROR_BADUTFOFFSET;
|
||||
if (start_offset > 0) return match_data->rc = PCRE2_ERROR_BADUTFOFFSET;
|
||||
#if PCRE2_CODE_UNIT_WIDTH == 8
|
||||
return PCRE2_ERROR_UTF8_ERR20; /* Isolated 0x80 byte */
|
||||
return match_data->rc = PCRE2_ERROR_UTF8_ERR20; /* Isolated 0x80 byte */
|
||||
#else
|
||||
return PCRE2_ERROR_UTF16_ERR3; /* Isolated low surrogate */
|
||||
return match_data->rc = PCRE2_ERROR_UTF16_ERR3; /* Isolated low surrogate */
|
||||
#endif
|
||||
}
|
||||
#endif /* WIDTH != 32 */
|
||||
|
|
@ -7053,12 +7187,12 @@ if (use_jit)
|
|||
/* 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,
|
||||
rc = PRIV(valid_utf)(start_match,
|
||||
length - (start_match - subject), &(match_data->startchar));
|
||||
if (match_data->rc != 0)
|
||||
if (rc != 0)
|
||||
{
|
||||
match_data->startchar += start_match - subject;
|
||||
return match_data->rc;
|
||||
return match_data->rc = rc;
|
||||
}
|
||||
jit_checked_utf = TRUE;
|
||||
}
|
||||
|
|
@ -7071,16 +7205,27 @@ if (use_jit)
|
|||
match_data, mcontext);
|
||||
if (rc != PCRE2_ERROR_JIT_BADOPTION)
|
||||
{
|
||||
match_data->subject_length = length;
|
||||
match_data->options = original_options;
|
||||
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);
|
||||
if (length != 0)
|
||||
{
|
||||
match_data->subject = match_data->memctl.malloc(CU2BYTES(length),
|
||||
match_data->memctl.memory_data);
|
||||
if (match_data->subject == NULL)
|
||||
return match_data->rc = PCRE2_ERROR_NOMEMORY;
|
||||
memcpy((void *)match_data->subject, subject, CU2BYTES(length));
|
||||
}
|
||||
else
|
||||
match_data->subject = NULL;
|
||||
match_data->flags |= PCRE2_MD_COPIED_SUBJECT;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* When pcre2_jit_match sets the subject, it doesn't know what the
|
||||
original passed-in pointer was. */
|
||||
if (match_data->subject != NULL) match_data->subject = original_subject;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
|
@ -7137,11 +7282,11 @@ if (utf &&
|
|||
}
|
||||
else if (start_match < end_subject && NOT_FIRSTCU(*start_match))
|
||||
{
|
||||
if (start_offset > 0) return PCRE2_ERROR_BADUTFOFFSET;
|
||||
if (start_offset > 0) return match_data->rc = PCRE2_ERROR_BADUTFOFFSET;
|
||||
#if PCRE2_CODE_UNIT_WIDTH == 8
|
||||
return PCRE2_ERROR_UTF8_ERR20; /* Isolated 0x80 byte */
|
||||
return match_data->rc = PCRE2_ERROR_UTF8_ERR20; /* Isolated 0x80 byte */
|
||||
#else
|
||||
return PCRE2_ERROR_UTF16_ERR3; /* Isolated low surrogate */
|
||||
return match_data->rc = PCRE2_ERROR_UTF16_ERR3; /* Isolated low surrogate */
|
||||
#endif
|
||||
}
|
||||
#endif /* WIDTH != 32 */
|
||||
|
|
@ -7189,10 +7334,10 @@ if (utf &&
|
|||
|
||||
for (;;)
|
||||
{
|
||||
match_data->rc = PRIV(valid_utf)(mb->check_subject,
|
||||
rc = PRIV(valid_utf)(mb->check_subject,
|
||||
length - (mb->check_subject - subject), &(match_data->startchar));
|
||||
|
||||
if (match_data->rc == 0) break; /* Valid UTF string */
|
||||
if (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
|
||||
|
|
@ -7200,7 +7345,7 @@ if (utf &&
|
|||
Otherwise return the error. */
|
||||
|
||||
match_data->startchar += mb->check_subject - subject;
|
||||
if (!allow_invalid || match_data->rc > 0) return match_data->rc;
|
||||
if (!allow_invalid || rc > 0) return match_data->rc = rc;
|
||||
end_subject = subject + match_data->startchar;
|
||||
|
||||
/* If the end precedes start_match, it means there is invalid UTF in the
|
||||
|
|
@ -7265,8 +7410,11 @@ mb->start_offset = start_offset;
|
|||
mb->end_subject = end_subject;
|
||||
mb->true_end_subject = true_end_subject;
|
||||
mb->hasthen = (re->flags & PCRE2_HASTHEN) != 0;
|
||||
mb->hasbsk = (re->flags & PCRE2_HASBSK) != 0;
|
||||
mb->allowemptypartial = (re->max_lookbehind > 0) ||
|
||||
(re->flags & PCRE2_MATCH_EMPTY) != 0;
|
||||
mb->allowlookaroundbsk =
|
||||
(re->extra_options & PCRE2_EXTRA_ALLOW_LOOKAROUND_BSK) != 0;
|
||||
mb->poptions = re->overall_options; /* Pattern options */
|
||||
mb->ignore_skip_arg = 0;
|
||||
mb->mark = mb->nomatch_mark = NULL; /* In case never set */
|
||||
|
|
@ -7314,9 +7462,11 @@ switch(re->newline_convention)
|
|||
mb->nltype = NLTYPE_ANYCRLF;
|
||||
break;
|
||||
|
||||
/* LCOV_EXCL_START */
|
||||
default:
|
||||
PCRE2_DEBUG_UNREACHABLE();
|
||||
return PCRE2_ERROR_INTERNAL;
|
||||
return match_data->rc = PCRE2_ERROR_INTERNAL;
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
/* The backtracking frames have fixed data at the front, and a PCRE2_SIZE
|
||||
|
|
@ -7358,7 +7508,7 @@ if (heapframes_size < START_FRAMES_SIZE) heapframes_size = START_FRAMES_SIZE;
|
|||
if (heapframes_size / 1024 > mb->heap_limit)
|
||||
{
|
||||
PCRE2_SIZE max_size = 1024 * mb->heap_limit;
|
||||
if (max_size < frame_size) return PCRE2_ERROR_HEAPLIMIT;
|
||||
if (max_size < frame_size) return match_data->rc = PCRE2_ERROR_HEAPLIMIT;
|
||||
heapframes_size = max_size;
|
||||
}
|
||||
|
||||
|
|
@ -7374,7 +7524,7 @@ if (match_data->heapframes_size < heapframes_size)
|
|||
if (match_data->heapframes == NULL)
|
||||
{
|
||||
match_data->heapframes_size = 0;
|
||||
return PCRE2_ERROR_NOMEMORY;
|
||||
return match_data->rc = PCRE2_ERROR_NOMEMORY;
|
||||
}
|
||||
match_data->heapframes_size = heapframes_size;
|
||||
}
|
||||
|
|
@ -7850,7 +8000,7 @@ for(;;)
|
|||
new_start_match = mb->verb_skip_ptr;
|
||||
break;
|
||||
}
|
||||
/* Fall through */
|
||||
PCRE2_FALLTHROUGH /* Fall through */
|
||||
|
||||
/* NOMATCH and PRUNE advance by one character. THEN at this level acts
|
||||
exactly like PRUNE. Unset ignore SKIP-with-argument. */
|
||||
|
|
@ -8008,6 +8158,7 @@ if (utf && end_subject != true_end_subject &&
|
|||
match_data->code = re;
|
||||
match_data->mark = mb->mark;
|
||||
match_data->matchedby = PCRE2_MATCHEDBY_INTERPRETER;
|
||||
match_data->options = original_options;
|
||||
|
||||
/* 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
|
||||
|
|
@ -8019,20 +8170,26 @@ 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->subject_length = length;
|
||||
match_data->start_offset = start_offset;
|
||||
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);
|
||||
if (length != 0)
|
||||
{
|
||||
match_data->subject = match_data->memctl.malloc(CU2BYTES(length),
|
||||
match_data->memctl.memory_data);
|
||||
if (match_data->subject == NULL)
|
||||
return match_data->rc = PCRE2_ERROR_NOMEMORY;
|
||||
memcpy((void *)match_data->subject, subject, CU2BYTES(length));
|
||||
}
|
||||
else
|
||||
match_data->subject = NULL;
|
||||
match_data->flags |= PCRE2_MD_COPIED_SUBJECT;
|
||||
}
|
||||
else match_data->subject = subject;
|
||||
else match_data->subject = original_subject;
|
||||
|
||||
return match_data->rc;
|
||||
}
|
||||
|
|
@ -8054,8 +8211,9 @@ PCRE2_ERROR_PARTIAL. */
|
|||
|
||||
else if (match_partial != NULL)
|
||||
{
|
||||
match_data->subject = subject;
|
||||
match_data->subject = original_subject;
|
||||
match_data->subject_length = length;
|
||||
match_data->start_offset = start_offset;
|
||||
match_data->ovector[0] = match_partial - subject;
|
||||
match_data->ovector[1] = end_subject - subject;
|
||||
match_data->startchar = match_partial - subject;
|
||||
|
|
@ -8066,7 +8224,13 @@ else if (match_partial != NULL)
|
|||
|
||||
/* Else this is the classic nomatch case. */
|
||||
|
||||
else match_data->rc = PCRE2_ERROR_NOMATCH;
|
||||
else
|
||||
{
|
||||
match_data->subject = original_subject;
|
||||
match_data->subject_length = length;
|
||||
match_data->start_offset = start_offset;
|
||||
match_data->rc = PCRE2_ERROR_NOMATCH;
|
||||
}
|
||||
|
||||
return match_data->rc;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,10 +39,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
*/
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "pcre2_internal.h"
|
||||
|
||||
|
||||
|
|
@ -85,6 +81,7 @@ PCRE2_EXP_DEFN pcre2_match_data * PCRE2_CALL_CONVENTION
|
|||
pcre2_match_data_create_from_pattern(const pcre2_code *code,
|
||||
pcre2_general_context *gcontext)
|
||||
{
|
||||
if (code == NULL) return NULL;
|
||||
if (gcontext == NULL) gcontext = (pcre2_general_context *)code;
|
||||
return pcre2_match_data_create(((const pcre2_real_code *)code)->top_bracket + 1,
|
||||
gcontext);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,171 @@
|
|||
/*************************************************
|
||||
* 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-2024 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.
|
||||
-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
#include "pcre2_internal.h"
|
||||
|
||||
|
||||
|
||||
/* Advance the offset by one code unit, and return the new value.
|
||||
It is only called when the offset is not at the end of the subject. */
|
||||
|
||||
static PCRE2_SIZE do_bumpalong(pcre2_match_data *match_data,
|
||||
PCRE2_SIZE offset)
|
||||
{
|
||||
PCRE2_SPTR subject = match_data->subject;
|
||||
PCRE2_SIZE subject_length = match_data->subject_length;
|
||||
#ifdef SUPPORT_UNICODE
|
||||
BOOL utf = (match_data->code->overall_options & PCRE2_UTF) != 0;
|
||||
#endif
|
||||
|
||||
/* Skip over CRLF as an atomic sequence, if CRLF is configured as a newline
|
||||
sequence. */
|
||||
|
||||
if (subject[offset] == CHAR_CR && offset + 1 < subject_length &&
|
||||
subject[offset + 1] == CHAR_LF)
|
||||
{
|
||||
switch(match_data->code->newline_convention)
|
||||
{
|
||||
case PCRE2_NEWLINE_CRLF:
|
||||
case PCRE2_NEWLINE_ANY:
|
||||
case PCRE2_NEWLINE_ANYCRLF:
|
||||
return offset + 2;
|
||||
}
|
||||
}
|
||||
|
||||
/* Advance by one full character if in UTF mode. */
|
||||
|
||||
#ifdef SUPPORT_UNICODE
|
||||
if (utf)
|
||||
{
|
||||
PCRE2_SPTR next = subject + offset + 1;
|
||||
PCRE2_SPTR subject_end = subject + subject_length;
|
||||
|
||||
(void)subject_end; /* Suppress warning; 32-bit FORWARDCHARTEST ignores this */
|
||||
FORWARDCHARTEST(next, subject_end);
|
||||
return next - subject;
|
||||
}
|
||||
#endif
|
||||
|
||||
return offset + 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*************************************************
|
||||
* Advance the match *
|
||||
*************************************************/
|
||||
|
||||
PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
|
||||
pcre2_next_match(pcre2_match_data *match_data, PCRE2_SIZE *pstart_offset,
|
||||
uint32_t *poptions)
|
||||
{
|
||||
int rc = match_data->rc;
|
||||
PCRE2_SIZE start_offset = match_data->start_offset;
|
||||
PCRE2_SIZE *ovector = match_data->ovector;
|
||||
|
||||
/* Match error, or no match: no further iteration possible. In previous versions
|
||||
of PCRE2, we recommended that clients use a strategy which involved retrying in
|
||||
certain cases after PCRE2_ERROR_NOMATCH, but this is no longer required. */
|
||||
|
||||
if (rc < 0)
|
||||
return FALSE;
|
||||
|
||||
/* Match succeeded: get the start offset for the next match */
|
||||
|
||||
/* Although \K can affect the position of ovector[0], there are no ways to do
|
||||
anything surprising with ovector[1], which must always be >= start_offset. */
|
||||
|
||||
PCRE2_ASSERT(ovector[1] >= start_offset);
|
||||
|
||||
/* Special handling for patterns which contain \K in a lookaround, which enables
|
||||
the match start to be pushed back to before the starting search offset
|
||||
(ovector[0] < start_offset) or after the match ends (ovector[0] > ovector[1]).
|
||||
This is not a problem if ovector[1] > start_offset, because in this case, we can
|
||||
just attempt the next match at ovector[1]: we are making progress, which is all
|
||||
that we require.
|
||||
|
||||
However, if we have ovector[1] == start_offset, then we have a very rare case
|
||||
which must be handled specially, because it's a non-empty match which
|
||||
nonetheless fails to make progress through the subject. */
|
||||
|
||||
if (ovector[0] != start_offset && ovector[1] == start_offset)
|
||||
{
|
||||
/* If the match end is at the end of the subject, we are done. */
|
||||
|
||||
if (start_offset >= match_data->subject_length)
|
||||
return FALSE;
|
||||
|
||||
/* Otherwise, bump along by one code unit, and do a normal search. */
|
||||
|
||||
*pstart_offset = do_bumpalong(match_data, ovector[1]);
|
||||
*poptions = 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* If the previous match was for an empty string, we are finished if we are at
|
||||
the end of the subject. Otherwise, arrange to run another match at the same
|
||||
point to see if a non-empty match can be found. */
|
||||
|
||||
if (ovector[0] == ovector[1])
|
||||
{
|
||||
/* If the match is at the end of the subject, we are done. */
|
||||
|
||||
if (ovector[0] >= match_data->subject_length)
|
||||
return FALSE;
|
||||
|
||||
/* Otherwise, continue at this exact same point, but we must set the flag
|
||||
which ensures that we don't return the exact same empty match again. */
|
||||
|
||||
*pstart_offset = ovector[1];
|
||||
*poptions = PCRE2_NOTEMPTY_ATSTART;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Finally, we must be in the happy state of a non-empty match, where the end of
|
||||
the match is further on in the subject than start_offset, so we are easily able
|
||||
to continue and make progress. */
|
||||
|
||||
*pstart_offset = ovector[1];
|
||||
*poptions = 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* End of pcre2_match_next.c */
|
||||
|
|
@ -48,10 +48,6 @@ 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"
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -43,13 +43,10 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
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. */
|
||||
|
|
@ -83,16 +80,17 @@ PRIV(ord2utf)(uint32_t cvalue, PCRE2_UCHAR *buffer)
|
|||
/* Convert to UTF-8 */
|
||||
|
||||
#if PCRE2_CODE_UNIT_WIDTH == 8
|
||||
int i, j;
|
||||
unsigned int i;
|
||||
|
||||
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--)
|
||||
for (unsigned int j = i; j != 0; j--)
|
||||
{
|
||||
*buffer-- = 0x80 | (cvalue & 0x3f);
|
||||
cvalue >>= 6;
|
||||
}
|
||||
*buffer = PRIV(utf8_table2)[i] | cvalue;
|
||||
*buffer = (PCRE2_UCHAR)(PRIV(utf8_table2)[i] | (int)cvalue);
|
||||
return i + 1;
|
||||
|
||||
/* Convert to UTF-16 */
|
||||
|
|
|
|||
|
|
@ -39,13 +39,10 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
*/
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "pcre2_internal.h"
|
||||
|
||||
|
||||
|
||||
/*************************************************
|
||||
* Return info about compiled pattern *
|
||||
*************************************************/
|
||||
|
|
@ -292,8 +289,7 @@ if (re->magic_number != MAGIC_NUMBER) return PCRE2_ERROR_BADMAGIC;
|
|||
if ((re->flags & (PCRE2_CODE_UNIT_WIDTH/8)) == 0) return PCRE2_ERROR_BADMODE;
|
||||
|
||||
cb.version = 0;
|
||||
cc = (PCRE2_SPTR)((const uint8_t *)re + sizeof(pcre2_real_code))
|
||||
+ re->name_count * re->name_entry_size;
|
||||
cc = (PCRE2_SPTR)((uint8_t *)re + re->code_start);
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -38,15 +38,14 @@ 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 *
|
||||
*************************************************/
|
||||
|
|
|
|||
|
|
@ -38,17 +38,15 @@ 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
|
||||
|
|
|
|||
|
|
@ -38,53 +38,15 @@ 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 *
|
||||
|
|
|
|||
|
|
@ -38,16 +38,15 @@ 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
|
||||
|
|
@ -139,7 +138,7 @@ for (;;)
|
|||
PCRE2_UCHAR op;
|
||||
PCRE2_SPTR cs, ce;
|
||||
|
||||
if (branchlength >= UINT16_MAX)
|
||||
if (branchlength >= (int)UINT16_MAX)
|
||||
{
|
||||
branchlength = UINT16_MAX;
|
||||
cc = nextbranch;
|
||||
|
|
@ -176,7 +175,7 @@ for (;;)
|
|||
cc += 1 + LINK_SIZE;
|
||||
break;
|
||||
}
|
||||
/* Fall through */
|
||||
PCRE2_FALLTHROUGH /* Fall through */
|
||||
|
||||
case OP_ONCE:
|
||||
case OP_SCRIPT_RUN:
|
||||
|
|
@ -253,7 +252,7 @@ for (;;)
|
|||
case OP_ASSERT_SCS:
|
||||
case OP_ASSERTBACK_NA:
|
||||
do cc += GET(cc, 1); while (*cc == OP_ALT);
|
||||
/* Fall through */
|
||||
PCRE2_FALLTHROUGH /* Fall through */
|
||||
|
||||
/* Skip over things that don't match chars */
|
||||
|
||||
|
|
@ -353,7 +352,7 @@ for (;;)
|
|||
case OP_PROP:
|
||||
case OP_NOTPROP:
|
||||
cc += 2;
|
||||
/* Fall through */
|
||||
PCRE2_FALLTHROUGH /* Fall through */
|
||||
|
||||
case OP_NOT_DIGIT:
|
||||
case OP_DIGIT:
|
||||
|
|
@ -434,7 +433,7 @@ for (;;)
|
|||
case OP_CRMINPLUS:
|
||||
case OP_CRPOSPLUS:
|
||||
branchlength++;
|
||||
/* Fall through */
|
||||
PCRE2_FALLTHROUGH /* Fall through */
|
||||
|
||||
case OP_CRSTAR:
|
||||
case OP_CRMINSTAR:
|
||||
|
|
@ -628,11 +627,11 @@ for (;;)
|
|||
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). */
|
||||
/* 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)
|
||||
if ((d > 0 && (INT_MAX/d) < min) || (int)UINT16_MAX - branchlength < min*d)
|
||||
branchlength = UINT16_MAX;
|
||||
else branchlength += min * d;
|
||||
break;
|
||||
|
|
@ -753,14 +752,18 @@ for (;;)
|
|||
/* This should not occur: we list all opcodes explicitly so that when
|
||||
new ones get added they are properly considered. */
|
||||
|
||||
/* LCOV_EXCL_START */
|
||||
default:
|
||||
PCRE2_DEBUG_UNREACHABLE();
|
||||
return -3;
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
}
|
||||
|
||||
/* LCOV_EXCL_START */
|
||||
PCRE2_DEBUG_UNREACHABLE(); /* Control should never reach here */
|
||||
return -3; /* Avoid compiler warnings */
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1304,7 +1307,7 @@ do
|
|||
|
||||
case OP_PROP:
|
||||
if (ncode[1] != PT_CLIST) break;
|
||||
/* Fall through */
|
||||
PCRE2_FALLTHROUGH /* Fall through */
|
||||
case OP_ANYNL:
|
||||
case OP_CHAR:
|
||||
case OP_CHARI:
|
||||
|
|
@ -1328,7 +1331,7 @@ do
|
|||
tcode = ncode;
|
||||
continue; /* With the following significant opcode */
|
||||
}
|
||||
/* Fall through */
|
||||
PCRE2_FALLTHROUGH /* Fall through */
|
||||
|
||||
/* For a group bracket or a positive assertion without an immediately
|
||||
following mandatory setting, recurse to set bits from within the
|
||||
|
|
@ -1456,7 +1459,7 @@ do
|
|||
|
||||
case OP_EXACT:
|
||||
tcode += IMM2_SIZE;
|
||||
/* Fall through */
|
||||
PCRE2_FALLTHROUGH /* Fall through */
|
||||
case OP_CHAR:
|
||||
case OP_PLUS:
|
||||
case OP_MINPLUS:
|
||||
|
|
@ -1467,7 +1470,7 @@ do
|
|||
|
||||
case OP_EXACTI:
|
||||
tcode += IMM2_SIZE;
|
||||
/* Fall through */
|
||||
PCRE2_FALLTHROUGH /* Fall through */
|
||||
case OP_CHARI:
|
||||
case OP_PLUSI:
|
||||
case OP_MINPLUSI:
|
||||
|
|
@ -1487,10 +1490,10 @@ do
|
|||
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. */
|
||||
the bits for NBSP and for code units >= 255, independently of UTF. */
|
||||
|
||||
#if PCRE2_CODE_UNIT_WIDTH != 8
|
||||
SET_BIT(0xA0);
|
||||
SET_BIT(CHAR_NBSP);
|
||||
SET_BIT(0xFF);
|
||||
#else
|
||||
/* For the 8-bit library in UTF-8 mode, set the bits for the first code
|
||||
|
|
@ -1506,12 +1509,9 @@ do
|
|||
}
|
||||
else
|
||||
#endif
|
||||
/* For the 8-bit library not in UTF-8 mode, set the bit for 0xA0, unless
|
||||
the code is EBCDIC. */
|
||||
/* For the 8-bit library not in UTF-8 mode, set the bit for NBSP. */
|
||||
{
|
||||
#ifndef EBCDIC
|
||||
SET_BIT(0xA0);
|
||||
#endif /* Not EBCDIC */
|
||||
SET_BIT(CHAR_NBSP);
|
||||
}
|
||||
#endif /* 8-bit support */
|
||||
|
||||
|
|
@ -1606,7 +1606,8 @@ do
|
|||
case OP_TYPEUPTO:
|
||||
case OP_TYPEMINUPTO:
|
||||
case OP_TYPEPOSUPTO:
|
||||
tcode += IMM2_SIZE; /* Fall through */
|
||||
tcode += IMM2_SIZE;
|
||||
PCRE2_FALLTHROUGH /* Fall through */
|
||||
|
||||
case OP_TYPESTAR:
|
||||
case OP_TYPEMINSTAR:
|
||||
|
|
@ -1626,10 +1627,10 @@ do
|
|||
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. */
|
||||
the bits for NBSP and for code units >= 255, independently of UTF. */
|
||||
|
||||
#if PCRE2_CODE_UNIT_WIDTH != 8
|
||||
SET_BIT(0xA0);
|
||||
SET_BIT(CHAR_NBSP);
|
||||
SET_BIT(0xFF);
|
||||
#else
|
||||
/* For the 8-bit library in UTF-8 mode, set the bits for the first code
|
||||
|
|
@ -1645,12 +1646,9 @@ do
|
|||
}
|
||||
else
|
||||
#endif
|
||||
/* For the 8-bit library not in UTF-8 mode, set the bit for 0xA0, unless
|
||||
the code is EBCDIC. */
|
||||
/* For the 8-bit library not in UTF-8 mode, set the bit for NBSP. */
|
||||
{
|
||||
#ifndef EBCDIC
|
||||
SET_BIT(0xA0);
|
||||
#endif /* Not EBCDIC */
|
||||
SET_BIT(CHAR_NBSP);
|
||||
}
|
||||
#endif /* 8-bit support */
|
||||
break;
|
||||
|
|
@ -1779,9 +1777,11 @@ do
|
|||
case XCL_END:
|
||||
goto HANDLE_CLASSMAP;
|
||||
|
||||
/* LCOV_EXCL_START */
|
||||
default:
|
||||
PCRE2_DEBUG_UNREACHABLE();
|
||||
return SSB_UNKNOWN; /* Internal error, should not occur */
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
}
|
||||
#endif /* SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8 */
|
||||
|
|
@ -1790,7 +1790,7 @@ do
|
|||
/* It seems that the fall through comment must be outside the #ifdef if
|
||||
it is to avoid the gcc compiler warning. */
|
||||
|
||||
/* Fall through */
|
||||
PCRE2_FALLTHROUGH /* 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
|
||||
|
|
@ -1805,14 +1805,15 @@ do
|
|||
re->start_bitmap[24] |= 0xf0; /* Bits for 0xc4 - 0xc8 */
|
||||
memset(re->start_bitmap+25, 0xff, 7); /* Bits for 0xc9 - 0xff */
|
||||
}
|
||||
PCRE2_FALLTHROUGH /* Fall through */
|
||||
#elif PCRE2_CODE_UNIT_WIDTH != 8
|
||||
SET_BIT(0xFF); /* For characters >= 255 */
|
||||
PCRE2_FALLTHROUGH /* Fall through */
|
||||
#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. */
|
||||
Otherwise, set up classmap for a non-XCLASS and advance past it. */
|
||||
|
||||
case OP_CLASS:
|
||||
if (*tcode == OP_XCLASS) tcode += GET(tcode, 1); else
|
||||
|
|
@ -1930,11 +1931,13 @@ if ((re->flags & (PCRE2_FIRSTSET|PCRE2_STARTLINE)) == 0)
|
|||
{
|
||||
int depth = 0;
|
||||
int rc = set_start_bits(re, code, utf, ucp, &depth);
|
||||
/* LCOV_EXCL_START */
|
||||
if (rc == SSB_UNKNOWN)
|
||||
{
|
||||
PCRE2_DEBUG_UNREACHABLE();
|
||||
return 1;
|
||||
}
|
||||
/* LCOV_EXCL_STOP */
|
||||
|
||||
/* 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
|
||||
|
|
@ -2002,6 +2005,16 @@ if ((re->flags & (PCRE2_FIRSTSET|PCRE2_STARTLINE)) == 0)
|
|||
|
||||
if (d != a) goto DONE; /* Not the other case of a */
|
||||
b = c; /* Save second in b */
|
||||
|
||||
#ifdef EBCDIC
|
||||
/* To match ASCII (which puts the uppercase one in a), swap a & b
|
||||
if needed. This doesn't really matter, but neatens the tests. */
|
||||
if (TABLE_GET((unsigned int)a, re->tables + lcc_offset, a) == a)
|
||||
{
|
||||
b = a;
|
||||
a = c;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else goto DONE; /* More than two characters found */
|
||||
}
|
||||
|
|
@ -2049,16 +2062,20 @@ if ((re->flags & (PCRE2_MATCH_EMPTY|PCRE2_HASACCEPT)) == 0 &&
|
|||
case -1: /* \C in UTF mode or over-complex regex */
|
||||
break; /* Leave minlength unchanged (will be zero) */
|
||||
|
||||
/* LCOV_EXCL_START */
|
||||
case -2:
|
||||
PCRE2_DEBUG_UNREACHABLE();
|
||||
return 2; /* missing capturing bracket */
|
||||
/* LCOV_EXCL_STOP */
|
||||
|
||||
/* LCOV_EXCL_START */
|
||||
case -3:
|
||||
PCRE2_DEBUG_UNREACHABLE();
|
||||
return 3; /* unrecognized opcode */
|
||||
/* LCOV_EXCL_STOP */
|
||||
|
||||
default:
|
||||
re->minlength = (min > UINT16_MAX)? UINT16_MAX : min;
|
||||
re->minlength = (min > (int)UINT16_MAX)? (int)UINT16_MAX : min;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,12 +39,10 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
*/
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "pcre2_internal.h"
|
||||
|
||||
|
||||
|
||||
#define PTR_STACK_SIZE 20
|
||||
|
||||
#define SUBSTITUTE_OPTIONS \
|
||||
|
|
@ -131,7 +129,6 @@ for (; ptr < ptrend; ptr++)
|
|||
ptr += 1; /* Must point after \ */
|
||||
erc = PRIV(check_escape)(&ptr, ptrend, &ch, &errorcode,
|
||||
code->overall_options, code->extra_options, code->top_bracket, FALSE, NULL);
|
||||
ptr -= 1; /* Back to last code unit of escape */
|
||||
if (errorcode != 0)
|
||||
{
|
||||
/* errorcode from check_escape is positive, so must not be returned by
|
||||
|
|
@ -327,9 +324,11 @@ if (input_len == 0) return 0;
|
|||
|
||||
switch (state->to_case)
|
||||
{
|
||||
/* LCOV_EXCL_START */
|
||||
default:
|
||||
PCRE2_DEBUG_UNREACHABLE();
|
||||
return 0;
|
||||
/* LCOV_EXCL_STOP */
|
||||
|
||||
case PCRE2_SUBSTITUTE_CASE_LOWER: // Can be single_char TRUE or FALSE
|
||||
case PCRE2_SUBSTITUTE_CASE_UPPER: // Can only be single_char FALSE
|
||||
|
|
@ -465,9 +464,11 @@ PCRE2_ASSERT(input_len != 0);
|
|||
|
||||
switch (state->to_case)
|
||||
{
|
||||
/* LCOV_EXCL_START */
|
||||
default:
|
||||
PCRE2_DEBUG_UNREACHABLE();
|
||||
return 0;
|
||||
/* LCOV_EXCL_STOP */
|
||||
|
||||
case PCRE2_SUBSTITUTE_CASE_LOWER: // Can be single_char TRUE or FALSE
|
||||
case PCRE2_SUBSTITUTE_CASE_UPPER: // Can only be single_char FALSE
|
||||
|
|
@ -751,12 +752,14 @@ BOOL use_existing_match;
|
|||
BOOL replacement_only;
|
||||
BOOL utf = (code->overall_options & PCRE2_UTF) != 0;
|
||||
PCRE2_UCHAR temp[6];
|
||||
PCRE2_UCHAR null_str[1] = { 0xcd };
|
||||
PCRE2_SPTR original_subject = subject;
|
||||
PCRE2_SPTR ptr;
|
||||
PCRE2_SPTR repend = NULL;
|
||||
PCRE2_SIZE extra_needed = 0;
|
||||
PCRE2_SIZE buff_offset, buff_length, lengthleft, fraglength;
|
||||
PCRE2_SIZE *ovector;
|
||||
PCRE2_SIZE ovecsave[3];
|
||||
PCRE2_SIZE ovecsave[2] = { 0, 0 };
|
||||
pcre2_substitute_callout_block scb;
|
||||
PCRE2_SIZE sub_start_extra_needed;
|
||||
PCRE2_SIZE (*substitute_case_callout)(PCRE2_SPTR, PCRE2_SIZE, PCRE2_UCHAR *,
|
||||
|
|
@ -768,7 +771,6 @@ void *substitute_case_callout_data = NULL;
|
|||
buff_offset = 0;
|
||||
lengthleft = buff_length = *blength;
|
||||
*blength = PCRE2_UNSET;
|
||||
ovecsave[0] = ovecsave[1] = ovecsave[2] = PCRE2_UNSET;
|
||||
|
||||
if (mcontext != NULL)
|
||||
{
|
||||
|
|
@ -788,18 +790,74 @@ zero length is interpreted as an empty string. */
|
|||
if (replacement == NULL)
|
||||
{
|
||||
if (rlength != 0) return PCRE2_ERROR_NULL;
|
||||
replacement = (PCRE2_SPTR)"";
|
||||
replacement = null_str;
|
||||
}
|
||||
|
||||
if (rlength == PCRE2_ZERO_TERMINATED) rlength = PRIV(strlen)(replacement);
|
||||
repend = replacement + rlength;
|
||||
|
||||
/* A NULL subject of zero length is treated as an empty string. */
|
||||
|
||||
if (subject == NULL)
|
||||
{
|
||||
if (length != 0) return PCRE2_ERROR_NULL;
|
||||
subject = null_str;
|
||||
}
|
||||
|
||||
if (length == PCRE2_ZERO_TERMINATED) length = PRIV(strlen)(subject);
|
||||
|
||||
/* 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 (use_existing_match && match_data == NULL) return PCRE2_ERROR_NULL;
|
||||
|
||||
/* If an existing match is being passed in, we should check that it matches
|
||||
the passed-in subject pointer, length, and match options. We don't currently
|
||||
have a use-case for someone to match on one subject, then try and use that
|
||||
match data on a different subject. In a UTF-encoded string, a simple change
|
||||
like replacing one character for another won't preserve the code unit offsets,
|
||||
so it's hard to see, in the general case, how it would be safe or useful to
|
||||
support swapping or mutating the subject string.
|
||||
|
||||
Similarly, using different match options between the first (external) and
|
||||
subsequent (internal, global) matches is hard to justify. */
|
||||
|
||||
if (use_existing_match)
|
||||
{
|
||||
/* Return early, as the rest of the match_data may not have been
|
||||
initialised. This duplicates and must be in sync with the check below that
|
||||
aborts substitution on any result other than success or no-match. */
|
||||
if (match_data->rc < 0 && match_data->rc != PCRE2_ERROR_NOMATCH)
|
||||
return match_data->rc;
|
||||
|
||||
/* Not supported if the passed-in match was from the DFA interpreter. */
|
||||
if (match_data->matchedby == PCRE2_MATCHEDBY_DFA_INTERPRETER)
|
||||
return PCRE2_ERROR_DFA_UFUNC;
|
||||
|
||||
if (code != match_data->code)
|
||||
return PCRE2_ERROR_DIFFSUBSPATTERN;
|
||||
|
||||
/* We want the passed-in subject strings to match. This implies the effective
|
||||
length must match, and either: the pointers are equal (with strict matching
|
||||
of NULL against NULL); or, the special case of PCRE2_COPY_MATCHED_SUBJECT
|
||||
where we cannot compare pointers but we can verify the contents. */
|
||||
if (length != match_data->subject_length ||
|
||||
!(original_subject == match_data->subject ||
|
||||
((match_data->flags & PCRE2_MD_COPIED_SUBJECT) != 0 &&
|
||||
(length == 0 ||
|
||||
memcmp(subject, match_data->subject, CU2BYTES(length)) == 0))))
|
||||
return PCRE2_ERROR_DIFFSUBSSUBJECT;
|
||||
|
||||
if (start_offset != match_data->start_offset)
|
||||
return PCRE2_ERROR_DIFFSUBSOFFSET;
|
||||
|
||||
if ((options & ~SUBSTITUTE_OPTIONS) != match_data->options)
|
||||
return PCRE2_ERROR_DIFFSUBSOPTIONS;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
|
@ -816,9 +874,8 @@ have to be changes below. */
|
|||
if (match_data == NULL)
|
||||
{
|
||||
pcre2_general_context gcontext;
|
||||
if (use_existing_match) return PCRE2_ERROR_NULL;
|
||||
gcontext.memctl = (mcontext == NULL)?
|
||||
((const pcre2_real_code *)code)->memctl :
|
||||
((pcre2_real_code *)code)->memctl :
|
||||
((pcre2_real_match_context *)mcontext)->memctl;
|
||||
match_data = internal_match_data =
|
||||
pcre2_match_data_create_from_pattern(code, &gcontext);
|
||||
|
|
@ -830,7 +887,7 @@ else if (use_existing_match)
|
|||
int pairs;
|
||||
pcre2_general_context gcontext;
|
||||
gcontext.memctl = (mcontext == NULL)?
|
||||
((const pcre2_real_code *)code)->memctl :
|
||||
((pcre2_real_code *)code)->memctl :
|
||||
((pcre2_real_match_context *)mcontext)->memctl;
|
||||
pairs = (code->top_bracket + 1 < match_data->oveccount)?
|
||||
code->top_bracket + 1 : match_data->oveccount;
|
||||
|
|
@ -841,9 +898,15 @@ else if (use_existing_match)
|
|||
+ 2*pairs*sizeof(PCRE2_SIZE));
|
||||
internal_match_data->heapframes = NULL;
|
||||
internal_match_data->heapframes_size = 0;
|
||||
/* Ensure that the subject is not freed when internal_match_data is */
|
||||
internal_match_data->flags &= ~PCRE2_MD_COPIED_SUBJECT;
|
||||
match_data = internal_match_data;
|
||||
}
|
||||
|
||||
/* If using an internal match data, there's no need to copy the subject. */
|
||||
|
||||
if (internal_match_data != NULL) options &= ~PCRE2_COPY_MATCHED_SUBJECT;
|
||||
|
||||
/* Remember ovector details */
|
||||
|
||||
ovector = pcre2_get_ovector_pointer(match_data);
|
||||
|
|
@ -856,19 +919,6 @@ 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
|
||||
|
|
@ -905,7 +955,7 @@ if (!replacement_only) CHECKMEMCPY(subject, start_offset);
|
|||
match is taken from the match_data that was passed in. */
|
||||
|
||||
subs = 0;
|
||||
do
|
||||
for (;;)
|
||||
{
|
||||
PCRE2_SPTR ptrstack[PTR_STACK_SIZE];
|
||||
uint32_t ptrstackptr = 0;
|
||||
|
|
@ -925,54 +975,12 @@ do
|
|||
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. */
|
||||
/* Any error other than no match returns the error code. No match breaks the
|
||||
global loop. */
|
||||
|
||||
if (rc < 0)
|
||||
{
|
||||
PCRE2_SIZE save_start;
|
||||
if (rc == PCRE2_ERROR_NOMATCH) break;
|
||||
|
||||
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_CRLF ||
|
||||
code->newline_convention == PCRE2_NEWLINE_ANY ||
|
||||
code->newline_convention == PCRE2_NEWLINE_ANYCRLF) &&
|
||||
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;
|
||||
}
|
||||
if (rc < 0) goto EXIT;
|
||||
|
||||
/* 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. */
|
||||
|
|
@ -983,25 +991,27 @@ do
|
|||
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. */
|
||||
/* Assert that our replacement loop is making progress, checked even in
|
||||
release builds. This should be impossible to hit, however, an infinite loop
|
||||
would be fairly catastrophic.
|
||||
|
||||
if (ovecsave[0] == ovector[0] && ovecsave[1] == ovector[1])
|
||||
"Progress" is measured as ovector[1] strictly advancing, or, an empty match
|
||||
after a non-empty match. */
|
||||
|
||||
/* LCOV_EXCL_START */
|
||||
if (subs > 0 &&
|
||||
!(ovector[1] > ovecsave[1] ||
|
||||
(ovector[1] == ovector[0] && ovecsave[1] > ovecsave[0] &&
|
||||
ovector[1] == ovecsave[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 */
|
||||
}
|
||||
PCRE2_DEBUG_UNREACHABLE();
|
||||
rc = PCRE2_ERROR_INTERNAL_DUPMATCH;
|
||||
goto EXIT;
|
||||
}
|
||||
/* LCOV_EXCL_STOP */
|
||||
|
||||
ovecsave[0] = ovector[0];
|
||||
ovecsave[1] = ovector[1];
|
||||
|
||||
/* Count substitutions with a paranoid check for integer overflow; surely no
|
||||
real call to this function would ever hit this! */
|
||||
|
|
@ -1133,6 +1143,44 @@ do
|
|||
subptrend = subject + length;
|
||||
goto SUBPTR_SUBSTITUTE;
|
||||
}
|
||||
else if (next == CHAR_PLUS &&
|
||||
!(ptr+1 < repend && ptr[1] == CHAR_LEFT_CURLY_BRACKET))
|
||||
{
|
||||
/* Perl supports $+ for "highest captured group" (not the same as $^N
|
||||
which is mainly only useful inside Perl's match callbacks). We also
|
||||
don't accept "$+{..." since that's Perl syntax for our ${name}. */
|
||||
++ptr;
|
||||
if (code->top_bracket == 0)
|
||||
{
|
||||
/* Treat either as "no such group" or "all groups unset" based on the
|
||||
PCRE2_SUBSTITUTE_UNKNOWN_UNSET option. */
|
||||
if ((suboptions & PCRE2_SUBSTITUTE_UNKNOWN_UNSET) == 0)
|
||||
{
|
||||
rc = PCRE2_ERROR_NOSUBSTRING;
|
||||
goto PTREXIT;
|
||||
}
|
||||
group = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If we have any capture groups, then the ovector needs to be large
|
||||
enough for all of them, or the result won't be accurate. */
|
||||
if (match_data->oveccount < code->top_bracket + 1)
|
||||
{
|
||||
rc = PCRE2_ERROR_UNAVAILABLE;
|
||||
goto PTREXIT;
|
||||
}
|
||||
for (group = code->top_bracket; group > 0; group--)
|
||||
if (ovector[2*group] != PCRE2_UNSET) break;
|
||||
}
|
||||
if (group == 0)
|
||||
{
|
||||
if ((suboptions & PCRE2_SUBSTITUTE_UNSET_EMPTY) != 0) continue;
|
||||
rc = PCRE2_ERROR_UNSET;
|
||||
goto PTREXIT;
|
||||
}
|
||||
goto GROUP_SUBSTITUTE;
|
||||
}
|
||||
|
||||
if (next == CHAR_LEFT_CURLY_BRACKET)
|
||||
{
|
||||
|
|
@ -1627,19 +1675,25 @@ do
|
|||
}
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
/* Exit the global loop if we are not in global mode, or if pcre2_next_match()
|
||||
indicates we have reached the end of the subject. */
|
||||
|
||||
ovecsave[0] = ovector[0];
|
||||
ovecsave[1] = ovector[1];
|
||||
ovecsave[2] = start_offset;
|
||||
if ((suboptions & PCRE2_SUBSTITUTE_GLOBAL) == 0 ||
|
||||
!pcre2_next_match(match_data, &start_offset, &goptions))
|
||||
{
|
||||
start_offset = ovector[1];
|
||||
break;
|
||||
}
|
||||
|
||||
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 */
|
||||
/* Verify that pcre2_next_match() has not done a bumpalong (because we have
|
||||
already returned PCRE2_ERROR_BADSUBSPATTERN for \K in lookarounds).
|
||||
|
||||
We would otherwise have to memcpy the fragment spanning from ovector[1] to the
|
||||
new start_offset.*/
|
||||
|
||||
PCRE2_ASSERT(start_offset == ovector[1]);
|
||||
|
||||
} /* End of global loop */
|
||||
|
||||
/* Copy the rest of the subject unless not required, and terminate the output
|
||||
with a binary zero. */
|
||||
|
|
|
|||
|
|
@ -39,10 +39,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
*/
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "pcre2_internal.h"
|
||||
|
||||
|
||||
|
|
@ -126,7 +122,7 @@ 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],
|
||||
if (size != 0) memcpy(buffer, match_data->subject + match_data->ovector[stringnumber*2],
|
||||
CU2BYTES(size));
|
||||
buffer[size] = 0;
|
||||
*sizeptr = size;
|
||||
|
|
@ -218,7 +214,7 @@ 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],
|
||||
if (size != 0) memcpy(yield, match_data->subject + match_data->ovector[stringnumber*2],
|
||||
CU2BYTES(size));
|
||||
yield[size] = 0;
|
||||
*stringptr = yield;
|
||||
|
|
@ -259,7 +255,7 @@ 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
|
||||
sizeptr where to put the length, if not NULL
|
||||
|
||||
Returns: 0 if successful, else a negative error number
|
||||
*/
|
||||
|
|
@ -342,8 +338,15 @@ else /* Matched using pcre2_dfa_match() */
|
|||
|
||||
left = match_data->ovector[stringnumber*2];
|
||||
right = match_data->ovector[stringnumber*2+1];
|
||||
/* LCOV_EXCL_START - this appears to be unreachable, as the ovector and
|
||||
subject_length should always be set consistently, no matter what misbehaviour
|
||||
the caller has committed. */
|
||||
if (left > match_data->subject_length || right > match_data->subject_length)
|
||||
{
|
||||
PCRE2_DEBUG_UNREACHABLE();
|
||||
return PCRE2_ERROR_INVALIDOFFSET;
|
||||
}
|
||||
/* LCOV_EXCL_STOP */
|
||||
if (sizeptr != NULL) *sizeptr = (left > right)? 0 : right - left;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,27 +38,33 @@ 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
|
||||
|
||||
#if !defined(PCRE2_PCRE2TEST) && !defined(PCRE2_DFTABLES) && \
|
||||
!defined(PCRE2_PCRE2POSIX) /* We're compiling the library */
|
||||
#include "pcre2_internal.h"
|
||||
#endif /* PCRE2_PCRE2TEST */
|
||||
#endif
|
||||
|
||||
|
||||
/* Utility macros */
|
||||
#define ARR_SIZE(x) sizeof(x)/sizeof(x[0])
|
||||
|
||||
|
||||
#if !defined(PCRE2_PCRE2TEST) && !defined(PCRE2_DFTABLES) && \
|
||||
!defined(PCRE2_PCRE2POSIX)
|
||||
|
||||
/* 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. */
|
||||
|
|
@ -66,6 +72,11 @@ adding to classes. */
|
|||
const uint32_t PRIV(hspace_list)[] = { HSPACE_LIST };
|
||||
const uint32_t PRIV(vspace_list)[] = { VSPACE_LIST };
|
||||
|
||||
#endif /* !PCRE2_PCRE2TEST && !PCRE2_DFTABLES && !PCRE2_PCRE2POSIX */
|
||||
|
||||
|
||||
#if !defined(PCRE2_DFTABLES) && !defined(PCRE2_PCRE2POSIX)
|
||||
|
||||
/* 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. */
|
||||
|
|
@ -80,6 +91,8 @@ const uint32_t PRIV(callout_end_delims[]) = {
|
|||
CHAR_CIRCUMFLEX_ACCENT, CHAR_PERCENT_SIGN, CHAR_NUMBER_SIGN,
|
||||
CHAR_DOLLAR_SIGN, CHAR_RIGHT_CURLY_BRACKET, 0 };
|
||||
|
||||
#endif /* !PCRE2_DFTABLES && !PCRE2_PCRE2POSIX */
|
||||
|
||||
|
||||
/*************************************************
|
||||
* Tables for UTF-8 support *
|
||||
|
|
@ -90,23 +103,24 @@ 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)
|
||||
(!defined(PCRE2_DFTABLES) && !defined(PCRE2_PCRE2POSIX) && \
|
||||
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};
|
||||
{ 0x7f, 0x7ff, 0xffff, 0x1fffff, 0x3ffffff, 0x7fffffff };
|
||||
|
||||
const int PRIV(utf8_table1_size) = sizeof(PRIV(utf8_table1)) / sizeof(int);
|
||||
const unsigned PRIV(utf8_table1_size) = ARR_SIZE(PRIV(utf8_table1));
|
||||
|
||||
/* 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};
|
||||
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. */
|
||||
|
|
@ -120,10 +134,11 @@ const uint8_t PRIV(utf8_table4)[] = {
|
|||
#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
|
||||
support is enabled. See also the pcre2_ucptables_inc.h file, which is generated by
|
||||
a Python script from Unicode data files. */
|
||||
|
||||
#ifdef SUPPORT_UNICODE
|
||||
#if !defined(PCRE2_DFTABLES) && !defined(PCRE2_PCRE2POSIX) && \
|
||||
defined(SUPPORT_UNICODE)
|
||||
|
||||
/* Table to translate from particular type value to the general value. */
|
||||
|
||||
|
|
@ -227,8 +242,69 @@ const int PRIV(ucp_typerange)[] = {
|
|||
/* Finally, include the tables that are auto-generated from the Unicode data
|
||||
files. */
|
||||
|
||||
#include "pcre2_ucptables.c"
|
||||
#include "pcre2_ucptables_inc.h"
|
||||
|
||||
#endif /* SUPPORT_UNICODE */
|
||||
#endif /* Unicode support needed */
|
||||
|
||||
|
||||
/*************************************************
|
||||
* Tables for EBCDIC support *
|
||||
*************************************************/
|
||||
|
||||
#if defined(EBCDIC) && \
|
||||
(defined(PCRE2_PCRE2TEST) || defined(PCRE2_DFTABLES) || 'a' != 0x81)
|
||||
|
||||
const uint8_t PRIV(ebcdic_1047_to_ascii)[256] = {
|
||||
0x00,0x01,0x02,0x03,0x9c,0x09,0x86,0x7f,0x97,0x8d,0x8e,0x0b,0x0c,0x0d,0x0e,0x0f,
|
||||
#ifdef EBCDIC_NL25
|
||||
0x10,0x11,0x12,0x13,0x9d,0x85,0x08,0x87,0x18,0x19,0x92,0x8f,0x1c,0x1d,0x1e,0x1f,
|
||||
0x80,0x81,0x82,0x83,0x84,0x0a,0x17,0x1b,0x88,0x89,0x8a,0x8b,0x8c,0x05,0x06,0x07,
|
||||
#else
|
||||
0x10,0x11,0x12,0x13,0x9d,0x0a,0x08,0x87,0x18,0x19,0x92,0x8f,0x1c,0x1d,0x1e,0x1f,
|
||||
0x80,0x81,0x82,0x83,0x84,0x85,0x17,0x1b,0x88,0x89,0x8a,0x8b,0x8c,0x05,0x06,0x07,
|
||||
#endif
|
||||
0x90,0x91,0x16,0x93,0x94,0x95,0x96,0x04,0x98,0x99,0x9a,0x9b,0x14,0x15,0x9e,0x1a,
|
||||
0x20,0xa0,0xe2,0xe4,0xe0,0xe1,0xe3,0xe5,0xe7,0xf1,0xa2,0x2e,0x3c,0x28,0x2b,0x7c,
|
||||
0x26,0xe9,0xea,0xeb,0xe8,0xed,0xee,0xef,0xec,0xdf,0x21,0x24,0x2a,0x29,0x3b,0x5e,
|
||||
0x2d,0x2f,0xc2,0xc4,0xc0,0xc1,0xc3,0xc5,0xc7,0xd1,0xa6,0x2c,0x25,0x5f,0x3e,0x3f,
|
||||
0xf8,0xc9,0xca,0xcb,0xc8,0xcd,0xce,0xcf,0xcc,0x60,0x3a,0x23,0x40,0x27,0x3d,0x22,
|
||||
0xd8,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0xab,0xbb,0xf0,0xfd,0xfe,0xb1,
|
||||
0xb0,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0xaa,0xba,0xe6,0xb8,0xc6,0xa4,
|
||||
0xb5,0x7e,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0xa1,0xbf,0xd0,0x5b,0xde,0xae,
|
||||
0xac,0xa3,0xa5,0xb7,0xa9,0xa7,0xb6,0xbc,0xbd,0xbe,0xdd,0xa8,0xaf,0x5d,0xb4,0xd7,
|
||||
0x7b,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0xad,0xf4,0xf6,0xf2,0xf3,0xf5,
|
||||
0x7d,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x52,0xb9,0xfb,0xfc,0xf9,0xfa,0xff,
|
||||
0x5c,0xf7,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0xb2,0xd4,0xd6,0xd2,0xd3,0xd5,
|
||||
0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0xb3,0xdb,0xdc,0xd9,0xda,0x9f,
|
||||
};
|
||||
|
||||
const uint8_t PRIV(ascii_to_ebcdic_1047)[256] = {
|
||||
#ifdef EBCDIC_NL25
|
||||
0x00,0x01,0x02,0x03,0x37,0x2d,0x2e,0x2f,0x16,0x05,0x25,0x0b,0x0c,0x0d,0x0e,0x0f,
|
||||
#else
|
||||
0x00,0x01,0x02,0x03,0x37,0x2d,0x2e,0x2f,0x16,0x05,0x15,0x0b,0x0c,0x0d,0x0e,0x0f,
|
||||
#endif
|
||||
0x10,0x11,0x12,0x13,0x3c,0x3d,0x32,0x26,0x18,0x19,0x3f,0x27,0x1c,0x1d,0x1e,0x1f,
|
||||
0x40,0x5a,0x7f,0x7b,0x5b,0x6c,0x50,0x7d,0x4d,0x5d,0x5c,0x4e,0x6b,0x60,0x4b,0x61,
|
||||
0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0x7a,0x5e,0x4c,0x7e,0x6e,0x6f,
|
||||
0x7c,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,
|
||||
0xd7,0xd8,0xd9,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xad,0xe0,0xbd,0x5f,0x6d,
|
||||
0x79,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x91,0x92,0x93,0x94,0x95,0x96,
|
||||
0x97,0x98,0x99,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xc0,0x4f,0xd0,0xa1,0x07,
|
||||
#ifdef EBCDIC_NL25
|
||||
0x20,0x21,0x22,0x23,0x24,0x15,0x06,0x17,0x28,0x29,0x2a,0x2b,0x2c,0x09,0x0a,0x1b,
|
||||
#else
|
||||
0x20,0x21,0x22,0x23,0x24,0x25,0x06,0x17,0x28,0x29,0x2a,0x2b,0x2c,0x09,0x0a,0x1b,
|
||||
#endif
|
||||
0x30,0x31,0x1a,0x33,0x34,0x35,0x36,0x08,0x38,0x39,0x3a,0x3b,0x04,0x14,0x3e,0xff,
|
||||
0x41,0xaa,0x4a,0xb1,0x9f,0xb2,0x6a,0xb5,0xbb,0xb4,0x9a,0x8a,0xb0,0xca,0xaf,0xbc,
|
||||
0x90,0x8f,0xea,0xfa,0xbe,0xa0,0xb6,0xb3,0x9d,0xda,0x9b,0x8b,0xb7,0xb8,0xb9,0xab,
|
||||
0x64,0x65,0x62,0x66,0x63,0x67,0x9e,0x68,0x74,0x71,0x72,0x73,0x78,0x75,0x76,0x77,
|
||||
0xac,0x69,0xed,0xee,0xeb,0xef,0xec,0xbf,0x80,0xfd,0xfe,0xfb,0xfc,0xba,0xae,0x59,
|
||||
0x44,0x45,0x42,0x46,0x43,0x47,0x9c,0x48,0x54,0x51,0x52,0x53,0x58,0x55,0x56,0x57,
|
||||
0x8c,0x49,0xcd,0xce,0xcb,0xcf,0xcc,0xe1,0x70,0xdd,0xde,0xdb,0xdc,0x8d,0x8e,0xdf,
|
||||
};
|
||||
|
||||
#endif /* EBCDIC support needed */
|
||||
|
||||
/* End of pcre2_tables.c */
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
/* This file contains tables of Unicode properties that are extracted from
|
||||
Unicode data files. See the comments at the start of maint/GenerateUcd.py for
|
||||
details.
|
||||
|
|
@ -52,13 +53,13 @@ _pcre2_xxx to xxxx, thereby avoiding name clashes with the library. At present,
|
|||
just one of these tables is actually needed. When compiling the library, some
|
||||
headers are needed. */
|
||||
|
||||
|
||||
#ifndef PCRE2_PCRE2TEST
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
#include "pcre2_internal.h"
|
||||
#endif /* PCRE2_PCRE2TEST */
|
||||
|
||||
|
||||
|
||||
/* The tables herein are needed only when UCP support is built, and in PCRE2
|
||||
that happens automatically with UTF support. This module should not be
|
||||
referenced otherwise, so it should not matter whether it is compiled or not.
|
||||
|
|
|
|||
|
|
@ -1593,4 +1593,4 @@ const size_t PRIV(utt_size) = sizeof(PRIV(utt)) / sizeof(ucp_type_table);
|
|||
|
||||
#endif /* SUPPORT_UNICODE */
|
||||
|
||||
/* End of pcre2_ucptables.c */
|
||||
/* End of pcre2_ucptables_inc.h */
|
||||
|
|
@ -71,6 +71,8 @@ side-effects. */
|
|||
} while(0)
|
||||
#endif
|
||||
|
||||
/* LCOV_EXCL_START */
|
||||
|
||||
/* PCRE2_UNREACHABLE() can be used to mark locations on the code that
|
||||
shouldn't be reached. In non debug builds is defined as a hint for
|
||||
the compiler to eliminate any code after it, so it is useful also for
|
||||
|
|
@ -107,8 +109,16 @@ the reason and the actions that should be taken if it ever triggers. */
|
|||
|
||||
#define PCRE2_DEBUG_UNREACHABLE() PCRE2_UNREACHABLE()
|
||||
|
||||
/* LCOV_EXCL_STOP */
|
||||
|
||||
#endif /* PCRE2_DEBUG */
|
||||
|
||||
#ifndef PCRE2_ASSERT
|
||||
#define PCRE2_ASSERT(x) do {} while(0)
|
||||
#endif
|
||||
|
||||
/* LCOV_EXCL_START */
|
||||
|
||||
#ifndef PCRE2_DEBUG_UNREACHABLE
|
||||
#define PCRE2_DEBUG_UNREACHABLE() do {} while(0)
|
||||
#endif
|
||||
|
|
@ -123,8 +133,45 @@ the reason and the actions that should be taken if it ever triggers. */
|
|||
#endif
|
||||
#endif /* !PCRE2_UNREACHABLE */
|
||||
|
||||
#ifndef PCRE2_ASSERT
|
||||
#define PCRE2_ASSERT(x) do {} while(0)
|
||||
/* LCOV_EXCL_STOP */
|
||||
|
||||
/* We define this fallthrough macro for suppressing -Wimplicit-fallthrough warnings.
|
||||
Clang only allows this via an attribute, whereas other compilers (eg. GCC) match attributes
|
||||
and also specially-formatted comments.
|
||||
|
||||
This macro should be used with no following semicolon, and ideally with a comment: */
|
||||
|
||||
// PCRE2_FALLTHROUGH /* Fall through */
|
||||
|
||||
#ifndef PCRE2_FALLTHROUGH
|
||||
|
||||
#if defined(__cplusplus) && __cplusplus >= 202002L && \
|
||||
defined(__has_cpp_attribute)
|
||||
/* Standards-compatible C++ variant. */
|
||||
#if __has_cpp_attribute(fallthrough)
|
||||
#define PCRE2_FALLTHROUGH [[fallthrough]];
|
||||
#endif
|
||||
#elif !defined(__cplusplus) && \
|
||||
defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L && \
|
||||
defined(__has_c_attribute)
|
||||
/* Standards-compatible C variant. */
|
||||
#if __has_c_attribute(fallthrough)
|
||||
#define PCRE2_FALLTHROUGH [[fallthrough]];
|
||||
#endif
|
||||
#elif ((defined(__clang__) && __clang_major__ >= 10) || \
|
||||
(defined(__GNUC__) && __GNUC__ >= 7)) && \
|
||||
defined(__has_attribute)
|
||||
/* Clang and GCC syntax. Rule out old versions because apparently Clang at
|
||||
least has a broken implementation of __has_attribute. */
|
||||
#if __has_attribute(fallthrough)
|
||||
#define PCRE2_FALLTHROUGH __attribute__((fallthrough));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* !PCRE2_FALLTHROUGH */
|
||||
|
||||
#ifndef PCRE2_FALLTHROUGH
|
||||
#define PCRE2_FALLTHROUGH
|
||||
#endif
|
||||
|
||||
#endif /* PCRE2_UTIL_H_IDEMPOTENT_GUARD */
|
||||
|
|
|
|||
|
|
@ -44,14 +44,13 @@ strings. This file is also #included by the pcre2test program, which uses
|
|||
macros to change 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 */
|
||||
|
||||
|
||||
|
||||
#ifndef SUPPORT_UNICODE
|
||||
/*************************************************
|
||||
* Dummy function when Unicode is not supported *
|
||||
|
|
|
|||
|
|
@ -38,18 +38,16 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
/* This module contains two internal functions that are used to match
|
||||
OP_XCLASS and OP_ECLASS. It is used by pcre2_auto_possessify() and by both
|
||||
pcre2_match() and pcre2_dfa_match(). */
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
|
||||
#include "pcre2_internal.h"
|
||||
|
||||
|
||||
|
||||
/*************************************************
|
||||
* Match character against an XCLASS *
|
||||
*************************************************/
|
||||
|
|
@ -252,9 +250,11 @@ if (*data == XCL_PROP || *data == XCL_NOTPROP)
|
|||
/* This should never occur, but compilers may mutter if there is no
|
||||
default. */
|
||||
|
||||
/* LCOV_EXCL_START */
|
||||
default:
|
||||
PCRE2_DEBUG_UNREACHABLE();
|
||||
return FALSE;
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
data += 2;
|
||||
|
|
@ -529,9 +529,11 @@ while (ptr < data_end)
|
|||
/* This should never occur, but compilers may mutter if there is no
|
||||
default. */
|
||||
|
||||
/* LCOV_EXCL_START */
|
||||
default:
|
||||
PCRE2_DEBUG_UNREACHABLE();
|
||||
return FALSE;
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue