Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 17 additions & 7 deletions ext/json/ext/parser/parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -612,12 +612,14 @@ json_eat_whitespace(JSON_ParserState *state)
while (rest(state) > 8) {
uint64_t chunk;
memcpy(&chunk, state->cursor, sizeof(uint64_t));
size_t consecutive_spaces = trailing_zeros64(chunk ^ 0x2020202020202020) / CHAR_BIT;
if (chunk == 0x2020202020202020) {
state->cursor += 8;
continue;
}

uint32_t consecutive_spaces = trailing_zeros64(chunk ^ 0x2020202020202020) / CHAR_BIT;
state->cursor += consecutive_spaces;
if (consecutive_spaces != 8) {
break;
}
break;
}
#endif
break;
Expand Down Expand Up @@ -1101,13 +1103,21 @@ static inline int json_parse_digits(JSON_ParserState *state, uint64_t *accumulat
continue;
}

if ((match & 0xFFFFFFFF) == 0x33333333) { // 4 consecutive digits
uint32_t consecutive_digits = trailing_zeros64(match ^ 0x3333333333333333) / CHAR_BIT;

if (consecutive_digits >= 4) {
*accumulator = (*accumulator * 10000) + decode_4digits_unrolled((uint32_t)next_8bytes);
state->cursor += 4;
break;
consecutive_digits -= 4;
}

while (consecutive_digits) {
*accumulator = *accumulator * 10 + (*state->cursor - '0');
consecutive_digits--;
state->cursor++;
}

break;
return (int)(state->cursor - start);
}
#endif

Expand Down
12 changes: 12 additions & 0 deletions ext/json/ext/simd/simd.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
#ifdef JSON_DEBUG
#include <assert.h>
#endif

typedef enum {
SIMD_NONE,
SIMD_NEON,
Expand All @@ -18,6 +22,10 @@ typedef enum {

static inline uint32_t trailing_zeros64(uint64_t input)
{
#ifdef JSON_DEBUG
assert(input > 0); // __builtin_ctz(0) is undefined behavior
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm doubting these asserts can actually fail. Not too sure what the compilation flags are on CI, but seems like they are optimized out even with JSON_DEBUG.

I'm unsure what's the best way to add assertions in ruby extensions. Perhaps I should just use RUBY_ASSERT and add a debug ruby in the CI matrix?

#endif

#if HAVE_BUILTIN_CTZLL
return __builtin_ctzll(input);
#else
Expand All @@ -33,6 +41,10 @@ static inline uint32_t trailing_zeros64(uint64_t input)

static inline int trailing_zeros(int input)
{
#ifdef JSON_DEBUG
assert(input > 0); // __builtin_ctz(0) is undefined behavior
#endif

#if HAVE_BUILTIN_CTZLL
return __builtin_ctz(input);
#else
Expand Down
4 changes: 4 additions & 0 deletions test/json/json_parser_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -804,6 +804,10 @@ def test_parse_leading_slash
end
end

def test_parse_whitespace_after_newline
assert_equal [], JSON.parse("[\n#{' ' * (8 + 8 + 4 + 3)}]")
end

private

def assert_equal_float(expected, actual, delta = 1e-2)
Expand Down
Loading