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.
Files changed (216) hide show
  1. checksums.yaml +7 -0
  2. data/BSDmakefile +58 -0
  3. data/CHANGELOG.md +870 -0
  4. data/CODE_OF_CONDUCT.md +76 -0
  5. data/CONTRIBUTING.md +58 -0
  6. data/LICENSE.md +7 -0
  7. data/Makefile +145 -0
  8. data/README.md +81 -0
  9. data/config.yml +4752 -0
  10. data/docs/build_system.md +119 -0
  11. data/docs/configuration.md +69 -0
  12. data/docs/cruby_compilation.md +27 -0
  13. data/docs/design.md +53 -0
  14. data/docs/encoding.md +121 -0
  15. data/docs/fuzzing.md +81 -0
  16. data/docs/heredocs.md +36 -0
  17. data/docs/javascript.md +133 -0
  18. data/docs/local_variable_depth.md +229 -0
  19. data/docs/mapping.md +117 -0
  20. data/docs/parser_translation.md +24 -0
  21. data/docs/parsing_rules.md +22 -0
  22. data/docs/releasing.md +147 -0
  23. data/docs/relocation.md +32 -0
  24. data/docs/ripper_translation.md +63 -0
  25. data/docs/ruby_api.md +45 -0
  26. data/docs/ruby_parser_translation.md +19 -0
  27. data/docs/serialization.md +230 -0
  28. data/docs/testing.md +72 -0
  29. data/ext/prism/api_node.c +7005 -0
  30. data/ext/prism/extconf.rb +126 -0
  31. data/ext/prism/extension.c +1783 -0
  32. data/ext/prism/extension.h +19 -0
  33. data/include/prism/arena.h +37 -0
  34. data/include/prism/ast.h +10371 -0
  35. data/include/prism/buffer.h +52 -0
  36. data/include/prism/comments.h +55 -0
  37. data/include/prism/compiler/accel.h +24 -0
  38. data/include/prism/compiler/align.h +36 -0
  39. data/include/prism/compiler/assume.h +25 -0
  40. data/include/prism/compiler/exported.h +24 -0
  41. data/include/prism/compiler/fallthrough.h +22 -0
  42. data/include/prism/compiler/filesystem.h +32 -0
  43. data/include/prism/compiler/flex_array.h +19 -0
  44. data/include/prism/compiler/force_inline.h +21 -0
  45. data/include/prism/compiler/format.h +25 -0
  46. data/include/prism/compiler/inline.h +17 -0
  47. data/include/prism/compiler/nodiscard.h +22 -0
  48. data/include/prism/compiler/nonnull.h +18 -0
  49. data/include/prism/compiler/unused.h +18 -0
  50. data/include/prism/constant_pool.h +81 -0
  51. data/include/prism/diagnostic.h +93 -0
  52. data/include/prism/errors_format.h +53 -0
  53. data/include/prism/excludes.h +29 -0
  54. data/include/prism/integer.h +41 -0
  55. data/include/prism/internal/allocator.h +68 -0
  56. data/include/prism/internal/allocator_debug.h +88 -0
  57. data/include/prism/internal/arena.h +108 -0
  58. data/include/prism/internal/bit.h +42 -0
  59. data/include/prism/internal/buffer.h +91 -0
  60. data/include/prism/internal/char.h +145 -0
  61. data/include/prism/internal/comments.h +53 -0
  62. data/include/prism/internal/constant_pool.h +152 -0
  63. data/include/prism/internal/diagnostic.h +389 -0
  64. data/include/prism/internal/encoding.h +242 -0
  65. data/include/prism/internal/integer.h +68 -0
  66. data/include/prism/internal/isinf.h +16 -0
  67. data/include/prism/internal/line_offset_list.h +34 -0
  68. data/include/prism/internal/list.h +62 -0
  69. data/include/prism/internal/magic_comments.h +23 -0
  70. data/include/prism/internal/memchr.h +15 -0
  71. data/include/prism/internal/node.h +38 -0
  72. data/include/prism/internal/options.h +232 -0
  73. data/include/prism/internal/parser.h +984 -0
  74. data/include/prism/internal/regexp.h +26 -0
  75. data/include/prism/internal/serialize.h +39 -0
  76. data/include/prism/internal/source.h +72 -0
  77. data/include/prism/internal/static_literals.h +100 -0
  78. data/include/prism/internal/stringy.h +35 -0
  79. data/include/prism/internal/strncasecmp.h +18 -0
  80. data/include/prism/internal/strpbrk.h +33 -0
  81. data/include/prism/internal/tokens.h +11 -0
  82. data/include/prism/json.h +32 -0
  83. data/include/prism/line_offset_list.h +61 -0
  84. data/include/prism/magic_comments.h +35 -0
  85. data/include/prism/node.h +94 -0
  86. data/include/prism/options.h +354 -0
  87. data/include/prism/parser.h +404 -0
  88. data/include/prism/prettyprint.h +31 -0
  89. data/include/prism/serialize.h +115 -0
  90. data/include/prism/source.h +155 -0
  91. data/include/prism/stream.h +28 -0
  92. data/include/prism/string_query.h +63 -0
  93. data/include/prism/stringy.h +72 -0
  94. data/include/prism/version.h +38 -0
  95. data/include/prism.h +131 -0
  96. data/lib/prism/3.3/prism.so +0 -0
  97. data/lib/prism/3.4/prism.so +0 -0
  98. data/lib/prism/4.0/prism.so +0 -0
  99. data/lib/prism/compiler.rb +815 -0
  100. data/lib/prism/desugar_compiler.rb +463 -0
  101. data/lib/prism/dispatcher.rb +2383 -0
  102. data/lib/prism/dot_visitor.rb +4848 -0
  103. data/lib/prism/dsl.rb +1369 -0
  104. data/lib/prism/ffi.rb +740 -0
  105. data/lib/prism/inspect_visitor.rb +2425 -0
  106. data/lib/prism/lex_compat.rb +953 -0
  107. data/lib/prism/mutation_compiler.rb +780 -0
  108. data/lib/prism/node.rb +33204 -0
  109. data/lib/prism/node_ext.rb +504 -0
  110. data/lib/prism/node_find.rb +215 -0
  111. data/lib/prism/parse_result/errors.rb +72 -0
  112. data/lib/prism/parse_result/newlines.rb +423 -0
  113. data/lib/prism/parse_result.rb +1221 -0
  114. data/lib/prism/pattern.rb +314 -0
  115. data/lib/prism/polyfill/append_as_bytes.rb +15 -0
  116. data/lib/prism/polyfill/byteindex.rb +13 -0
  117. data/lib/prism/polyfill/scan_byte.rb +14 -0
  118. data/lib/prism/polyfill/unpack1.rb +14 -0
  119. data/lib/prism/polyfill/warn.rb +36 -0
  120. data/lib/prism/reflection.rb +427 -0
  121. data/lib/prism/relocation.rb +567 -0
  122. data/lib/prism/serialize.rb +5308 -0
  123. data/lib/prism/string_query.rb +46 -0
  124. data/lib/prism/translation/parser/builder.rb +70 -0
  125. data/lib/prism/translation/parser/compiler.rb +2226 -0
  126. data/lib/prism/translation/parser/lexer.rb +769 -0
  127. data/lib/prism/translation/parser.rb +376 -0
  128. data/lib/prism/translation/parser_current.rb +26 -0
  129. data/lib/prism/translation/parser_versions.rb +36 -0
  130. data/lib/prism/translation/ripper/filter.rb +53 -0
  131. data/lib/prism/translation/ripper/lexer.rb +133 -0
  132. data/lib/prism/translation/ripper/sexp.rb +118 -0
  133. data/lib/prism/translation/ripper/shim.rb +7 -0
  134. data/lib/prism/translation/ripper.rb +4278 -0
  135. data/lib/prism/translation/ruby_parser.rb +1721 -0
  136. data/lib/prism/translation.rb +20 -0
  137. data/lib/prism/visitor.rb +1440 -0
  138. data/lib/prism.rb +168 -0
  139. data/prism.gemspec +234 -0
  140. data/rbi/generated/prism/compiler.rbi +489 -0
  141. data/rbi/generated/prism/desugar_compiler.rbi +306 -0
  142. data/rbi/generated/prism/dispatcher.rbi +1138 -0
  143. data/rbi/generated/prism/dot_visitor.rbi +618 -0
  144. data/rbi/generated/prism/dsl.rbi +751 -0
  145. data/rbi/generated/prism/inspect_visitor.rbi +503 -0
  146. data/rbi/generated/prism/lex_compat.rbi +162 -0
  147. data/rbi/generated/prism/mutation_compiler.rbi +464 -0
  148. data/rbi/generated/prism/node.rbi +13681 -0
  149. data/rbi/generated/prism/node_ext.rbi +259 -0
  150. data/rbi/generated/prism/node_find.rbi +79 -0
  151. data/rbi/generated/prism/parse_result/errors.rbi +21 -0
  152. data/rbi/generated/prism/parse_result/newlines.rbi +208 -0
  153. data/rbi/generated/prism/parse_result.rbi +764 -0
  154. data/rbi/generated/prism/pattern.rbi +134 -0
  155. data/rbi/generated/prism/reflection.rbi +89 -0
  156. data/rbi/generated/prism/relocation.rbi +329 -0
  157. data/rbi/generated/prism/serialize.rbi +181 -0
  158. data/rbi/generated/prism/string_query.rbi +36 -0
  159. data/rbi/generated/prism/translation.rbi +7 -0
  160. data/rbi/generated/prism/visitor.rbi +650 -0
  161. data/rbi/generated/prism.rbi +86 -0
  162. data/rbi/prism/translation/parser.rbi +11 -0
  163. data/rbi/prism/translation/parser_versions.rbi +28 -0
  164. data/rbi/prism/translation/ripper.rbi +15 -0
  165. data/rbi/rubyvm/node_find.rbi +14 -0
  166. data/sig/generated/prism/compiler.rbs +492 -0
  167. data/sig/generated/prism/desugar_compiler.rbs +305 -0
  168. data/sig/generated/prism/dispatcher.rbs +1292 -0
  169. data/sig/generated/prism/dot_visitor.rbs +635 -0
  170. data/sig/generated/prism/dsl.rbs +928 -0
  171. data/sig/generated/prism/inspect_visitor.rbs +509 -0
  172. data/sig/generated/prism/lex_compat.rbs +166 -0
  173. data/sig/generated/prism/mutation_compiler.rbs +464 -0
  174. data/sig/generated/prism/node.rbs +20160 -0
  175. data/sig/generated/prism/node_ext.rbs +290 -0
  176. data/sig/generated/prism/node_find.rbs +90 -0
  177. data/sig/generated/prism/parse_result/errors.rbs +22 -0
  178. data/sig/generated/prism/parse_result/newlines.rbs +223 -0
  179. data/sig/generated/prism/parse_result.rbs +859 -0
  180. data/sig/generated/prism/pattern.rbs +156 -0
  181. data/sig/generated/prism/reflection.rbs +101 -0
  182. data/sig/generated/prism/relocation.rbs +428 -0
  183. data/sig/generated/prism/serialize.rbs +195 -0
  184. data/sig/generated/prism/string_query.rbs +36 -0
  185. data/sig/generated/prism/translation.rbs +8 -0
  186. data/sig/generated/prism/visitor.rbs +1111 -0
  187. data/sig/generated/prism.rbs +84 -0
  188. data/sig/manifest.yaml +2 -0
  189. data/src/arena.c +117 -0
  190. data/src/buffer.c +380 -0
  191. data/src/char.c +289 -0
  192. data/src/comments.c +454 -0
  193. data/src/constant_pool.c +406 -0
  194. data/src/diagnostic.c +886 -0
  195. data/src/encoding.c +5345 -0
  196. data/src/errors_format.c +519 -0
  197. data/src/integer.c +681 -0
  198. data/src/json.c +5733 -0
  199. data/src/line_offset_list.c +100 -0
  200. data/src/list.c +24 -0
  201. data/src/memchr.c +37 -0
  202. data/src/node.c +4515 -0
  203. data/src/options.c +451 -0
  204. data/src/parser.c +349 -0
  205. data/src/prettyprint.c +9024 -0
  206. data/src/prism.c +23739 -0
  207. data/src/regexp.c +1706 -0
  208. data/src/serialize.c +2309 -0
  209. data/src/source.c +518 -0
  210. data/src/static_literals.c +685 -0
  211. data/src/string_query.c +166 -0
  212. data/src/stringy.c +91 -0
  213. data/src/strncasecmp.c +37 -0
  214. data/src/strpbrk.c +447 -0
  215. data/src/tokens.c +724 -0
  216. metadata +259 -0
@@ -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
+ }