yarp 0.11.0 → 0.12.0
Sign up to get free protection for your applications and to get access to all the features.
- 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.
|