Skip to content

Commit

Permalink
Merge pull request #1525 from ruby/u32
Browse files Browse the repository at this point in the history
Explicitly use u32 for constant pool
  • Loading branch information
kddnewton authored Sep 19, 2023
2 parents 7846a6c + 32b173e commit 12963ee
Show file tree
Hide file tree
Showing 6 changed files with 27 additions and 28 deletions.
8 changes: 4 additions & 4 deletions include/yarp/util/yp_constant_pool.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,20 +44,20 @@ typedef struct {
bool owned: 1;
const uint8_t *start;
size_t length;
size_t hash;
uint32_t hash;
} yp_constant_t;

typedef struct {
yp_constant_t *constants;
size_t size;
size_t capacity;
uint32_t size;
uint32_t capacity;
} yp_constant_pool_t;

// Define an empty constant pool.
#define YP_CONSTANT_POOL_EMPTY ((yp_constant_pool_t) { .constants = NULL, .size = 0, .capacity = 0 })

// Initialize a new constant pool with a given capacity.
bool yp_constant_pool_init(yp_constant_pool_t *pool, size_t capacity);
bool yp_constant_pool_init(yp_constant_pool_t *pool, uint32_t capacity);

// Insert a constant into a constant pool that is a slice of a source string.
// Returns the id of the constant, or 0 if any potential calls to resize fail.
Expand Down
2 changes: 1 addition & 1 deletion rust/yarp/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -552,7 +552,7 @@ impl<'pr> ConstantId<'pr> {{
unsafe {{
let pool = &(*self.parser.as_ptr()).constant_pool;
for i in 0..pool.capacity {{
let constant = &(*pool.constants.add(i));
let constant = &(*pool.constants.add(i.try_into().unwrap()));
if constant.id() == self.id {{
return std::slice::from_raw_parts(constant.start, constant.length);
}}
Expand Down
37 changes: 18 additions & 19 deletions src/util/yp_constant_pool.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,10 @@ yp_constant_id_list_free(yp_constant_id_list_t *list) {

// A relatively simple hash function (djb2) that is used to hash strings. We are
// optimizing here for simplicity and speed.
static inline size_t
static inline uint32_t
yp_constant_pool_hash(const uint8_t *start, size_t length) {
// This is a prime number used as the initial value for the hash function.
size_t value = 5381;
uint32_t value = 5381;

for (size_t index = 0; index < length; index++) {
value = ((value << 5) + value) + start[index];
Expand All @@ -60,8 +60,8 @@ yp_constant_pool_hash(const uint8_t *start, size_t length) {
}

// https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
static size_t
next_power_of_two(size_t v) {
static uint32_t
next_power_of_two(uint32_t v) {
// Avoid underflow in subtraction on next line.
if (v == 0) {
// 1 is the nearest power of 2 to 0 (2^0)
Expand All @@ -73,16 +73,13 @@ next_power_of_two(size_t v) {
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
#if defined(__LP64__) || defined(_WIN64)
v |= v >> 32;
#endif
v++;
return v;
}

#ifndef NDEBUG
static bool
is_power_of_two(size_t size) {
is_power_of_two(uint32_t size) {
return (size & (size - 1)) == 0;
}
#endif
Expand All @@ -91,22 +88,23 @@ is_power_of_two(size_t size) {
static inline bool
yp_constant_pool_resize(yp_constant_pool_t *pool) {
assert(is_power_of_two(pool->capacity));
size_t next_capacity = pool->capacity * 2;

uint32_t next_capacity = pool->capacity * 2;
if (next_capacity < pool->capacity) return false;

const size_t mask = next_capacity - 1;
const uint32_t mask = next_capacity - 1;
yp_constant_t *next_constants = calloc(next_capacity, sizeof(yp_constant_t));
if (next_constants == NULL) return false;

// For each constant in the current constant pool, rehash the content, find
// the index in the next constant pool, and insert it.
for (size_t index = 0; index < pool->capacity; index++) {
for (uint32_t index = 0; index < pool->capacity; index++) {
yp_constant_t *constant = &pool->constants[index];

// If an id is set on this constant, then we know we have content here.
// In this case we need to insert it into the next constant pool.
if (constant->id != 0) {
size_t next_index = constant->hash & mask;
uint32_t next_index = constant->hash & mask;

// This implements linear scanning to find the next available slot
// in case this index is already taken. We don't need to bother
Expand All @@ -129,9 +127,9 @@ yp_constant_pool_resize(yp_constant_pool_t *pool) {

// Initialize a new constant pool with a given capacity.
bool
yp_constant_pool_init(yp_constant_pool_t *pool, size_t capacity) {
const size_t size_t_max = (~((size_t) 0));
if (capacity >= ((size_t_max / 2) + 1)) return false;
yp_constant_pool_init(yp_constant_pool_t *pool, uint32_t capacity) {
const uint32_t maximum = (~((uint32_t) 0));
if (capacity >= ((maximum / 2) + 1)) return false;

capacity = next_power_of_two(capacity);
pool->constants = calloc(capacity, sizeof(yp_constant_t));
Expand All @@ -150,9 +148,10 @@ yp_constant_pool_insert(yp_constant_pool_t *pool, const uint8_t *start, size_t l
}

assert(is_power_of_two(pool->capacity));
const size_t mask = pool->capacity - 1;
size_t hash = yp_constant_pool_hash(start, length);
size_t index = hash & mask;
const uint32_t mask = pool->capacity - 1;

uint32_t hash = yp_constant_pool_hash(start, length);
uint32_t index = hash & mask;
yp_constant_t *constant;

while (constant = &pool->constants[index], constant->id != 0) {
Expand Down Expand Up @@ -185,7 +184,7 @@ yp_constant_pool_insert(yp_constant_pool_t *pool, const uint8_t *start, size_t l
}

pool->size++;
assert(pool->size < ((size_t) (1 << 31)));
assert(pool->size < ((uint32_t) (1 << 31)));

*constant = (yp_constant_t) {
.id = (unsigned int) (pool->size & 0x7FFFFFFF),
Expand Down
2 changes: 1 addition & 1 deletion src/yarp.c
Original file line number Diff line number Diff line change
Expand Up @@ -14381,7 +14381,7 @@ yp_parser_init(yp_parser_t *parser, const uint8_t *source, size_t size, const ch
//
// This ratio will need to change if we add more constants to the constant
// pool for another node type.
size_t constant_size = size / 95;
uint32_t constant_size = ((uint32_t) size) / 95;
yp_constant_pool_init(&parser->constant_pool, constant_size < 4 ? 4 : constant_size);

// Initialize the newline list. Similar to the constant pool, we're going to
Expand Down
2 changes: 1 addition & 1 deletion templates/ext/yarp/api_node.c.erb
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ yp_ast_new(yp_parser_t *parser, yp_node_t *node, rb_encoding *encoding) {
VALUE source = yp_source_new(parser, encoding);
ID *constants = calloc(parser->constant_pool.size, sizeof(ID));

for (size_t index = 0; index < parser->constant_pool.capacity; index++) {
for (uint32_t index = 0; index < parser->constant_pool.capacity; index++) {
yp_constant_t constant = parser->constant_pool.constants[index];

if (constant.id != 0) {
Expand Down
4 changes: 2 additions & 2 deletions templates/src/serialize.c.erb
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ yp_serialize_content(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer)
yp_buffer_append_zeroes(buffer, 4);

// Next, encode the length of the constant pool.
yp_buffer_append_u32(buffer, yp_sizet_to_u32(parser->constant_pool.size));
yp_buffer_append_u32(buffer, parser->constant_pool.size);

// Now we're going to serialize the content of the node.
yp_serialize_node(parser, node, buffer);
Expand All @@ -200,7 +200,7 @@ yp_serialize_content(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer)
yp_buffer_append_zeroes(buffer, parser->constant_pool.size * 8);

yp_constant_t *constant;
for (size_t index = 0; index < parser->constant_pool.capacity; index++) {
for (uint32_t index = 0; index < parser->constant_pool.capacity; index++) {
constant = &parser->constant_pool.constants[index];

// If we find a constant at this index, serialize it at the correct
Expand Down

0 comments on commit 12963ee

Please sign in to comment.