yarp 0.11.0 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
data/src/serialize.c CHANGED
@@ -67,10 +67,16 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) {
67
67
  // it is not part of the AST
68
68
  case YP_SCOPE_NODE:
69
69
  return;
70
- case YP_ALIAS_NODE: {
71
- yp_serialize_node(parser, (yp_node_t *)((yp_alias_node_t *)node)->new_name, buffer);
72
- yp_serialize_node(parser, (yp_node_t *)((yp_alias_node_t *)node)->old_name, buffer);
73
- yp_serialize_location(parser, &((yp_alias_node_t *)node)->keyword_loc, buffer);
70
+ case YP_ALIAS_GLOBAL_VARIABLE_NODE: {
71
+ yp_serialize_node(parser, (yp_node_t *)((yp_alias_global_variable_node_t *)node)->new_name, buffer);
72
+ yp_serialize_node(parser, (yp_node_t *)((yp_alias_global_variable_node_t *)node)->old_name, buffer);
73
+ yp_serialize_location(parser, &((yp_alias_global_variable_node_t *)node)->keyword_loc, buffer);
74
+ break;
75
+ }
76
+ case YP_ALIAS_METHOD_NODE: {
77
+ yp_serialize_node(parser, (yp_node_t *)((yp_alias_method_node_t *)node)->new_name, buffer);
78
+ yp_serialize_node(parser, (yp_node_t *)((yp_alias_method_node_t *)node)->old_name, buffer);
79
+ yp_serialize_location(parser, &((yp_alias_method_node_t *)node)->keyword_loc, buffer);
74
80
  break;
75
81
  }
76
82
  case YP_ALTERNATION_PATTERN_NODE: {
@@ -323,7 +329,7 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) {
323
329
  yp_buffer_append_u8(buffer, 1);
324
330
  yp_serialize_location(parser, &((yp_call_and_write_node_t *)node)->closing_loc, buffer);
325
331
  }
326
- yp_buffer_append_u32(buffer, node->flags >> 1);
332
+ yp_buffer_append_u32(buffer, node->flags >> 2);
327
333
  yp_serialize_string(parser, &((yp_call_and_write_node_t *)node)->read_name, buffer);
328
334
  yp_serialize_string(parser, &((yp_call_and_write_node_t *)node)->write_name, buffer);
329
335
  yp_serialize_location(parser, &((yp_call_and_write_node_t *)node)->operator_loc, buffer);
@@ -370,7 +376,7 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) {
370
376
  } else {
371
377
  yp_serialize_node(parser, (yp_node_t *)((yp_call_node_t *)node)->block, buffer);
372
378
  }
373
- yp_buffer_append_u32(buffer, node->flags >> 1);
379
+ yp_buffer_append_u32(buffer, node->flags >> 2);
374
380
  yp_serialize_string(parser, &((yp_call_node_t *)node)->name, buffer);
375
381
  break;
376
382
  }
@@ -409,7 +415,7 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) {
409
415
  yp_buffer_append_u8(buffer, 1);
410
416
  yp_serialize_location(parser, &((yp_call_operator_write_node_t *)node)->closing_loc, buffer);
411
417
  }
412
- yp_buffer_append_u32(buffer, node->flags >> 1);
418
+ yp_buffer_append_u32(buffer, node->flags >> 2);
413
419
  yp_serialize_string(parser, &((yp_call_operator_write_node_t *)node)->read_name, buffer);
414
420
  yp_serialize_string(parser, &((yp_call_operator_write_node_t *)node)->write_name, buffer);
415
421
  yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_call_operator_write_node_t *)node)->operator));
@@ -452,7 +458,7 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) {
452
458
  yp_buffer_append_u8(buffer, 1);
453
459
  yp_serialize_location(parser, &((yp_call_or_write_node_t *)node)->closing_loc, buffer);
454
460
  }
455
- yp_buffer_append_u32(buffer, node->flags >> 1);
461
+ yp_buffer_append_u32(buffer, node->flags >> 2);
456
462
  yp_serialize_string(parser, &((yp_call_or_write_node_t *)node)->read_name, buffer);
457
463
  yp_serialize_string(parser, &((yp_call_or_write_node_t *)node)->write_name, buffer);
458
464
  yp_serialize_location(parser, &((yp_call_or_write_node_t *)node)->operator_loc, buffer);
@@ -799,7 +805,7 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) {
799
805
  yp_serialize_node(parser, (yp_node_t *)((yp_flip_flop_node_t *)node)->right, buffer);
800
806
  }
801
807
  yp_serialize_location(parser, &((yp_flip_flop_node_t *)node)->operator_loc, buffer);
802
- yp_buffer_append_u32(buffer, node->flags >> 1);
808
+ yp_buffer_append_u32(buffer, node->flags >> 2);
803
809
  break;
804
810
  }
805
811
  case YP_FLOAT_NODE: {
@@ -945,6 +951,10 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) {
945
951
  yp_serialize_node(parser, (yp_node_t *)((yp_imaginary_node_t *)node)->numeric, buffer);
946
952
  break;
947
953
  }
954
+ case YP_IMPLICIT_NODE: {
955
+ yp_serialize_node(parser, (yp_node_t *)((yp_implicit_node_t *)node)->value, buffer);
956
+ break;
957
+ }
948
958
  case YP_IN_NODE: {
949
959
  yp_serialize_node(parser, (yp_node_t *)((yp_in_node_t *)node)->pattern, buffer);
950
960
  if (((yp_in_node_t *)node)->statements == NULL) {
@@ -999,6 +1009,18 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) {
999
1009
  break;
1000
1010
  }
1001
1011
  case YP_INTEGER_NODE: {
1012
+ yp_buffer_append_u32(buffer, node->flags >> 2);
1013
+ break;
1014
+ }
1015
+ case YP_INTERPOLATED_MATCH_LAST_LINE_NODE: {
1016
+ yp_serialize_location(parser, &((yp_interpolated_match_last_line_node_t *)node)->opening_loc, buffer);
1017
+ uint32_t parts_size = yp_sizet_to_u32(((yp_interpolated_match_last_line_node_t *)node)->parts.size);
1018
+ yp_buffer_append_u32(buffer, parts_size);
1019
+ for (uint32_t index = 0; index < parts_size; index++) {
1020
+ yp_serialize_node(parser, (yp_node_t *) ((yp_interpolated_match_last_line_node_t *)node)->parts.nodes[index], buffer);
1021
+ }
1022
+ yp_serialize_location(parser, &((yp_interpolated_match_last_line_node_t *)node)->closing_loc, buffer);
1023
+ yp_buffer_append_u32(buffer, node->flags >> 2);
1002
1024
  break;
1003
1025
  }
1004
1026
  case YP_INTERPOLATED_REGULAR_EXPRESSION_NODE: {
@@ -1009,7 +1031,7 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) {
1009
1031
  yp_serialize_node(parser, (yp_node_t *) ((yp_interpolated_regular_expression_node_t *)node)->parts.nodes[index], buffer);
1010
1032
  }
1011
1033
  yp_serialize_location(parser, &((yp_interpolated_regular_expression_node_t *)node)->closing_loc, buffer);
1012
- yp_buffer_append_u32(buffer, node->flags >> 1);
1034
+ yp_buffer_append_u32(buffer, node->flags >> 2);
1013
1035
  break;
1014
1036
  }
1015
1037
  case YP_INTERPOLATED_STRING_NODE: {
@@ -1155,6 +1177,14 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) {
1155
1177
  yp_serialize_location(parser, &((yp_local_variable_write_node_t *)node)->operator_loc, buffer);
1156
1178
  break;
1157
1179
  }
1180
+ case YP_MATCH_LAST_LINE_NODE: {
1181
+ yp_serialize_location(parser, &((yp_match_last_line_node_t *)node)->opening_loc, buffer);
1182
+ yp_serialize_location(parser, &((yp_match_last_line_node_t *)node)->content_loc, buffer);
1183
+ yp_serialize_location(parser, &((yp_match_last_line_node_t *)node)->closing_loc, buffer);
1184
+ yp_serialize_string(parser, &((yp_match_last_line_node_t *)node)->unescaped, buffer);
1185
+ yp_buffer_append_u32(buffer, node->flags >> 2);
1186
+ break;
1187
+ }
1158
1188
  case YP_MATCH_PREDICATE_NODE: {
1159
1189
  yp_serialize_node(parser, (yp_node_t *)((yp_match_predicate_node_t *)node)->value, buffer);
1160
1190
  yp_serialize_node(parser, (yp_node_t *)((yp_match_predicate_node_t *)node)->pattern, buffer);
@@ -1167,6 +1197,15 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) {
1167
1197
  yp_serialize_location(parser, &((yp_match_required_node_t *)node)->operator_loc, buffer);
1168
1198
  break;
1169
1199
  }
1200
+ case YP_MATCH_WRITE_NODE: {
1201
+ yp_serialize_node(parser, (yp_node_t *)((yp_match_write_node_t *)node)->call, buffer);
1202
+ uint32_t locals_size = yp_sizet_to_u32(((yp_match_write_node_t *)node)->locals.size);
1203
+ yp_buffer_append_u32(buffer, locals_size);
1204
+ for (uint32_t index = 0; index < locals_size; index++) {
1205
+ yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_match_write_node_t *)node)->locals.ids[index]));
1206
+ }
1207
+ break;
1208
+ }
1170
1209
  case YP_MISSING_NODE: {
1171
1210
  break;
1172
1211
  }
@@ -1274,16 +1313,16 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) {
1274
1313
  for (uint32_t index = 0; index < optionals_size; index++) {
1275
1314
  yp_serialize_node(parser, (yp_node_t *) ((yp_parameters_node_t *)node)->optionals.nodes[index], buffer);
1276
1315
  }
1277
- uint32_t posts_size = yp_sizet_to_u32(((yp_parameters_node_t *)node)->posts.size);
1278
- yp_buffer_append_u32(buffer, posts_size);
1279
- for (uint32_t index = 0; index < posts_size; index++) {
1280
- yp_serialize_node(parser, (yp_node_t *) ((yp_parameters_node_t *)node)->posts.nodes[index], buffer);
1281
- }
1282
1316
  if (((yp_parameters_node_t *)node)->rest == NULL) {
1283
1317
  yp_buffer_append_u8(buffer, 0);
1284
1318
  } else {
1285
1319
  yp_serialize_node(parser, (yp_node_t *)((yp_parameters_node_t *)node)->rest, buffer);
1286
1320
  }
1321
+ uint32_t posts_size = yp_sizet_to_u32(((yp_parameters_node_t *)node)->posts.size);
1322
+ yp_buffer_append_u32(buffer, posts_size);
1323
+ for (uint32_t index = 0; index < posts_size; index++) {
1324
+ yp_serialize_node(parser, (yp_node_t *) ((yp_parameters_node_t *)node)->posts.nodes[index], buffer);
1325
+ }
1287
1326
  uint32_t keywords_size = yp_sizet_to_u32(((yp_parameters_node_t *)node)->keywords.size);
1288
1327
  yp_buffer_append_u32(buffer, keywords_size);
1289
1328
  for (uint32_t index = 0; index < keywords_size; index++) {
@@ -1366,7 +1405,7 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) {
1366
1405
  yp_serialize_node(parser, (yp_node_t *)((yp_range_node_t *)node)->right, buffer);
1367
1406
  }
1368
1407
  yp_serialize_location(parser, &((yp_range_node_t *)node)->operator_loc, buffer);
1369
- yp_buffer_append_u32(buffer, node->flags >> 1);
1408
+ yp_buffer_append_u32(buffer, node->flags >> 2);
1370
1409
  break;
1371
1410
  }
1372
1411
  case YP_RATIONAL_NODE: {
@@ -1381,7 +1420,7 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) {
1381
1420
  yp_serialize_location(parser, &((yp_regular_expression_node_t *)node)->content_loc, buffer);
1382
1421
  yp_serialize_location(parser, &((yp_regular_expression_node_t *)node)->closing_loc, buffer);
1383
1422
  yp_serialize_string(parser, &((yp_regular_expression_node_t *)node)->unescaped, buffer);
1384
- yp_buffer_append_u32(buffer, node->flags >> 1);
1423
+ yp_buffer_append_u32(buffer, node->flags >> 2);
1385
1424
  break;
1386
1425
  }
1387
1426
  case YP_REQUIRED_DESTRUCTURED_PARAMETER_NODE: {
@@ -1510,6 +1549,7 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) {
1510
1549
  break;
1511
1550
  }
1512
1551
  case YP_STRING_NODE: {
1552
+ yp_buffer_append_u32(buffer, node->flags >> 2);
1513
1553
  if (((yp_string_node_t *)node)->opening_loc.start == NULL) {
1514
1554
  yp_buffer_append_u8(buffer, 0);
1515
1555
  } else {
@@ -1621,7 +1661,7 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) {
1621
1661
  } else {
1622
1662
  yp_serialize_node(parser, (yp_node_t *)((yp_until_node_t *)node)->statements, buffer);
1623
1663
  }
1624
- yp_buffer_append_u32(buffer, node->flags >> 1);
1664
+ yp_buffer_append_u32(buffer, node->flags >> 2);
1625
1665
  break;
1626
1666
  }
1627
1667
  case YP_WHEN_NODE: {
@@ -1652,7 +1692,7 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) {
1652
1692
  } else {
1653
1693
  yp_serialize_node(parser, (yp_node_t *)((yp_while_node_t *)node)->statements, buffer);
1654
1694
  }
1655
- yp_buffer_append_u32(buffer, node->flags >> 1);
1695
+ yp_buffer_append_u32(buffer, node->flags >> 2);
1656
1696
  break;
1657
1697
  }
1658
1698
  case YP_X_STRING_NODE: {
data/src/util/yp_char.c CHANGED
@@ -123,6 +123,9 @@ yp_char_is_inline_whitespace(const uint8_t b) {
123
123
  return yp_char_is_char_kind(b, YP_CHAR_BIT_INLINE_WHITESPACE);
124
124
  }
125
125
 
126
+ // Scan through the string and return the number of characters at the start of
127
+ // the string that match the given kind. Disallows searching past the given
128
+ // maximum number of characters.
126
129
  static inline size_t
127
130
  yp_strspn_number_kind(const uint8_t *string, ptrdiff_t length, uint8_t kind) {
128
131
  if (length <= 0) return 0;
@@ -134,20 +137,57 @@ yp_strspn_number_kind(const uint8_t *string, ptrdiff_t length, uint8_t kind) {
134
137
  return size;
135
138
  }
136
139
 
140
+ // Scan through the string and return the number of characters at the start of
141
+ // the string that match the given kind. Disallows searching past the given
142
+ // maximum number of characters.
143
+ //
144
+ // Additionally, report the location of the last invalid underscore character
145
+ // found in the string through the out invalid parameter.
146
+ static inline size_t
147
+ yp_strspn_number_kind_underscores(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid, uint8_t kind) {
148
+ if (length <= 0) return 0;
149
+
150
+ size_t size = 0;
151
+ size_t maximum = (size_t) length;
152
+
153
+ bool underscore = false;
154
+ while (size < maximum && (yp_number_table[string[size]] & kind)) {
155
+ if (string[size] == '_') {
156
+ if (underscore) *invalid = string + size;
157
+ underscore = true;
158
+ } else {
159
+ underscore = false;
160
+ }
161
+
162
+ size++;
163
+ }
164
+
165
+ if (string[size - 1] == '_') *invalid = string + size - 1;
166
+ return size;
167
+ }
168
+
137
169
  // Returns the number of characters at the start of the string that are binary
138
170
  // digits or underscores. Disallows searching past the given maximum number of
139
171
  // characters.
172
+ //
173
+ // If multiple underscores are found in a row or if an underscore is
174
+ // found at the end of the number, then the invalid pointer is set to the index
175
+ // of the first invalid underscore.
140
176
  size_t
141
- yp_strspn_binary_number(const uint8_t *string, ptrdiff_t length) {
142
- return yp_strspn_number_kind(string, length, YP_NUMBER_BIT_BINARY_NUMBER);
177
+ yp_strspn_binary_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid) {
178
+ return yp_strspn_number_kind_underscores(string, length, invalid, YP_NUMBER_BIT_BINARY_NUMBER);
143
179
  }
144
180
 
145
181
  // Returns the number of characters at the start of the string that are octal
146
- // digits or underscores. Disallows searching past the given maximum number of
182
+ // digits or underscores. Disallows searching past the given maximum number of
147
183
  // characters.
184
+ //
185
+ // If multiple underscores are found in a row or if an underscore is
186
+ // found at the end of the number, then the invalid pointer is set to the index
187
+ // of the first invalid underscore.
148
188
  size_t
149
- yp_strspn_octal_number(const uint8_t *string, ptrdiff_t length) {
150
- return yp_strspn_number_kind(string, length, YP_NUMBER_BIT_OCTAL_NUMBER);
189
+ yp_strspn_octal_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid) {
190
+ return yp_strspn_number_kind_underscores(string, length, invalid, YP_NUMBER_BIT_OCTAL_NUMBER);
151
191
  }
152
192
 
153
193
  // Returns the number of characters at the start of the string that are decimal
@@ -160,9 +200,13 @@ yp_strspn_decimal_digit(const uint8_t *string, ptrdiff_t length) {
160
200
  // Returns the number of characters at the start of the string that are decimal
161
201
  // digits or underscores. Disallows searching past the given maximum number of
162
202
  // characters.
203
+ //
204
+ // If multiple underscores are found in a row or if an underscore is
205
+ // found at the end of the number, then the invalid pointer is set to the index
206
+ // of the first invalid underscore.
163
207
  size_t
164
- yp_strspn_decimal_number(const uint8_t *string, ptrdiff_t length) {
165
- return yp_strspn_number_kind(string, length, YP_NUMBER_BIT_DECIMAL_NUMBER);
208
+ yp_strspn_decimal_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid) {
209
+ return yp_strspn_number_kind_underscores(string, length, invalid, YP_NUMBER_BIT_DECIMAL_NUMBER);
166
210
  }
167
211
 
168
212
  // Returns the number of characters at the start of the string that are
@@ -176,9 +220,13 @@ yp_strspn_hexadecimal_digit(const uint8_t *string, ptrdiff_t length) {
176
220
  // Returns the number of characters at the start of the string that are
177
221
  // hexadecimal digits or underscores. Disallows searching past the given maximum
178
222
  // number of characters.
223
+ //
224
+ // If multiple underscores are found in a row or if an underscore is
225
+ // found at the end of the number, then the invalid pointer is set to the index
226
+ // of the first invalid underscore.
179
227
  size_t
180
- yp_strspn_hexadecimal_number(const uint8_t *string, ptrdiff_t length) {
181
- return yp_strspn_number_kind(string, length, YP_NUMBER_BIT_HEXADECIMAL_NUMBER);
228
+ yp_strspn_hexadecimal_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid) {
229
+ return yp_strspn_number_kind_underscores(string, length, invalid, YP_NUMBER_BIT_HEXADECIMAL_NUMBER);
182
230
  }
183
231
 
184
232
  static inline bool
@@ -59,10 +59,42 @@ yp_constant_pool_hash(const uint8_t *start, size_t length) {
59
59
  return value;
60
60
  }
61
61
 
62
+ // https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
63
+ static size_t
64
+ next_power_of_two(size_t v) {
65
+ // Avoid underflow in subtraction on next line.
66
+ if (v == 0) {
67
+ // 1 is the nearest power of 2 to 0 (2^0)
68
+ return 1;
69
+ }
70
+ v--;
71
+ v |= v >> 1;
72
+ v |= v >> 2;
73
+ v |= v >> 4;
74
+ v |= v >> 8;
75
+ v |= v >> 16;
76
+ #if defined(__LP64__) || defined(_WIN64)
77
+ v |= v >> 32;
78
+ #endif
79
+ v++;
80
+ return v;
81
+ }
82
+
83
+ #ifndef NDEBUG
84
+ static bool
85
+ is_power_of_two(size_t size) {
86
+ return (size & (size - 1)) == 0;
87
+ }
88
+ #endif
89
+
62
90
  // Resize a constant pool to a given capacity.
63
91
  static inline bool
64
92
  yp_constant_pool_resize(yp_constant_pool_t *pool) {
93
+ assert(is_power_of_two(pool->capacity));
65
94
  size_t next_capacity = pool->capacity * 2;
95
+ if (next_capacity < pool->capacity) return false;
96
+
97
+ const size_t mask = next_capacity - 1;
66
98
  yp_constant_t *next_constants = calloc(next_capacity, sizeof(yp_constant_t));
67
99
  if (next_constants == NULL) return false;
68
100
 
@@ -74,13 +106,13 @@ yp_constant_pool_resize(yp_constant_pool_t *pool) {
74
106
  // If an id is set on this constant, then we know we have content here.
75
107
  // In this case we need to insert it into the next constant pool.
76
108
  if (constant->id != 0) {
77
- size_t next_index = constant->hash % next_capacity;
109
+ size_t next_index = constant->hash & mask;
78
110
 
79
111
  // This implements linear scanning to find the next available slot
80
112
  // in case this index is already taken. We don't need to bother
81
113
  // comparing the values since we know that the hash is unique.
82
114
  while (next_constants[next_index].id != 0) {
83
- next_index = (next_index + 1) % next_capacity;
115
+ next_index = (next_index + 1) & mask;
84
116
  }
85
117
 
86
118
  // Here we copy over the entire constant, which includes the id so
@@ -98,6 +130,10 @@ yp_constant_pool_resize(yp_constant_pool_t *pool) {
98
130
  // Initialize a new constant pool with a given capacity.
99
131
  bool
100
132
  yp_constant_pool_init(yp_constant_pool_t *pool, size_t capacity) {
133
+ const size_t size_t_max = (~((size_t) 0));
134
+ if (capacity >= ((size_t_max / 2) + 1)) return false;
135
+
136
+ capacity = next_power_of_two(capacity);
101
137
  pool->constants = calloc(capacity, sizeof(yp_constant_t));
102
138
  if (pool->constants == NULL) return false;
103
139
 
@@ -107,14 +143,16 @@ yp_constant_pool_init(yp_constant_pool_t *pool, size_t capacity) {
107
143
  }
108
144
 
109
145
  // Insert a constant into a constant pool and return its index in the pool.
110
- static size_t
111
- yp_constant_pool_insert(yp_constant_pool_t *pool, const uint8_t *start, size_t length) {
146
+ static inline yp_constant_id_t
147
+ yp_constant_pool_insert(yp_constant_pool_t *pool, const uint8_t *start, size_t length, bool owned) {
112
148
  if (pool->size >= (pool->capacity / 4 * 3)) {
113
- if (!yp_constant_pool_resize(pool)) return pool->capacity;
149
+ if (!yp_constant_pool_resize(pool)) return 0;
114
150
  }
115
151
 
152
+ assert(is_power_of_two(pool->capacity));
153
+ const size_t mask = pool->capacity - 1;
116
154
  size_t hash = yp_constant_pool_hash(start, length);
117
- size_t index = hash % pool->capacity;
155
+ size_t index = hash & mask;
118
156
  yp_constant_t *constant;
119
157
 
120
158
  while (constant = &pool->constants[index], constant->id != 0) {
@@ -122,31 +160,49 @@ yp_constant_pool_insert(yp_constant_pool_t *pool, const uint8_t *start, size_t l
122
160
  // same as the content we are trying to insert. If it is, then we can
123
161
  // return the id of the existing constant.
124
162
  if ((constant->length == length) && memcmp(constant->start, start, length) == 0) {
125
- return index;
163
+ // Since we have found a match, we need to check if this is
164
+ // attempting to insert a shared or an owned constant. We want to
165
+ // prefer shared constants since they don't require allocations.
166
+ if (owned) {
167
+ // If we're attempting to insert an owned constant and we have
168
+ // an existing constant, then either way we don't want the given
169
+ // memory. Either it's duplicated with the existing constant or
170
+ // it's not necessary because we have a shared version.
171
+ free((void *) start);
172
+ } else if (constant->owned) {
173
+ // If we're attempting to insert a shared constant and the
174
+ // existing constant is owned, then we can free the owned
175
+ // constant and replace it with the shared constant.
176
+ free((void *) constant->start);
177
+ constant->start = start;
178
+ constant->owned = false;
179
+ }
180
+
181
+ return constant->id;
126
182
  }
127
183
 
128
- index = (index + 1) % pool->capacity;
184
+ index = (index + 1) & mask;
129
185
  }
130
186
 
131
187
  pool->size++;
132
188
  assert(pool->size < ((size_t) (1 << 31)));
133
189
 
134
- pool->constants[index] = (yp_constant_t) {
190
+ *constant = (yp_constant_t) {
135
191
  .id = (unsigned int) (pool->size & 0x7FFFFFFF),
192
+ .owned = owned,
136
193
  .start = start,
137
194
  .length = length,
138
195
  .hash = hash
139
196
  };
140
197
 
141
- return index;
198
+ return constant->id;
142
199
  }
143
200
 
144
201
  // Insert a constant into a constant pool. Returns the id of the constant, or 0
145
202
  // if any potential calls to resize fail.
146
203
  yp_constant_id_t
147
204
  yp_constant_pool_insert_shared(yp_constant_pool_t *pool, const uint8_t *start, size_t length) {
148
- size_t index = yp_constant_pool_insert(pool, start, length);
149
- return index == pool->capacity ? 0 : ((yp_constant_id_t) pool->constants[index].id);
205
+ return yp_constant_pool_insert(pool, start, length, false);
150
206
  }
151
207
 
152
208
  // Insert a constant into a constant pool from memory that is now owned by the
@@ -154,12 +210,7 @@ yp_constant_pool_insert_shared(yp_constant_pool_t *pool, const uint8_t *start, s
154
210
  // resize fail.
155
211
  yp_constant_id_t
156
212
  yp_constant_pool_insert_owned(yp_constant_pool_t *pool, const uint8_t *start, size_t length) {
157
- size_t index = yp_constant_pool_insert(pool, start, length);
158
- if (index == pool->capacity) return 0;
159
-
160
- yp_constant_t *constant = &pool->constants[index];
161
- constant->owned = true;
162
- return ((yp_constant_id_t) constant->id);
213
+ return yp_constant_pool_insert(pool, start, length, true);
163
214
  }
164
215
 
165
216
  // Free the memory associated with a constant pool.