[ruby/yarp] Explicitly use u32 for constant pool
https://github.com/ruby/yarp/commit/32b173e6c8
This commit is contained in:
parent
2531ba4ba0
commit
ffc1fc7a6d
@ -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);
|
VALUE source = yp_source_new(parser, encoding);
|
||||||
ID *constants = calloc(parser->constant_pool.size, sizeof(ID));
|
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];
|
yp_constant_t constant = parser->constant_pool.constants[index];
|
||||||
|
|
||||||
if (constant.id != 0) {
|
if (constant.id != 0) {
|
||||||
|
@ -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);
|
yp_buffer_append_zeroes(buffer, 4);
|
||||||
|
|
||||||
// Next, encode the length of the constant pool.
|
// 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.
|
// Now we're going to serialize the content of the node.
|
||||||
yp_serialize_node(parser, node, buffer);
|
yp_serialize_node(parser, node, buffer);
|
||||||
@ -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_buffer_append_zeroes(buffer, parser->constant_pool.size * 8);
|
||||||
|
|
||||||
yp_constant_t *constant;
|
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];
|
constant = &parser->constant_pool.constants[index];
|
||||||
|
|
||||||
// If we find a constant at this index, serialize it at the correct
|
// If we find a constant at this index, serialize it at the correct
|
||||||
|
@ -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
|
// A relatively simple hash function (djb2) that is used to hash strings. We are
|
||||||
// optimizing here for simplicity and speed.
|
// 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) {
|
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.
|
// 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++) {
|
for (size_t index = 0; index < length; index++) {
|
||||||
value = ((value << 5) + value) + start[index];
|
value = ((value << 5) + value) + start[index];
|
||||||
@ -60,8 +60,8 @@ yp_constant_pool_hash(const uint8_t *start, size_t length) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
|
// https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
|
||||||
static size_t
|
static uint32_t
|
||||||
next_power_of_two(size_t v) {
|
next_power_of_two(uint32_t v) {
|
||||||
// Avoid underflow in subtraction on next line.
|
// Avoid underflow in subtraction on next line.
|
||||||
if (v == 0) {
|
if (v == 0) {
|
||||||
// 1 is the nearest power of 2 to 0 (2^0)
|
// 1 is the nearest power of 2 to 0 (2^0)
|
||||||
@ -73,16 +73,13 @@ next_power_of_two(size_t v) {
|
|||||||
v |= v >> 4;
|
v |= v >> 4;
|
||||||
v |= v >> 8;
|
v |= v >> 8;
|
||||||
v |= v >> 16;
|
v |= v >> 16;
|
||||||
#if defined(__LP64__) || defined(_WIN64)
|
|
||||||
v |= v >> 32;
|
|
||||||
#endif
|
|
||||||
v++;
|
v++;
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
static bool
|
static bool
|
||||||
is_power_of_two(size_t size) {
|
is_power_of_two(uint32_t size) {
|
||||||
return (size & (size - 1)) == 0;
|
return (size & (size - 1)) == 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -91,22 +88,23 @@ is_power_of_two(size_t size) {
|
|||||||
static inline bool
|
static inline bool
|
||||||
yp_constant_pool_resize(yp_constant_pool_t *pool) {
|
yp_constant_pool_resize(yp_constant_pool_t *pool) {
|
||||||
assert(is_power_of_two(pool->capacity));
|
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;
|
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));
|
yp_constant_t *next_constants = calloc(next_capacity, sizeof(yp_constant_t));
|
||||||
if (next_constants == NULL) return false;
|
if (next_constants == NULL) return false;
|
||||||
|
|
||||||
// For each constant in the current constant pool, rehash the content, find
|
// For each constant in the current constant pool, rehash the content, find
|
||||||
// the index in the next constant pool, and insert it.
|
// 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];
|
yp_constant_t *constant = &pool->constants[index];
|
||||||
|
|
||||||
// If an id is set on this constant, then we know we have content here.
|
// 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.
|
// In this case we need to insert it into the next constant pool.
|
||||||
if (constant->id != 0) {
|
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
|
// This implements linear scanning to find the next available slot
|
||||||
// in case this index is already taken. We don't need to bother
|
// in case this index is already taken. We don't need to bother
|
||||||
@ -129,9 +127,9 @@ yp_constant_pool_resize(yp_constant_pool_t *pool) {
|
|||||||
|
|
||||||
// Initialize a new constant pool with a given capacity.
|
// Initialize a new constant pool with a given capacity.
|
||||||
bool
|
bool
|
||||||
yp_constant_pool_init(yp_constant_pool_t *pool, size_t capacity) {
|
yp_constant_pool_init(yp_constant_pool_t *pool, uint32_t capacity) {
|
||||||
const size_t size_t_max = (~((size_t) 0));
|
const uint32_t maximum = (~((uint32_t) 0));
|
||||||
if (capacity >= ((size_t_max / 2) + 1)) return false;
|
if (capacity >= ((maximum / 2) + 1)) return false;
|
||||||
|
|
||||||
capacity = next_power_of_two(capacity);
|
capacity = next_power_of_two(capacity);
|
||||||
pool->constants = calloc(capacity, sizeof(yp_constant_t));
|
pool->constants = calloc(capacity, sizeof(yp_constant_t));
|
||||||
@ -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));
|
assert(is_power_of_two(pool->capacity));
|
||||||
const size_t mask = pool->capacity - 1;
|
const uint32_t mask = pool->capacity - 1;
|
||||||
size_t hash = yp_constant_pool_hash(start, length);
|
|
||||||
size_t index = hash & mask;
|
uint32_t hash = yp_constant_pool_hash(start, length);
|
||||||
|
uint32_t index = hash & mask;
|
||||||
yp_constant_t *constant;
|
yp_constant_t *constant;
|
||||||
|
|
||||||
while (constant = &pool->constants[index], constant->id != 0) {
|
while (constant = &pool->constants[index], constant->id != 0) {
|
||||||
@ -185,7 +184,7 @@ yp_constant_pool_insert(yp_constant_pool_t *pool, const uint8_t *start, size_t l
|
|||||||
}
|
}
|
||||||
|
|
||||||
pool->size++;
|
pool->size++;
|
||||||
assert(pool->size < ((size_t) (1 << 31)));
|
assert(pool->size < ((uint32_t) (1 << 31)));
|
||||||
|
|
||||||
*constant = (yp_constant_t) {
|
*constant = (yp_constant_t) {
|
||||||
.id = (unsigned int) (pool->size & 0x7FFFFFFF),
|
.id = (unsigned int) (pool->size & 0x7FFFFFFF),
|
||||||
|
@ -44,20 +44,20 @@ typedef struct {
|
|||||||
bool owned: 1;
|
bool owned: 1;
|
||||||
const uint8_t *start;
|
const uint8_t *start;
|
||||||
size_t length;
|
size_t length;
|
||||||
size_t hash;
|
uint32_t hash;
|
||||||
} yp_constant_t;
|
} yp_constant_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
yp_constant_t *constants;
|
yp_constant_t *constants;
|
||||||
size_t size;
|
uint32_t size;
|
||||||
size_t capacity;
|
uint32_t capacity;
|
||||||
} yp_constant_pool_t;
|
} yp_constant_pool_t;
|
||||||
|
|
||||||
// Define an empty constant pool.
|
// Define an empty constant pool.
|
||||||
#define YP_CONSTANT_POOL_EMPTY ((yp_constant_pool_t) { .constants = NULL, .size = 0, .capacity = 0 })
|
#define YP_CONSTANT_POOL_EMPTY ((yp_constant_pool_t) { .constants = NULL, .size = 0, .capacity = 0 })
|
||||||
|
|
||||||
// Initialize a new constant pool with a given capacity.
|
// 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.
|
// 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.
|
// Returns the id of the constant, or 0 if any potential calls to resize fail.
|
||||||
|
@ -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
|
// This ratio will need to change if we add more constants to the constant
|
||||||
// pool for another node type.
|
// 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);
|
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
|
// Initialize the newline list. Similar to the constant pool, we're going to
|
||||||
|
Loading…
x
Reference in New Issue
Block a user