prism 2.0.0.rc1-x86_64-linux-gnu
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/BSDmakefile +58 -0
- data/CHANGELOG.md +870 -0
- data/CODE_OF_CONDUCT.md +76 -0
- data/CONTRIBUTING.md +58 -0
- data/LICENSE.md +7 -0
- data/Makefile +145 -0
- data/README.md +81 -0
- data/config.yml +4752 -0
- data/docs/build_system.md +119 -0
- data/docs/configuration.md +69 -0
- data/docs/cruby_compilation.md +27 -0
- data/docs/design.md +53 -0
- data/docs/encoding.md +121 -0
- data/docs/fuzzing.md +81 -0
- data/docs/heredocs.md +36 -0
- data/docs/javascript.md +133 -0
- data/docs/local_variable_depth.md +229 -0
- data/docs/mapping.md +117 -0
- data/docs/parser_translation.md +24 -0
- data/docs/parsing_rules.md +22 -0
- data/docs/releasing.md +147 -0
- data/docs/relocation.md +32 -0
- data/docs/ripper_translation.md +63 -0
- data/docs/ruby_api.md +45 -0
- data/docs/ruby_parser_translation.md +19 -0
- data/docs/serialization.md +230 -0
- data/docs/testing.md +72 -0
- data/ext/prism/api_node.c +7005 -0
- data/ext/prism/extconf.rb +126 -0
- data/ext/prism/extension.c +1783 -0
- data/ext/prism/extension.h +19 -0
- data/include/prism/arena.h +37 -0
- data/include/prism/ast.h +10371 -0
- data/include/prism/buffer.h +52 -0
- data/include/prism/comments.h +55 -0
- data/include/prism/compiler/accel.h +24 -0
- data/include/prism/compiler/align.h +36 -0
- data/include/prism/compiler/assume.h +25 -0
- data/include/prism/compiler/exported.h +24 -0
- data/include/prism/compiler/fallthrough.h +22 -0
- data/include/prism/compiler/filesystem.h +32 -0
- data/include/prism/compiler/flex_array.h +19 -0
- data/include/prism/compiler/force_inline.h +21 -0
- data/include/prism/compiler/format.h +25 -0
- data/include/prism/compiler/inline.h +17 -0
- data/include/prism/compiler/nodiscard.h +22 -0
- data/include/prism/compiler/nonnull.h +18 -0
- data/include/prism/compiler/unused.h +18 -0
- data/include/prism/constant_pool.h +81 -0
- data/include/prism/diagnostic.h +93 -0
- data/include/prism/errors_format.h +53 -0
- data/include/prism/excludes.h +29 -0
- data/include/prism/integer.h +41 -0
- data/include/prism/internal/allocator.h +68 -0
- data/include/prism/internal/allocator_debug.h +88 -0
- data/include/prism/internal/arena.h +108 -0
- data/include/prism/internal/bit.h +42 -0
- data/include/prism/internal/buffer.h +91 -0
- data/include/prism/internal/char.h +145 -0
- data/include/prism/internal/comments.h +53 -0
- data/include/prism/internal/constant_pool.h +152 -0
- data/include/prism/internal/diagnostic.h +389 -0
- data/include/prism/internal/encoding.h +242 -0
- data/include/prism/internal/integer.h +68 -0
- data/include/prism/internal/isinf.h +16 -0
- data/include/prism/internal/line_offset_list.h +34 -0
- data/include/prism/internal/list.h +62 -0
- data/include/prism/internal/magic_comments.h +23 -0
- data/include/prism/internal/memchr.h +15 -0
- data/include/prism/internal/node.h +38 -0
- data/include/prism/internal/options.h +232 -0
- data/include/prism/internal/parser.h +984 -0
- data/include/prism/internal/regexp.h +26 -0
- data/include/prism/internal/serialize.h +39 -0
- data/include/prism/internal/source.h +72 -0
- data/include/prism/internal/static_literals.h +100 -0
- data/include/prism/internal/stringy.h +35 -0
- data/include/prism/internal/strncasecmp.h +18 -0
- data/include/prism/internal/strpbrk.h +33 -0
- data/include/prism/internal/tokens.h +11 -0
- data/include/prism/json.h +32 -0
- data/include/prism/line_offset_list.h +61 -0
- data/include/prism/magic_comments.h +35 -0
- data/include/prism/node.h +94 -0
- data/include/prism/options.h +354 -0
- data/include/prism/parser.h +404 -0
- data/include/prism/prettyprint.h +31 -0
- data/include/prism/serialize.h +115 -0
- data/include/prism/source.h +155 -0
- data/include/prism/stream.h +28 -0
- data/include/prism/string_query.h +63 -0
- data/include/prism/stringy.h +72 -0
- data/include/prism/version.h +38 -0
- data/include/prism.h +131 -0
- data/lib/prism/3.3/prism.so +0 -0
- data/lib/prism/3.4/prism.so +0 -0
- data/lib/prism/4.0/prism.so +0 -0
- data/lib/prism/compiler.rb +815 -0
- data/lib/prism/desugar_compiler.rb +463 -0
- data/lib/prism/dispatcher.rb +2383 -0
- data/lib/prism/dot_visitor.rb +4848 -0
- data/lib/prism/dsl.rb +1369 -0
- data/lib/prism/ffi.rb +740 -0
- data/lib/prism/inspect_visitor.rb +2425 -0
- data/lib/prism/lex_compat.rb +953 -0
- data/lib/prism/mutation_compiler.rb +780 -0
- data/lib/prism/node.rb +33204 -0
- data/lib/prism/node_ext.rb +504 -0
- data/lib/prism/node_find.rb +215 -0
- data/lib/prism/parse_result/errors.rb +72 -0
- data/lib/prism/parse_result/newlines.rb +423 -0
- data/lib/prism/parse_result.rb +1221 -0
- data/lib/prism/pattern.rb +314 -0
- data/lib/prism/polyfill/append_as_bytes.rb +15 -0
- data/lib/prism/polyfill/byteindex.rb +13 -0
- data/lib/prism/polyfill/scan_byte.rb +14 -0
- data/lib/prism/polyfill/unpack1.rb +14 -0
- data/lib/prism/polyfill/warn.rb +36 -0
- data/lib/prism/reflection.rb +427 -0
- data/lib/prism/relocation.rb +567 -0
- data/lib/prism/serialize.rb +5308 -0
- data/lib/prism/string_query.rb +46 -0
- data/lib/prism/translation/parser/builder.rb +70 -0
- data/lib/prism/translation/parser/compiler.rb +2226 -0
- data/lib/prism/translation/parser/lexer.rb +769 -0
- data/lib/prism/translation/parser.rb +376 -0
- data/lib/prism/translation/parser_current.rb +26 -0
- data/lib/prism/translation/parser_versions.rb +36 -0
- data/lib/prism/translation/ripper/filter.rb +53 -0
- data/lib/prism/translation/ripper/lexer.rb +133 -0
- data/lib/prism/translation/ripper/sexp.rb +118 -0
- data/lib/prism/translation/ripper/shim.rb +7 -0
- data/lib/prism/translation/ripper.rb +4278 -0
- data/lib/prism/translation/ruby_parser.rb +1721 -0
- data/lib/prism/translation.rb +20 -0
- data/lib/prism/visitor.rb +1440 -0
- data/lib/prism.rb +168 -0
- data/prism.gemspec +234 -0
- data/rbi/generated/prism/compiler.rbi +489 -0
- data/rbi/generated/prism/desugar_compiler.rbi +306 -0
- data/rbi/generated/prism/dispatcher.rbi +1138 -0
- data/rbi/generated/prism/dot_visitor.rbi +618 -0
- data/rbi/generated/prism/dsl.rbi +751 -0
- data/rbi/generated/prism/inspect_visitor.rbi +503 -0
- data/rbi/generated/prism/lex_compat.rbi +162 -0
- data/rbi/generated/prism/mutation_compiler.rbi +464 -0
- data/rbi/generated/prism/node.rbi +13681 -0
- data/rbi/generated/prism/node_ext.rbi +259 -0
- data/rbi/generated/prism/node_find.rbi +79 -0
- data/rbi/generated/prism/parse_result/errors.rbi +21 -0
- data/rbi/generated/prism/parse_result/newlines.rbi +208 -0
- data/rbi/generated/prism/parse_result.rbi +764 -0
- data/rbi/generated/prism/pattern.rbi +134 -0
- data/rbi/generated/prism/reflection.rbi +89 -0
- data/rbi/generated/prism/relocation.rbi +329 -0
- data/rbi/generated/prism/serialize.rbi +181 -0
- data/rbi/generated/prism/string_query.rbi +36 -0
- data/rbi/generated/prism/translation.rbi +7 -0
- data/rbi/generated/prism/visitor.rbi +650 -0
- data/rbi/generated/prism.rbi +86 -0
- data/rbi/prism/translation/parser.rbi +11 -0
- data/rbi/prism/translation/parser_versions.rbi +28 -0
- data/rbi/prism/translation/ripper.rbi +15 -0
- data/rbi/rubyvm/node_find.rbi +14 -0
- data/sig/generated/prism/compiler.rbs +492 -0
- data/sig/generated/prism/desugar_compiler.rbs +305 -0
- data/sig/generated/prism/dispatcher.rbs +1292 -0
- data/sig/generated/prism/dot_visitor.rbs +635 -0
- data/sig/generated/prism/dsl.rbs +928 -0
- data/sig/generated/prism/inspect_visitor.rbs +509 -0
- data/sig/generated/prism/lex_compat.rbs +166 -0
- data/sig/generated/prism/mutation_compiler.rbs +464 -0
- data/sig/generated/prism/node.rbs +20160 -0
- data/sig/generated/prism/node_ext.rbs +290 -0
- data/sig/generated/prism/node_find.rbs +90 -0
- data/sig/generated/prism/parse_result/errors.rbs +22 -0
- data/sig/generated/prism/parse_result/newlines.rbs +223 -0
- data/sig/generated/prism/parse_result.rbs +859 -0
- data/sig/generated/prism/pattern.rbs +156 -0
- data/sig/generated/prism/reflection.rbs +101 -0
- data/sig/generated/prism/relocation.rbs +428 -0
- data/sig/generated/prism/serialize.rbs +195 -0
- data/sig/generated/prism/string_query.rbs +36 -0
- data/sig/generated/prism/translation.rbs +8 -0
- data/sig/generated/prism/visitor.rbs +1111 -0
- data/sig/generated/prism.rbs +84 -0
- data/sig/manifest.yaml +2 -0
- data/src/arena.c +117 -0
- data/src/buffer.c +380 -0
- data/src/char.c +289 -0
- data/src/comments.c +454 -0
- data/src/constant_pool.c +406 -0
- data/src/diagnostic.c +886 -0
- data/src/encoding.c +5345 -0
- data/src/errors_format.c +519 -0
- data/src/integer.c +681 -0
- data/src/json.c +5733 -0
- data/src/line_offset_list.c +100 -0
- data/src/list.c +24 -0
- data/src/memchr.c +37 -0
- data/src/node.c +4515 -0
- data/src/options.c +451 -0
- data/src/parser.c +349 -0
- data/src/prettyprint.c +9024 -0
- data/src/prism.c +23739 -0
- data/src/regexp.c +1706 -0
- data/src/serialize.c +2309 -0
- data/src/source.c +518 -0
- data/src/static_literals.c +685 -0
- data/src/string_query.c +166 -0
- data/src/stringy.c +91 -0
- data/src/strncasecmp.c +37 -0
- data/src/strpbrk.c +447 -0
- data/src/tokens.c +724 -0
- metadata +259 -0
data/src/constant_pool.c
ADDED
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
#include "prism/internal/constant_pool.h"
|
|
2
|
+
|
|
3
|
+
#include "prism/compiler/align.h"
|
|
4
|
+
#include "prism/compiler/inline.h"
|
|
5
|
+
#include "prism/internal/arena.h"
|
|
6
|
+
|
|
7
|
+
#include <assert.h>
|
|
8
|
+
#include <stdbool.h>
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Initialize a list of constant ids.
|
|
12
|
+
*/
|
|
13
|
+
void
|
|
14
|
+
pm_constant_id_list_init(pm_constant_id_list_t *list) {
|
|
15
|
+
list->ids = NULL;
|
|
16
|
+
list->size = 0;
|
|
17
|
+
list->capacity = 0;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Initialize a list of constant ids with a given capacity.
|
|
22
|
+
*/
|
|
23
|
+
void
|
|
24
|
+
pm_constant_id_list_init_capacity(pm_arena_t *arena, pm_constant_id_list_t *list, size_t capacity) {
|
|
25
|
+
if (capacity) {
|
|
26
|
+
list->ids = (pm_constant_id_t *) pm_arena_zalloc(arena, capacity * sizeof(pm_constant_id_t), PRISM_ALIGNOF(pm_constant_id_t));
|
|
27
|
+
} else {
|
|
28
|
+
list->ids = NULL;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
list->size = 0;
|
|
32
|
+
list->capacity = capacity;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Append a constant id to a list of constant ids.
|
|
37
|
+
*/
|
|
38
|
+
void
|
|
39
|
+
pm_constant_id_list_append(pm_arena_t *arena, pm_constant_id_list_t *list, pm_constant_id_t id) {
|
|
40
|
+
if (list->size >= list->capacity) {
|
|
41
|
+
size_t new_capacity = list->capacity == 0 ? 8 : list->capacity * 2;
|
|
42
|
+
pm_constant_id_t *new_ids = (pm_constant_id_t *) pm_arena_alloc(arena, sizeof(pm_constant_id_t) * new_capacity, PRISM_ALIGNOF(pm_constant_id_t));
|
|
43
|
+
|
|
44
|
+
if (list->size > 0) {
|
|
45
|
+
memcpy(new_ids, list->ids, list->size * sizeof(pm_constant_id_t));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
list->ids = new_ids;
|
|
49
|
+
list->capacity = new_capacity;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
list->ids[list->size++] = id;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Insert a constant id into a list of constant ids at the specified index.
|
|
57
|
+
*/
|
|
58
|
+
void
|
|
59
|
+
pm_constant_id_list_insert(pm_constant_id_list_t *list, size_t index, pm_constant_id_t id) {
|
|
60
|
+
assert(index < list->capacity);
|
|
61
|
+
assert(list->ids[index] == PM_CONSTANT_ID_UNSET);
|
|
62
|
+
|
|
63
|
+
list->ids[index] = id;
|
|
64
|
+
list->size++;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* The slot that holds the given id, or the empty slot it would occupy. The
|
|
69
|
+
* table is never full, so this terminates.
|
|
70
|
+
*/
|
|
71
|
+
static PRISM_INLINE size_t
|
|
72
|
+
pm_constant_id_set_slot(const pm_constant_id_set_t *set, pm_constant_id_t id) {
|
|
73
|
+
assert(set->capacity != 0);
|
|
74
|
+
|
|
75
|
+
size_t mask = set->capacity - 1;
|
|
76
|
+
size_t index = ((size_t) pm_constant_id_hash(id)) & mask;
|
|
77
|
+
|
|
78
|
+
while (set->ids[index] != PM_CONSTANT_ID_UNSET && set->ids[index] != id) {
|
|
79
|
+
index = (index + 1) & mask;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return index;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Add a constant id to the set, reporting whether it was not already there.
|
|
87
|
+
*/
|
|
88
|
+
bool
|
|
89
|
+
pm_constant_id_set_insert(pm_arena_t *arena, pm_constant_id_set_t *set, pm_constant_id_t id) {
|
|
90
|
+
/* PM_CONSTANT_ID_UNSET marks an empty slot, so it cannot also be a member. */
|
|
91
|
+
assert(id != PM_CONSTANT_ID_UNSET);
|
|
92
|
+
|
|
93
|
+
/*
|
|
94
|
+
* Grow at the same load factor the locals table and the constant pool use.
|
|
95
|
+
* An empty set has no slots at all, so this also builds the first table.
|
|
96
|
+
*/
|
|
97
|
+
if (set->size >= (set->capacity / 4 * 3)) {
|
|
98
|
+
size_t capacity = set->capacity == 0 ? 8 : set->capacity * 2;
|
|
99
|
+
pm_constant_id_set_t grown = {
|
|
100
|
+
.size = set->size,
|
|
101
|
+
.capacity = capacity,
|
|
102
|
+
.ids = (pm_constant_id_t *) pm_arena_zalloc(arena, capacity * sizeof(pm_constant_id_t), PRISM_ALIGNOF(pm_constant_id_t))
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
for (size_t index = 0; index < set->capacity; index++) {
|
|
106
|
+
pm_constant_id_t moved = set->ids[index];
|
|
107
|
+
if (moved != PM_CONSTANT_ID_UNSET) grown.ids[pm_constant_id_set_slot(&grown, moved)] = moved;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
*set = grown;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
size_t index = pm_constant_id_set_slot(set, id);
|
|
114
|
+
if (set->ids[index] == id) return false;
|
|
115
|
+
|
|
116
|
+
set->ids[index] = id;
|
|
117
|
+
set->size++;
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* A multiply-xorshift hash that processes input a word at a time. This is
|
|
123
|
+
* significantly faster than the byte-at-a-time djb2 hash for the short strings
|
|
124
|
+
* typical in Ruby source (~15 bytes average). Each word is mixed into the hash
|
|
125
|
+
* by XOR followed by multiplication by a large odd constant, which spreads
|
|
126
|
+
* entropy across all bits. A final xorshift fold produces the 32-bit result.
|
|
127
|
+
*/
|
|
128
|
+
static PRISM_INLINE uint32_t
|
|
129
|
+
pm_constant_pool_hash(const uint8_t *start, size_t length) {
|
|
130
|
+
// This constant is borrowed from wyhash. It is a 64-bit odd integer with
|
|
131
|
+
// roughly equal 0/1 bits, chosen for good avalanche behavior when used in
|
|
132
|
+
// multiply-xorshift sequences.
|
|
133
|
+
static const uint64_t secret = 0x517cc1b727220a95ULL;
|
|
134
|
+
uint64_t hash = (uint64_t) length;
|
|
135
|
+
|
|
136
|
+
if (length <= 8) {
|
|
137
|
+
// Short strings: read first and last 4 bytes (overlapping for len < 8).
|
|
138
|
+
// This covers the majority of Ruby identifiers with a single multiply.
|
|
139
|
+
if (length >= 4) {
|
|
140
|
+
uint32_t a, b;
|
|
141
|
+
memcpy(&a, start, 4);
|
|
142
|
+
memcpy(&b, start + length - 4, 4);
|
|
143
|
+
hash ^= (uint64_t) a | ((uint64_t) b << 32);
|
|
144
|
+
} else if (length > 0) {
|
|
145
|
+
hash ^= (uint64_t) start[0] | ((uint64_t) start[length >> 1] << 8) | ((uint64_t) start[length - 1] << 16);
|
|
146
|
+
}
|
|
147
|
+
hash *= secret;
|
|
148
|
+
} else if (length <= 16) {
|
|
149
|
+
// Medium strings: read first and last 8 bytes (overlapping).
|
|
150
|
+
// Two multiplies instead of the three the loop-based approach needs.
|
|
151
|
+
uint64_t word;
|
|
152
|
+
memcpy(&word, start, 8);
|
|
153
|
+
hash ^= word;
|
|
154
|
+
hash *= secret;
|
|
155
|
+
memcpy(&word, start + length - 8, 8);
|
|
156
|
+
hash ^= word;
|
|
157
|
+
hash *= secret;
|
|
158
|
+
} else {
|
|
159
|
+
const uint8_t *ptr = start;
|
|
160
|
+
size_t remaining = length;
|
|
161
|
+
|
|
162
|
+
while (remaining >= 8) {
|
|
163
|
+
uint64_t word;
|
|
164
|
+
memcpy(&word, ptr, 8);
|
|
165
|
+
hash ^= word;
|
|
166
|
+
hash *= secret;
|
|
167
|
+
ptr += 8;
|
|
168
|
+
remaining -= 8;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (remaining > 0) {
|
|
172
|
+
// Read the last 8 bytes (overlapping with already-processed data).
|
|
173
|
+
uint64_t word;
|
|
174
|
+
memcpy(&word, start + length - 8, 8);
|
|
175
|
+
hash ^= word;
|
|
176
|
+
hash *= secret;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
hash ^= hash >> 32;
|
|
181
|
+
return (uint32_t) hash;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
|
|
186
|
+
*/
|
|
187
|
+
static uint32_t
|
|
188
|
+
next_power_of_two(uint32_t v) {
|
|
189
|
+
// Avoid underflow in subtraction on next line.
|
|
190
|
+
if (v == 0) {
|
|
191
|
+
// 1 is the nearest power of 2 to 0 (2^0)
|
|
192
|
+
return 1;
|
|
193
|
+
}
|
|
194
|
+
v--;
|
|
195
|
+
v |= v >> 1;
|
|
196
|
+
v |= v >> 2;
|
|
197
|
+
v |= v >> 4;
|
|
198
|
+
v |= v >> 8;
|
|
199
|
+
v |= v >> 16;
|
|
200
|
+
v++;
|
|
201
|
+
return v;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
#ifndef NDEBUG
|
|
205
|
+
static bool
|
|
206
|
+
is_power_of_two(uint32_t size) {
|
|
207
|
+
return (size & (size - 1)) == 0;
|
|
208
|
+
}
|
|
209
|
+
#endif
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Resize a constant pool to a given capacity.
|
|
213
|
+
*/
|
|
214
|
+
static PRISM_INLINE void
|
|
215
|
+
pm_constant_pool_resize(pm_arena_t *arena, pm_constant_pool_t *pool) {
|
|
216
|
+
assert(is_power_of_two(pool->capacity));
|
|
217
|
+
|
|
218
|
+
uint32_t next_capacity = pool->capacity * 2;
|
|
219
|
+
const uint32_t mask = next_capacity - 1;
|
|
220
|
+
|
|
221
|
+
pm_constant_pool_bucket_t *next_buckets = (pm_constant_pool_bucket_t *) pm_arena_zalloc(arena, next_capacity * sizeof(pm_constant_pool_bucket_t), PRISM_ALIGNOF(pm_constant_pool_bucket_t));
|
|
222
|
+
pm_constant_t *next_constants = (pm_constant_t *) pm_arena_alloc(arena, next_capacity * sizeof(pm_constant_t), PRISM_ALIGNOF(pm_constant_t));
|
|
223
|
+
|
|
224
|
+
// For each bucket in the current constant pool, find the index in the
|
|
225
|
+
// next constant pool, and insert it.
|
|
226
|
+
for (uint32_t index = 0; index < pool->capacity; index++) {
|
|
227
|
+
pm_constant_pool_bucket_t *bucket = &pool->buckets[index];
|
|
228
|
+
|
|
229
|
+
// If an id is set on this constant, then we know we have content here.
|
|
230
|
+
// In this case we need to insert it into the next constant pool.
|
|
231
|
+
if (bucket->id != PM_CONSTANT_ID_UNSET) {
|
|
232
|
+
uint32_t next_index = bucket->hash & mask;
|
|
233
|
+
|
|
234
|
+
// This implements linear scanning to find the next available slot
|
|
235
|
+
// in case this index is already taken. We don't need to bother
|
|
236
|
+
// comparing the values since we know that the hash is unique.
|
|
237
|
+
while (next_buckets[next_index].id != PM_CONSTANT_ID_UNSET) {
|
|
238
|
+
next_index = (next_index + 1) & mask;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Here we copy over the entire bucket, which includes the id so
|
|
242
|
+
// that they are consistent between resizes.
|
|
243
|
+
next_buckets[next_index] = *bucket;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// The constants are stable with respect to hash table resizes.
|
|
248
|
+
memcpy(next_constants, pool->constants, pool->size * sizeof(pm_constant_t));
|
|
249
|
+
|
|
250
|
+
pool->constants = next_constants;
|
|
251
|
+
pool->buckets = next_buckets;
|
|
252
|
+
pool->capacity = next_capacity;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Initialize a new constant pool with a given capacity.
|
|
257
|
+
*/
|
|
258
|
+
void
|
|
259
|
+
pm_constant_pool_init(pm_arena_t *arena, pm_constant_pool_t *pool, uint32_t capacity) {
|
|
260
|
+
capacity = next_power_of_two(capacity);
|
|
261
|
+
|
|
262
|
+
pool->buckets = (pm_constant_pool_bucket_t *) pm_arena_zalloc(arena, capacity * sizeof(pm_constant_pool_bucket_t), PRISM_ALIGNOF(pm_constant_pool_bucket_t));
|
|
263
|
+
pool->constants = (pm_constant_t *) pm_arena_alloc(arena, capacity * sizeof(pm_constant_t), PRISM_ALIGNOF(pm_constant_t));
|
|
264
|
+
pool->size = 0;
|
|
265
|
+
pool->capacity = capacity;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Return a pointer to the constant indicated by the given constant id.
|
|
270
|
+
*/
|
|
271
|
+
pm_constant_t *
|
|
272
|
+
pm_constant_pool_id_to_constant(const pm_constant_pool_t *pool, pm_constant_id_t constant_id) {
|
|
273
|
+
assert(constant_id != PM_CONSTANT_ID_UNSET && constant_id <= pool->size);
|
|
274
|
+
return &pool->constants[constant_id - 1];
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Find a constant in a constant pool. Returns the id of the constant, or 0 if
|
|
279
|
+
* the constant is not found.
|
|
280
|
+
*/
|
|
281
|
+
pm_constant_id_t
|
|
282
|
+
pm_constant_pool_find(const pm_constant_pool_t *pool, const uint8_t *start, size_t length) {
|
|
283
|
+
assert(is_power_of_two(pool->capacity));
|
|
284
|
+
const uint32_t mask = pool->capacity - 1;
|
|
285
|
+
|
|
286
|
+
uint32_t hash = pm_constant_pool_hash(start, length);
|
|
287
|
+
uint32_t index = hash & mask;
|
|
288
|
+
pm_constant_pool_bucket_t *bucket;
|
|
289
|
+
|
|
290
|
+
while (bucket = &pool->buckets[index], bucket->id != PM_CONSTANT_ID_UNSET) {
|
|
291
|
+
// Compare the stored hash before touching the contents so that probe
|
|
292
|
+
// collisions are rejected without a memcmp call.
|
|
293
|
+
if ((bucket->hash == hash) && (bucket->length == length) && memcmp(bucket->start, start, length) == 0) {
|
|
294
|
+
return bucket->id;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
index = (index + 1) & mask;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
return PM_CONSTANT_ID_UNSET;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Insert a constant into a constant pool and return its index in the pool.
|
|
305
|
+
*/
|
|
306
|
+
static PRISM_INLINE pm_constant_id_t
|
|
307
|
+
pm_constant_pool_insert(pm_arena_t *arena, pm_constant_pool_t *pool, const uint8_t *start, size_t length, pm_constant_pool_bucket_type_t type) {
|
|
308
|
+
if (pool->size >= (pool->capacity / 4 * 3)) {
|
|
309
|
+
pm_constant_pool_resize(arena, pool);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
assert(is_power_of_two(pool->capacity));
|
|
313
|
+
const uint32_t mask = pool->capacity - 1;
|
|
314
|
+
|
|
315
|
+
uint32_t hash = pm_constant_pool_hash(start, length);
|
|
316
|
+
uint32_t index = hash & mask;
|
|
317
|
+
pm_constant_pool_bucket_t *bucket;
|
|
318
|
+
|
|
319
|
+
while (bucket = &pool->buckets[index], bucket->id != PM_CONSTANT_ID_UNSET) {
|
|
320
|
+
// If there is a collision, then we need to check if the content is the
|
|
321
|
+
// same as the content we are trying to insert. If it is, then we can
|
|
322
|
+
// return the id of the existing constant. Compare the stored hash
|
|
323
|
+
// first so that probe collisions are rejected without a memcmp call.
|
|
324
|
+
if ((bucket->hash == hash) && (bucket->length == length) && memcmp(bucket->start, start, length) == 0) {
|
|
325
|
+
// Since we have found a match, we need to check if this is
|
|
326
|
+
// attempting to insert a shared or an owned constant. We want to
|
|
327
|
+
// prefer shared constants since they don't require allocations.
|
|
328
|
+
if (type != PM_CONSTANT_POOL_BUCKET_OWNED && bucket->type == PM_CONSTANT_POOL_BUCKET_OWNED) {
|
|
329
|
+
// If we're attempting to insert a shared constant and the
|
|
330
|
+
// existing constant is owned, then we can replace it with the
|
|
331
|
+
// shared constant to prefer non-owned references.
|
|
332
|
+
bucket->start = start;
|
|
333
|
+
bucket->type = (unsigned int) (type & 0x3);
|
|
334
|
+
pool->constants[bucket->id - 1].start = start;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
return bucket->id;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
index = (index + 1) & mask;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// IDs are allocated starting at 1, since the value 0 denotes a non-existent
|
|
344
|
+
// constant.
|
|
345
|
+
uint32_t id = ++pool->size;
|
|
346
|
+
assert(pool->size < ((uint32_t) (1 << 30)));
|
|
347
|
+
|
|
348
|
+
*bucket = (pm_constant_pool_bucket_t) {
|
|
349
|
+
.id = (unsigned int) (id & 0x3fffffff),
|
|
350
|
+
.type = (unsigned int) (type & 0x3),
|
|
351
|
+
.hash = hash,
|
|
352
|
+
.start = start,
|
|
353
|
+
.length = length
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
pool->constants[id - 1] = (pm_constant_t) {
|
|
357
|
+
.start = start,
|
|
358
|
+
.length = length,
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
return id;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Insert a constant into a constant pool. Returns the id of the constant, or
|
|
366
|
+
* PM_CONSTANT_ID_UNSET if any potential calls to resize fail.
|
|
367
|
+
*/
|
|
368
|
+
pm_constant_id_t
|
|
369
|
+
pm_constant_pool_insert_shared(pm_arena_t *arena, pm_constant_pool_t *pool, const uint8_t *start, size_t length) {
|
|
370
|
+
return pm_constant_pool_insert(arena, pool, start, length, PM_CONSTANT_POOL_BUCKET_DEFAULT);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Insert a constant into a constant pool from memory that is now owned by the
|
|
375
|
+
* constant pool. Returns the id of the constant, or PM_CONSTANT_ID_UNSET if any
|
|
376
|
+
* potential calls to resize fail.
|
|
377
|
+
*/
|
|
378
|
+
pm_constant_id_t
|
|
379
|
+
pm_constant_pool_insert_owned(pm_arena_t *arena, pm_constant_pool_t *pool, uint8_t *start, size_t length) {
|
|
380
|
+
return pm_constant_pool_insert(arena, pool, start, length, PM_CONSTANT_POOL_BUCKET_OWNED);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* Insert a constant into a constant pool from memory that is constant. Returns
|
|
385
|
+
* the id of the constant, or PM_CONSTANT_ID_UNSET if any potential calls to
|
|
386
|
+
* resize fail.
|
|
387
|
+
*/
|
|
388
|
+
pm_constant_id_t
|
|
389
|
+
pm_constant_pool_insert_constant(pm_arena_t *arena, pm_constant_pool_t *pool, const uint8_t *start, size_t length) {
|
|
390
|
+
return pm_constant_pool_insert(arena, pool, start, length, PM_CONSTANT_POOL_BUCKET_CONSTANT);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Return a raw pointer to the start of a constant.
|
|
395
|
+
*/
|
|
396
|
+
const uint8_t *
|
|
397
|
+
pm_constant_start(const pm_constant_t *constant) {
|
|
398
|
+
return constant->start;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* Return the length of a constant.
|
|
403
|
+
*/
|
|
404
|
+
size_t pm_constant_length(const pm_constant_t *constant) {
|
|
405
|
+
return constant->length;
|
|
406
|
+
}
|