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
9 changes: 6 additions & 3 deletions src/constant_pool.c
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,9 @@ pm_constant_pool_find(const pm_constant_pool_t *pool, const uint8_t *start, size
pm_constant_pool_bucket_t *bucket;

while (bucket = &pool->buckets[index], bucket->id != PM_CONSTANT_ID_UNSET) {
if ((bucket->length == length) && memcmp(bucket->start, start, length) == 0) {
// Compare the stored hash before touching the contents so that probe
// collisions are rejected without a memcmp call.
if ((bucket->hash == hash) && (bucket->length == length) && memcmp(bucket->start, start, length) == 0) {
return bucket->id;
}

Expand Down Expand Up @@ -274,8 +276,9 @@ pm_constant_pool_insert(pm_arena_t *arena, pm_constant_pool_t *pool, const uint8
while (bucket = &pool->buckets[index], bucket->id != PM_CONSTANT_ID_UNSET) {
// If there is a collision, then we need to check if the content is the
// same as the content we are trying to insert. If it is, then we can
// return the id of the existing constant.
if ((bucket->length == length) && memcmp(bucket->start, start, length) == 0) {
// return the id of the existing constant. Compare the stored hash
// first so that probe collisions are rejected without a memcmp call.
if ((bucket->hash == hash) && (bucket->length == length) && memcmp(bucket->start, start, length) == 0) {
// Since we have found a match, we need to check if this is
// attempting to insert a shared or an owned constant. We want to
// prefer shared constants since they don't require allocations.
Expand Down
15 changes: 13 additions & 2 deletions src/prism.c
Original file line number Diff line number Diff line change
Expand Up @@ -8716,6 +8716,13 @@ lex_identifier(pm_parser_t *parser, bool previous_command_start) {
if (encoding_changed) {
return parser->encoding->isupper_char(current_start, end - current_start) ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
}

/* Identifiers usually start with an ASCII byte, for which the uppercase
* check is a simple range comparison. This avoids the call into the
* encoding module for every identifier. */
if (*current_start < 0x80) {
return (*current_start >= 'A' && *current_start <= 'Z') ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
}
return pm_encoding_utf_8_isupper_char(current_start, end - current_start) ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
}

Expand Down Expand Up @@ -10093,7 +10100,11 @@ parser_lex(pm_parser_t *parser) {
// token. Skip runs of inline whitespace in bulk to avoid per-character
// stores back to parser->current.end.
bool chomping = true;
while (parser->current.end < parser->end && chomping) {
while (chomping) {
/* Skip the run of inline whitespace in bulk, then decide what
* to do based on the first byte after it. Handling both in a
* single pass avoids re-entering the scan when the run was
* non-empty, which is the common case. */
{
static const uint8_t inline_whitespace[256] = {
[' '] = 1, ['\t'] = 1, ['\f'] = 1, ['\v'] = 1
Expand All @@ -10103,8 +10114,8 @@ parser_lex(pm_parser_t *parser) {
if (scan > parser->current.end) {
parser->current.end = scan;
space_seen = true;
continue;
}
if (scan >= parser->end) break;
}

switch (*parser->current.end) {
Expand Down