pcre2: Update to 10.47

This commit is contained in:
Rémi Verschelde 2025-12-12 23:10:07 +01:00
parent 08e6cd181f
commit 36e7675d6d
No known key found for this signature in database
GPG Key ID: C3336907360768E1
69 changed files with 8548 additions and 3234 deletions

View File

@ -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",
]

11
thirdparty/README.md vendored
View File

@ -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`

View File

@ -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

View File

@ -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

View File

@ -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();
}

View File

@ -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

View File

@ -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 */

View File

@ -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

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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

View File

@ -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));

View File

@ -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));

View File

@ -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) {

View File

@ -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);
}

View File

@ -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))

View File

@ -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 */

View File

@ -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_)

View File

@ -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)
{

View File

@ -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)[] = {

View File

@ -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

View File

@ -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 */

View File

@ -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 */

View File

@ -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)

View File

@ -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;

View File

@ -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;

View File

@ -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 */
}

View File

@ -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;
}

View File

@ -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 */

View File

@ -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

View File

@ -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 *
*************************************************/

View File

@ -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 */

View File

@ -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 */

View File

@ -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

View File

@ -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 */

View File

@ -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 */

View File

@ -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

View File

@ -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)
{

View File

@ -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;
}

View File

@ -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);

171
thirdparty/pcre2/src/pcre2_match_next.c vendored Normal file
View File

@ -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 */

View File

@ -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"

View File

@ -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 */

View File

@ -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)
{

View File

@ -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 *
*************************************************/

View File

@ -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

View File

@ -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 *

View File

@ -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;
}
}

View File

@ -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. */

View File

@ -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;
}

View File

@ -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 */

View File

@ -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.

View File

@ -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 */

View File

@ -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 */

View File

@ -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 *

View File

@ -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 */
}
}