Skip to content
Merged
6 changes: 2 additions & 4 deletions embed.fnc
Original file line number Diff line number Diff line change
Expand Up @@ -4010,6 +4010,8 @@ CRTdip |UV |valid_utf8_to_uv \
CRTdmp |UV |valid_utf8_to_uvchr \
|NN const U8 *s \
|NULLOK STRLEN *retlen
CRTip |unsigned int|variant_byte_number \
|PERL_UINTMAX_T word
Adp |int |vcmp |NN SV *lhv \
|NN SV *rhv
Adpr |void |vcroak |NULLOK const char *pat \
Expand Down Expand Up @@ -4108,10 +4110,6 @@ TXp |void |set_padlist |NN CV *cv \
: Used in sv.c
p |void |dump_sv_child |NN SV *sv
#endif
#if !defined(EBCDIC)
CRTip |unsigned int|variant_byte_number \
|PERL_UINTMAX_T word
#endif
#if defined(F_FREESP) && !defined(HAS_CHSIZE) && !defined(HAS_TRUNCATE)
ARdp |I32 |my_chsize |int fd \
|Off_t length
Expand Down
4 changes: 1 addition & 3 deletions embed.h
Original file line number Diff line number Diff line change
Expand Up @@ -848,6 +848,7 @@
# define valid_identifier_sv(a) Perl_valid_identifier_sv(aTHX_ a)
# define valid_utf8_to_uv Perl_valid_utf8_to_uv
# define Perl_valid_utf8_to_uvchr valid_utf8_to_uvchr
# define variant_byte_number Perl_variant_byte_number
# define vcmp(a,b) Perl_vcmp(aTHX_ a,b)
# define vcroak(a,b) Perl_vcroak(aTHX_ a,b)
# define vdeb(a,b) Perl_vdeb(aTHX_ a,b)
Expand All @@ -874,9 +875,6 @@
# define pad_setsv(a,b) Perl_pad_setsv(aTHX_ a,b)
# define pad_sv(a) Perl_pad_sv(aTHX_ a)
# endif
# if !defined(EBCDIC)
# define variant_byte_number Perl_variant_byte_number
# endif
# if defined(F_FREESP) && !defined(HAS_CHSIZE) && !defined(HAS_TRUNCATE)
# define my_chsize(a,b) Perl_my_chsize(aTHX_ a,b)
# endif
Expand Down
153 changes: 97 additions & 56 deletions inline.h
Original file line number Diff line number Diff line change
Expand Up @@ -1361,7 +1361,7 @@ Perl_valid_utf8_to_uv(const U8 *s, STRLEN *retlen)
/* Note that this is branchless except for the switch() jump table, and
* checking that the caller wants a *retlen returned.
*
* There is wasted effort for length 1 inputs of initializing 'uv' to 0
* There is wasted effort for length 1 inputs of initializing 'uv' to 0
* and calculating 'full_shift' (unless the compiler optimizes that out).
* Benchmarks indicate this is acceptable.
* See GH #23690 */
Expand Down Expand Up @@ -1459,14 +1459,60 @@ Perl_valid_utf8_to_uv(const U8 *s, STRLEN *retlen)
# define PERL_WORDSIZE sizeof(PERL_UINTMAX_T)
# define PERL_WORD_BOUNDARY_MASK (PERL_WORDSIZE - 1)

/* Evaluates to 0 if 'x' is at a word boundary; otherwise evaluates to 1, by
* or'ing together the lowest bits of 'x'. Hopefully the final term gets
* optimized out completely on a 32-bit system, and its mask gets optimized out
* on a 64-bit system */
# define PERL_IS_SUBWORD_ADDR(x) (1 & ( PTR2nat(x) \
| ( PTR2nat(x) >> 1) \
| ( ( (PTR2nat(x) \
& PERL_WORD_BOUNDARY_MASK) >> 2))))
/* Given an address of a byte 'x', how many bytes away is that address to the
* following closest full word boundary. */
# define BYTES_REMAINING_IN_WORD(x) \
( (PERL_WORDSIZE - (PTR2nat(x) & PERL_WORD_BOUNDARY_MASK)) \
& PERL_WORD_BOUNDARY_MASK)
/* For example, consider two addresses in an 8 byte word size (the dots are
* don't cares):
* 0b...............010 0b...............000
* ((8 - (0b1101010 & 0x7)) & 0x7) ((8 - (0b1101000 & 0x7)) & 0x7)
* ((8 - 0b10) & 0x7) ((8 - 0) & 0x7)
* (6 & 0x7) (8 & 0x7)
* 6 0 */

/* Some tasks that are byte-oriented can be done as well a full word-at-a-time,
* running 8 times faster on an 8-byte word, for example. But there is
* generally extra setup required to do this, and byte-at-a-time must be used
* anyway to get to the next word boundary. This macro calculates whether the
* trade-off is worth doing. If not, it returns NULL; if so, it returns a
* pointer to the first byte of the next word. Code using this is typically
* structured like:
* U8 * next_word_boundary = WORTH_PER_LOOP()
* if (next_word_boundary) {
* loop per-byte until next_word_boundary
* loop per-word until less than a word left before upper boundary
* }
* loop per-byte until reach final boundary
*
* 's' is the current position in the string
* 'e' is the upper string bound
* 'full_words_needed' is the caller's determination of where to make the
* trade-off between per-byte and per-word. Only if the number of words
* in the input string is at least this many, does the macro return
* non-NULL.
*
* Because of EBCDIC, there are two forms of this macro.
* WORTH_PER_WORD_LOOP_BINMODE() is for use when the data being examined is
* not dependent on the character set. The more usual form is plain
* WORTH_PER_WORD_LOOP() for character data. Because EBCDIC needs an extra
* transformation, per-word operations are not appropriate on it, so the macro
* always returns NULL, meaning don't use a per-word loop on an EBCDIC
* platform. */
# define WORTH_PER_WORD_LOOP_BINMODE(s, e, full_words_needed) \
/* Note multiple evaluations of 's' */ \
( ( ( (s) + BYTES_REMAINING_IN_WORD(s) \
+ (full_words_needed) * PERL_WORDSIZE) < (e) ) \
? ((s) + BYTES_REMAINING_IN_WORD(s)) \
: NULL)

# ifdef EBCDIC
# define WORTH_PER_WORD_LOOP(s, e, f) NULL
# else
# define WORTH_PER_WORD_LOOP(s, e, f) \
WORTH_PER_WORD_LOOP_BINMODE(s, e, f)
# endif

/*
=for apidoc is_utf8_invariant_string
Expand Down Expand Up @@ -1515,35 +1561,22 @@ C<L</is_utf8_string>> and C<L</is_utf8_fixed_width_buf_flags>>.
PERL_STATIC_INLINE bool
Perl_is_utf8_invariant_string_loc(const U8* const s, STRLEN len, const U8 ** ep)
{
const U8* send;
const U8* x = s;

PERL_ARGS_ASSERT_IS_UTF8_INVARIANT_STRING_LOC;

const U8* send = s + len;
const U8* x = s;

if (len == 0) {
len = strlen((const char *)s);
}

send = s + len;

#ifndef EBCDIC

/* Do the word-at-a-time iff there is at least one usable full word. That
* means that after advancing to a word boundary, there still is at least a
* full word left. The number of bytes needed to advance is 'wordsize -
* offset' unless offset is 0. */
if ((STRLEN) (send - x) >= PERL_WORDSIZE

/* This term is wordsize if subword; 0 if not */
+ PERL_WORDSIZE * PERL_IS_SUBWORD_ADDR(x)
* full word left. */
const U8 * const per_byte_end = WORTH_PER_WORD_LOOP(x, send, 1);

/* 'offset' */
- (PTR2nat(x) & PERL_WORD_BOUNDARY_MASK))
{

/* Process per-byte until reach word boundary. XXX This loop could be
* eliminated if we knew that this platform had fast unaligned reads */
while (PTR2nat(x) & PERL_WORD_BOUNDARY_MASK) {
if (per_byte_end) {
while (x < per_byte_end ) {
if (! UTF8_IS_INVARIANT(*x)) {
if (ep) {
*ep = x;
Expand Down Expand Up @@ -1585,8 +1618,6 @@ Perl_is_utf8_invariant_string_loc(const U8* const s, STRLEN len, const U8 ** ep)
} while (x + PERL_WORDSIZE <= send);
}

#endif /* End of ! EBCDIC */

/* Process per-byte. (Can't use libc functions like strpbrk() because
* input isn't necessarily a C string) */
while (x < send) {
Expand Down Expand Up @@ -1977,13 +2008,20 @@ Perl_single_1bit_pos32(U32 word)

}

#ifndef EBCDIC
/* Returns the byte number of the lowest numbered-byte whose uppermost bit is
* set */
#define first_upper_bit_set_byte_number(word) Perl_variant_byte_number(word)

PERL_STATIC_INLINE unsigned int
Perl_variant_byte_number(PERL_UINTMAX_T word)
{
/* This returns the position in a word (0..7) of the first variant byte in
* it. This is a helper function. Note that there are no branches */
/* This returns the position in a word (0..7) of the first byte whose
* uppermost bit is set. On ASCII boxes, this is equivalent to the first
* byte whose representation is different in UTF-8 vs not, hence the name
* and text in the comments. It was only later that this was used for
* binary data, not tied to the character set.
*
* This is a helper function. Note that there are no branches */

/* Get just the msb bits of each byte */
word &= PERL_VARIANTS_WORD_MASK;
Expand All @@ -1992,7 +2030,7 @@ Perl_variant_byte_number(PERL_UINTMAX_T word)
* word */
assert(word);

# if BYTEORDER == 0x1234 || BYTEORDER == 0x12345678
#if BYTEORDER == 0x1234 || BYTEORDER == 0x12345678

/* Bytes are stored like
* Byte8 ... Byte2 Byte1
Expand All @@ -2005,7 +2043,7 @@ Perl_variant_byte_number(PERL_UINTMAX_T word)
* to 0..7 */
return (unsigned int) ((word + 1) >> 3) - 1;

# elif BYTEORDER == 0x4321 || BYTEORDER == 0x87654321
#elif BYTEORDER == 0x4321 || BYTEORDER == 0x87654321

/* Bytes are stored like
* Byte1 Byte2 ... Byte8
Expand All @@ -2024,13 +2062,24 @@ Perl_variant_byte_number(PERL_UINTMAX_T word)

return (unsigned int) word;

# else
# error Unexpected byte order
# endif
#else /* Unhandled byte-order; the compiler knows which comes first */

}
const U8 * bytes = (U8 *) &word;
for (unsigned int i = 0; i < sizeof(word); i++) {
if (bytes[i]) {
return i;
}
}

assert(0);

/* If all else fails, it's better to return something than just random */
return 0;

#endif

}

#if defined(PERL_CORE) || defined(PERL_EXT)

/*
Expand Down Expand Up @@ -2063,23 +2112,16 @@ C<L<perlapi/is_utf8_invariant_string_loc>>,
PERL_STATIC_INLINE Size_t
S_variant_under_utf8_count(const U8* const s, const U8* const e)
{
const U8* x = s;
Size_t count = 0;

PERL_ARGS_ASSERT_VARIANT_UNDER_UTF8_COUNT;

# ifndef EBCDIC
const U8* x = s;
Size_t count = 0;

/* Test if the string is long enough to use word-at-a-time. (Logic is the
* same as for is_utf8_invariant_string()) */
if ((STRLEN) (e - x) >= PERL_WORDSIZE
+ PERL_WORDSIZE * PERL_IS_SUBWORD_ADDR(x)
- (PTR2nat(x) & PERL_WORD_BOUNDARY_MASK))
{

/* Process per-byte until reach word boundary. XXX This loop could be
* eliminated if we knew that this platform had fast unaligned reads */
while (PTR2nat(x) & PERL_WORD_BOUNDARY_MASK) {
const U8 * const per_byte_end = WORTH_PER_WORD_LOOP(x, e, 1);
if (per_byte_end) {
while (x < per_byte_end ) {
count += ! UTF8_IS_INVARIANT(*x++);
}

Expand All @@ -2095,8 +2137,6 @@ S_variant_under_utf8_count(const U8* const s, const U8* const e)
} while (x + PERL_WORDSIZE <= e);
}

# endif

/* Process per-byte */
while (x < e) {
if (! UTF8_IS_INVARIANT(*x)) {
Expand All @@ -2117,6 +2157,7 @@ S_variant_under_utf8_count(const U8* const s, const U8* const e)
# undef PERL_COUNT_MULTIPLIER
# undef PERL_WORD_BOUNDARY_MASK
# undef PERL_VARIANTS_WORD_MASK
# undef BYTES_REMAINING_IN_WORD
#endif

#define is_utf8_string(s, len) is_utf8_string_loclen(s, len, NULL, NULL)
Expand Down Expand Up @@ -3284,7 +3325,7 @@ Perl_utf8_to_uv_msgs(const U8 * const s0,
*
* The terminology of the dfa refers to a 'class'. The variable 'type'
* would have been named 'class' except that is a reserved word in C++
*
*
* The table can be a U16 on EBCDIC platforms, so 'state' is declared
* as U16; 'type' is likely to never occupy more than 5 bits. */
PERL_UINT_FAST8_T type = PL_strict_utf8_dfa_tab[*s];
Expand Down Expand Up @@ -4758,7 +4799,7 @@ extracted from C<sv> using L</C<SvPV_const>>. C<sv> must not be NULL.
Memory deallocation

To prevent memory leaks, the memory allocated for the new string needs to be
freed when no longer needed.
freed when no longer needed.

=over

Expand Down
15 changes: 5 additions & 10 deletions proto.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading