yarp 0.11.0 → 0.12.0
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 +4 -4
- data/CHANGELOG.md +26 -1
- data/config.yml +105 -6
- data/ext/yarp/api_node.c +200 -34
- data/ext/yarp/extension.c +8 -1
- data/ext/yarp/extension.h +1 -1
- data/include/yarp/ast.h +246 -293
- data/include/yarp/diagnostic.h +7 -2
- data/include/yarp/enc/yp_encoding.h +1 -1
- data/include/yarp/parser.h +44 -16
- data/include/yarp/util/yp_char.h +21 -5
- data/include/yarp/version.h +2 -2
- data/lib/yarp/mutation_visitor.rb +28 -3
- data/lib/yarp/node.rb +3507 -85
- data/lib/yarp/serialize.rb +146 -136
- data/lib/yarp.rb +57 -42
- data/src/diagnostic.c +6 -1
- data/src/enc/yp_unicode.c +5 -5
- data/src/node.c +87 -8
- data/src/prettyprint.c +85 -21
- data/src/serialize.c +59 -19
- data/src/util/yp_char.c +57 -9
- data/src/util/yp_constant_pool.c +69 -18
- data/src/yarp.c +1528 -1018
- data/yarp.gemspec +1 -1
- metadata +3 -3
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
|
71
|
-
yp_serialize_node(parser, (yp_node_t *)((
|
72
|
-
yp_serialize_node(parser, (yp_node_t *)((
|
73
|
-
yp_serialize_location(parser, &((
|
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 >>
|
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 >>
|
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 >>
|
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 >>
|
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 >>
|
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 >>
|
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 >>
|
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 >>
|
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 >>
|
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 >>
|
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
|
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.
|
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
|
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
|
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
|
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
|
data/src/util/yp_constant_pool.c
CHANGED
@@ -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
|
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)
|
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
|
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
|
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
|
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
|
-
|
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)
|
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
|
-
|
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
|
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
|
-
|
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
|
-
|
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.
|