/src/Python-3.8.3/Parser/node.c
Line  | Count  | Source  | 
1  |  | /* Parse tree node implementation */  | 
2  |  |  | 
3  |  | #include "Python.h"  | 
4  |  | #include "node.h"  | 
5  |  | #include "errcode.h"  | 
6  |  |  | 
7  |  | node *  | 
8  |  | PyNode_New(int type)  | 
9  | 18  | { | 
10  | 18  |     node *n = (node *) PyObject_MALLOC(1 * sizeof(node));  | 
11  | 18  |     if (n == NULL)  | 
12  | 0  |         return NULL;  | 
13  | 18  |     n->n_type = type;  | 
14  | 18  |     n->n_str = NULL;  | 
15  | 18  |     n->n_lineno = 0;  | 
16  | 18  |     n->n_end_lineno = 0;  | 
17  | 18  |     n->n_end_col_offset = -1;  | 
18  | 18  |     n->n_nchildren = 0;  | 
19  | 18  |     n->n_child = NULL;  | 
20  | 18  |     return n;  | 
21  | 18  | }  | 
22  |  |  | 
23  |  | /* See comments at XXXROUNDUP below.  Returns -1 on overflow. */  | 
24  |  | static int  | 
25  |  | fancy_roundup(int n)  | 
26  | 0  | { | 
27  |  |     /* Round up to the closest power of 2 >= n. */  | 
28  | 0  |     int result = 256;  | 
29  | 0  |     assert(n > 128);  | 
30  | 0  |     while (result < n) { | 
31  | 0  |         result <<= 1;  | 
32  | 0  |         if (result <= 0)  | 
33  | 0  |             return -1;  | 
34  | 0  |     }  | 
35  | 0  |     return result;  | 
36  | 0  | }  | 
37  |  |  | 
38  |  | /* A gimmick to make massive numbers of reallocs quicker.  The result is  | 
39  |  |  * a number >= the input.  In PyNode_AddChild, it's used like so, when  | 
40  |  |  * we're about to add child number current_size + 1:  | 
41  |  |  *  | 
42  |  |  *     if XXXROUNDUP(current_size) < XXXROUNDUP(current_size + 1):  | 
43  |  |  *         allocate space for XXXROUNDUP(current_size + 1) total children  | 
44  |  |  *     else:  | 
45  |  |  *         we already have enough space  | 
46  |  |  *  | 
47  |  |  * Since a node starts out empty, we must have  | 
48  |  |  *  | 
49  |  |  *     XXXROUNDUP(0) < XXXROUNDUP(1)  | 
50  |  |  *  | 
51  |  |  * so that we allocate space for the first child.  One-child nodes are very  | 
52  |  |  * common (presumably that would change if we used a more abstract form  | 
53  |  |  * of syntax tree), so to avoid wasting memory it's desirable that  | 
54  |  |  * XXXROUNDUP(1) == 1.  That in turn forces XXXROUNDUP(0) == 0.  | 
55  |  |  *  | 
56  |  |  * Else for 2 <= n <= 128, we round up to the closest multiple of 4.  Why 4?  | 
57  |  |  * Rounding up to a multiple of an exact power of 2 is very efficient, and  | 
58  |  |  * most nodes with more than one child have <= 4 kids.  | 
59  |  |  *  | 
60  |  |  * Else we call fancy_roundup() to grow proportionately to n.  We've got an  | 
61  |  |  * extreme case then (like test_longexp.py), and on many platforms doing  | 
62  |  |  * anything less than proportional growth leads to exorbitant runtime  | 
63  |  |  * (e.g., MacPython), or extreme fragmentation of user address space (e.g.,  | 
64  |  |  * Win98).  | 
65  |  |  *  | 
66  |  |  * In a run of compileall across the 2.3a0 Lib directory, Andrew MacIntyre  | 
67  |  |  * reported that, with this scheme, 89% of PyObject_REALLOC calls in  | 
68  |  |  * PyNode_AddChild passed 1 for the size, and 9% passed 4.  So this usually  | 
69  |  |  * wastes very little memory, but is very effective at sidestepping  | 
70  |  |  * platform-realloc disasters on vulnerable platforms.  | 
71  |  |  *  | 
72  |  |  * Note that this would be straightforward if a node stored its current  | 
73  |  |  * capacity.  The code is tricky to avoid that.  | 
74  |  |  */  | 
75  | 16.0k  | #define XXXROUNDUP(n) ((n) <= 1 ? (n) :                         \  | 
76  | 16.0k  |                (n) <= 128 ? (int)_Py_SIZE_ROUND_UP((n), 4) :    \  | 
77  | 2.13k  |                fancy_roundup(n))  | 
78  |  |  | 
79  |  |  | 
80  |  | void  | 
81  |  | _PyNode_FinalizeEndPos(node *n)  | 
82  | 8.03k  | { | 
83  | 8.03k  |     int nch = NCH(n);  | 
84  | 8.03k  |     node *last;  | 
85  | 8.03k  |     if (nch == 0) { | 
86  | 1.41k  |         return;  | 
87  | 1.41k  |     }  | 
88  | 6.62k  |     last = CHILD(n, nch - 1);  | 
89  | 6.62k  |     _PyNode_FinalizeEndPos(last);  | 
90  | 6.62k  |     n->n_end_lineno = last->n_end_lineno;  | 
91  | 6.62k  |     n->n_end_col_offset = last->n_end_col_offset;  | 
92  | 6.62k  | }  | 
93  |  |  | 
94  |  | int  | 
95  |  | PyNode_AddChild(node *n1, int type, char *str, int lineno, int col_offset,  | 
96  |  |                 int end_lineno, int end_col_offset)  | 
97  | 8.01k  | { | 
98  | 8.01k  |     const int nch = n1->n_nchildren;  | 
99  | 8.01k  |     int current_capacity;  | 
100  | 8.01k  |     int required_capacity;  | 
101  | 8.01k  |     node *n;  | 
102  |  |  | 
103  |  |     // finalize end position of previous node (if any)  | 
104  | 8.01k  |     if (nch > 0) { | 
105  | 1.39k  |         _PyNode_FinalizeEndPos(CHILD(n1, nch - 1));  | 
106  | 1.39k  |     }  | 
107  |  |  | 
108  | 8.01k  |     if (nch == INT_MAX || nch < 0)  | 
109  | 0  |         return E_OVERFLOW;  | 
110  |  |  | 
111  | 8.01k  |     current_capacity = XXXROUNDUP(nch);  | 
112  | 8.01k  |     required_capacity = XXXROUNDUP(nch + 1);  | 
113  | 8.01k  |     if (current_capacity < 0 || required_capacity < 0)  | 
114  | 0  |         return E_OVERFLOW;  | 
115  | 8.01k  |     if (current_capacity < required_capacity) { | 
116  | 7.36k  |         if ((size_t)required_capacity > SIZE_MAX / sizeof(node)) { | 
117  | 0  |             return E_NOMEM;  | 
118  | 0  |         }  | 
119  | 7.36k  |         n = n1->n_child;  | 
120  | 7.36k  |         n = (node *) PyObject_REALLOC(n,  | 
121  | 7.36k  |                                       required_capacity * sizeof(node));  | 
122  | 7.36k  |         if (n == NULL)  | 
123  | 0  |             return E_NOMEM;  | 
124  | 7.36k  |         n1->n_child = n;  | 
125  | 7.36k  |     }  | 
126  |  |  | 
127  | 8.01k  |     n = &n1->n_child[n1->n_nchildren++];  | 
128  | 8.01k  |     n->n_type = type;  | 
129  | 8.01k  |     n->n_str = str;  | 
130  | 8.01k  |     n->n_lineno = lineno;  | 
131  | 8.01k  |     n->n_col_offset = col_offset;  | 
132  | 8.01k  |     n->n_end_lineno = end_lineno;  // this and below will be updates after all children are added.  | 
133  | 8.01k  |     n->n_end_col_offset = end_col_offset;  | 
134  | 8.01k  |     n->n_nchildren = 0;  | 
135  | 8.01k  |     n->n_child = NULL;  | 
136  | 8.01k  |     return 0;  | 
137  | 8.01k  | }  | 
138  |  |  | 
139  |  | /* Forward */  | 
140  |  | static void freechildren(node *);  | 
141  |  | static Py_ssize_t sizeofchildren(node *n);  | 
142  |  |  | 
143  |  |  | 
144  |  | void  | 
145  |  | PyNode_Free(node *n)  | 
146  | 32  | { | 
147  | 32  |     if (n != NULL) { | 
148  | 16  |         freechildren(n);  | 
149  | 16  |         PyObject_FREE(n);  | 
150  | 16  |     }  | 
151  | 32  | }  | 
152  |  |  | 
153  |  | Py_ssize_t  | 
154  |  | _PyNode_SizeOf(node *n)  | 
155  | 0  | { | 
156  | 0  |     Py_ssize_t res = 0;  | 
157  |  | 
  | 
158  | 0  |     if (n != NULL)  | 
159  | 0  |         res = sizeof(node) + sizeofchildren(n);  | 
160  | 0  |     return res;  | 
161  | 0  | }  | 
162  |  |  | 
163  |  | static void  | 
164  |  | freechildren(node *n)  | 
165  | 8.03k  | { | 
166  | 8.03k  |     int i;  | 
167  | 16.0k  |     for (i = NCH(n); --i >= 0; )  | 
168  | 8.01k  |         freechildren(CHILD(n, i));  | 
169  | 8.03k  |     if (n->n_child != NULL)  | 
170  | 6.62k  |         PyObject_FREE(n->n_child);  | 
171  | 8.03k  |     if (STR(n) != NULL)  | 
172  | 1.41k  |         PyObject_FREE(STR(n));  | 
173  | 8.03k  | }  | 
174  |  |  | 
175  |  | static Py_ssize_t  | 
176  |  | sizeofchildren(node *n)  | 
177  | 0  | { | 
178  | 0  |     Py_ssize_t res = 0;  | 
179  | 0  |     int i;  | 
180  | 0  |     for (i = NCH(n); --i >= 0; )  | 
181  | 0  |         res += sizeofchildren(CHILD(n, i));  | 
182  | 0  |     if (n->n_child != NULL)  | 
183  |  |         /* allocated size of n->n_child array */  | 
184  | 0  |         res += XXXROUNDUP(NCH(n)) * sizeof(node);  | 
185  | 0  |     if (STR(n) != NULL)  | 
186  | 0  |         res += strlen(STR(n)) + 1;  | 
187  | 0  |     return res;  | 
188  | 0  | }  |