35
35
36
36
// NOTE: we are using linear arrays to store and search for qstr's (unique strings, interned strings)
37
37
// ultimately we will replace this with a static hash table of some kind
38
- // also probably need to include the length in the string data, to allow null bytes in the string
39
38
40
39
#if MICROPY_DEBUG_VERBOSE // print debugging info
41
40
#define DEBUG_printf DEBUG_printf
44
43
#endif
45
44
46
45
// A qstr is an index into the qstr pool.
47
- // The data for a qstr contains (hash, length, data):
48
- // - hash (configurable number of bytes)
49
- // - length (configurable number of bytes)
50
- // - data ("length" number of bytes)
51
- // - \0 terminated (so they can be printed using printf)
52
-
53
- #if MICROPY_QSTR_BYTES_IN_HASH == 1
54
- #define Q_HASH_MASK (0xff)
55
- #define Q_GET_HASH (q ) ((mp_uint_t)(q)[0])
56
- #define Q_SET_HASH (q , hash ) do { (q)[0] = (hash); } while (0)
57
- #elif MICROPY_QSTR_BYTES_IN_HASH == 2
58
- #define Q_HASH_MASK (0xffff)
59
- #define Q_GET_HASH (q ) ((mp_uint_t)(q)[0] | ((mp_uint_t)(q)[1] << 8))
60
- #define Q_SET_HASH (q , hash ) do { (q)[0] = (hash); (q)[1] = (hash) >> 8; } while (0)
61
- #else
62
- #error unimplemented qstr hash decoding
63
- #endif
64
- #define Q_GET_ALLOC (q ) (MICROPY_QSTR_BYTES_IN_HASH + MICROPY_QSTR_BYTES_IN_LEN + Q_GET_LENGTH(q) + 1)
65
- #define Q_GET_DATA (q ) ((q) + MICROPY_QSTR_BYTES_IN_HASH + MICROPY_QSTR_BYTES_IN_LEN)
66
- #if MICROPY_QSTR_BYTES_IN_LEN == 1
67
- #define Q_GET_LENGTH (q ) ((q)[MICROPY_QSTR_BYTES_IN_HASH])
68
- #define Q_SET_LENGTH (q , len ) do { (q)[MICROPY_QSTR_BYTES_IN_HASH] = (len); } while (0)
69
- #elif MICROPY_QSTR_BYTES_IN_LEN == 2
70
- #define Q_GET_LENGTH (q ) ((q)[MICROPY_QSTR_BYTES_IN_HASH] | ((q)[MICROPY_QSTR_BYTES_IN_HASH + 1] << 8))
71
- #define Q_SET_LENGTH (q , len ) do { (q)[MICROPY_QSTR_BYTES_IN_HASH] = (len); (q)[MICROPY_QSTR_BYTES_IN_HASH + 1] = (len) >> 8; } while (0)
72
- #else
73
- #error unimplemented qstr length decoding
74
- #endif
46
+ // The data for a qstr is \0 terminated (so they can be printed using printf)
47
+
48
+ #define Q_HASH_MASK ((1 << (8 * MICROPY_QSTR_BYTES_IN_HASH)) - 1)
75
49
76
50
#if MICROPY_PY_THREAD && !MICROPY_PY_THREAD_GIL
77
51
#define QSTR_ENTER () mp_thread_mutex_lock(&MP_STATE_VM(qstr_mutex), 1)
@@ -100,14 +74,32 @@ mp_uint_t qstr_compute_hash(const byte *data, size_t len) {
100
74
return hash ;
101
75
}
102
76
77
+ const qstr_hash_t mp_qstr_const_hashes [] = {
78
+ #ifndef NO_QSTR
79
+ #define QDEF (id , hash , len , str ) hash ,
80
+ #include "genhdr/qstrdefs.generated.h"
81
+ #undef QDEF
82
+ #endif
83
+ };
84
+
85
+ const qstr_len_t mp_qstr_const_lengths [] = {
86
+ #ifndef NO_QSTR
87
+ #define QDEF (id , hash , len , str ) len ,
88
+ #include "genhdr/qstrdefs.generated.h"
89
+ #undef QDEF
90
+ #endif
91
+ };
92
+
103
93
const qstr_pool_t mp_qstr_const_pool = {
104
94
NULL , // no previous pool
105
95
0 , // no previous pool
106
96
MICROPY_ALLOC_QSTR_ENTRIES_INIT ,
107
97
MP_QSTRnumber_of , // corresponds to number of strings in array just below
98
+ (qstr_hash_t * )mp_qstr_const_hashes ,
99
+ (qstr_len_t * )mp_qstr_const_lengths ,
108
100
{
109
101
#ifndef NO_QSTR
110
- #define QDEF (id , str ) str ,
102
+ #define QDEF (id , hash , len , str ) str ,
111
103
#include "genhdr/qstrdefs.generated.h"
112
104
#undef QDEF
113
105
#endif
@@ -130,19 +122,21 @@ void qstr_init(void) {
130
122
#endif
131
123
}
132
124
133
- STATIC const byte * find_qstr (qstr q ) {
125
+ STATIC qstr_pool_t * find_qstr (qstr * q ) {
134
126
// search pool for this qstr
135
127
// total_prev_len==0 in the final pool, so the loop will always terminate
136
128
qstr_pool_t * pool = MP_STATE_VM (last_pool );
137
- while (q < pool -> total_prev_len ) {
129
+ while (* q < pool -> total_prev_len ) {
138
130
pool = pool -> prev ;
139
131
}
140
- return pool -> qstrs [q - pool -> total_prev_len ];
132
+ * q -= pool -> total_prev_len ;
133
+ assert (* q < pool -> len );
134
+ return pool ;
141
135
}
142
136
143
137
// qstr_mutex must be taken while in this function
144
- STATIC qstr qstr_add (const byte * q_ptr ) {
145
- DEBUG_printf ("QSTR: add hash=%d len=%d data=%.*s\n" , Q_GET_HASH ( q_ptr ), Q_GET_LENGTH ( q_ptr ), Q_GET_LENGTH ( q_ptr ), Q_GET_DATA ( q_ptr ) );
138
+ STATIC qstr qstr_add (mp_uint_t hash , mp_uint_t len , const char * q_ptr ) {
139
+ DEBUG_printf ("QSTR: add hash=%d len=%d data=%.*s\n" , hash , len , len , q_ptr );
146
140
147
141
// make sure we have room in the pool for a new qstr
148
142
if (MP_STATE_VM (last_pool )-> len >= MP_STATE_VM (last_pool )-> alloc ) {
@@ -151,7 +145,9 @@ STATIC qstr qstr_add(const byte *q_ptr) {
151
145
// Put a lower bound on the allocation size in case the extra qstr pool has few entries
152
57AE
146
new_alloc = MAX (MICROPY_ALLOC_QSTR_ENTRIES_INIT , new_alloc );
153
147
#endif
154
- qstr_pool_t * pool = m_new_obj_var_maybe (qstr_pool_t , const char * , new_alloc );
148
+ mp_uint_t pool_size = sizeof (qstr_pool_t )
149
+ + (sizeof (const char * ) + sizeof (qstr_hash_t ) + sizeof (qstr_len_t )) * new_alloc ;
150
+ qstr_pool_t * pool = (qstr_pool_t * )m_malloc_maybe (pool_size );
155
151
if (pool == NULL ) {
156
152
// Keep qstr_last_chunk consistent with qstr_pool_t: qstr_last_chunk is not scanned
157
153
// at garbage collection since it's reachable from a qstr_pool_t. And the caller of
@@ -162,6 +158,8 @@ STATIC qstr qstr_add(const byte *q_ptr) {
162
158
QSTR_EXIT ();
163
159
m_malloc_fail (new_alloc );
164
160
}
161
+ pool -> hashes = (qstr_hash_t * )(pool -> qstrs + new_alloc );
162
+ pool -> lengths = (qstr_len_t * )(pool -> hashes + new_alloc );
165
163
pool -> prev = MP_STATE_VM (last_pool );
166
164
pool -> total_prev_len = MP_STATE_VM (last_pool )-> total_prev_len + MP_STATE_VM (last_pool )-> len ;
167
165
pool -> alloc = new_alloc ;
@@ -171,10 +169,14 @@ STATIC qstr qstr_add(const byte *q_ptr) {
171
169
}
172
170
173
171
// add the new qstr
174
- MP_STATE_VM (last_pool )-> qstrs [MP_STATE_VM (last_pool )-> len ++ ] = q_ptr ;
172
+ mp_uint_t at = MP_STATE_VM (last_pool )-> len ;
173
+ MP_STATE_VM (last_pool )-> hashes [at ] = hash ;
174
+ MP_STATE_VM (last_pool )-> lengths [at ] = len ;
175
+ MP_STATE_VM (last_pool )-> qstrs [at ] = q_ptr ;
176
+ MP_STATE_VM (last_pool )-> len ++ ;
175
177
176
178
// return id for the newly-added qstr
177
- return MP_STATE_VM (last_pool )-> total_prev_len + MP_STATE_VM ( last_pool ) -> len - 1 ;
179
+ return MP_STATE_VM (last_pool )-> total_prev_len + at ;
178
180
}
179
181
180
182
qstr qstr_find_strn (const char * str , size_t str_len ) {
@@ -183,9 +185,10 @@ qstr qstr_find_strn(const char *str, size_t str_len) {
183
185
184
186
// search pools for the data
185
187
for (qstr_pool_t * pool = MP_STATE_VM (last_pool ); pool != NULL ; pool = pool -> prev ) {
186
- for (const byte * * q = pool -> qstrs , * * q_top = pool -> qstrs + pool -> len ; q < q_top ; q ++ ) {
187
- if (Q_GET_HASH (* q ) == str_hash && Q_GET_LENGTH (* q ) == str_len && memcmp (Q_GET_DATA (* q ), str , str_len ) == 0 ) {
188
- return pool -> total_prev_len + (q - pool -> qstrs );
188
+ for (mp_uint_t at = 0 , top = pool -> len ; at < top ; at ++ ) {
189
+ if (pool -> hashes [at ] == str_hash && pool -> lengths [at ] == str_len
190
+ && memcmp (pool -> qstrs [at ], str , str_len ) == 0 ) {
191
+ return pool -> total_prev_len + at ;
189
192
}
190
193
}
191
194
}
@@ -211,14 +214,14 @@ qstr qstr_from_strn(const char *str, size_t len) {
211
214
}
212
215
213
216
// compute number of bytes needed to intern this string
214
- size_t n_bytes = MICROPY_QSTR_BYTES_IN_HASH + MICROPY_QSTR_BYTES_IN_LEN + len + 1 ;
217
+ size_t n_bytes = len + 1 ;
215
218
216
219
if (MP_STATE_VM (qstr_last_chunk ) != NULL && MP_STATE_VM (qstr_last_used ) + n_bytes > MP_STATE_VM (qstr_last_alloc )) {
217
220
// not enough room at end of previously interned string so try to grow
218
- byte * new_p = m_renew_maybe (byte , MP_STATE_VM (qstr_last_chunk ), MP_STATE_VM (qstr_last_alloc ), MP_STATE_VM (qstr_last_alloc ) + n_bytes , false);
221
+ char * new_p = m_renew_maybe (char , MP_STATE_VM (qstr_last_chunk ), MP_STATE_VM (qstr_last_alloc ), MP_STATE_VM (qstr_last_alloc ) + n_bytes , false);
219
222
if (new_p == NULL ) {
220
223
// could not grow existing memory; shrink it to fit previous
221
- (void )m_renew_maybe (byte , MP_STATE_VM (qstr_last_chunk ), MP_STATE_VM (qstr_last_alloc ), MP_STATE_VM (qstr_last_used ), false);
224
+ (void )m_renew_maybe (char , MP_STATE_VM (qstr_last_chunk ), MP_STATE_VM (qstr_last_alloc ), MP_STATE_VM (qstr_last_used ), false);
222
225
MP_STATE_VM (qstr_last_chunk ) = NULL ;
223
226
} else {
224
227
// could grow existing memory
@@ -232,10 +235,10 @@ qstr qstr_from_strn(const char *str, size_t len) {
232
235
if (al < MICROPY_ALLOC_QSTR_CHUNK_INIT ) {
233
236
al = MICROPY_ALLOC_QSTR_CHUNK_INIT ;
234
237
}
235
- MP_STATE_VM (qstr_last_chunk ) = m_new_maybe (byte , al );
238
+ MP_STATE_VM (qstr_last_chunk ) = m_new_maybe (char , al );
236
239
if (MP_STATE_VM (qstr_last_chunk ) == NULL ) {
237
240
// failed to allocate a large chunk so try with exact size
238
- MP_STATE_VM (qstr_last_chunk ) = m_new_maybe (byte , n_bytes );
241
+ MP_STATE_VM (qstr_last_chunk ) = m_new_maybe (char , n_bytes );
239
242
if (MP_STATE_VM (qstr_last_chunk ) == NULL ) {
240
243
QSTR_EXIT ();
241
244
m_malloc_fail (n_bytes );
@@ -247,40 +250,38 @@ qstr qstr_from_strn(const char *str, size_t len) {
247
250
}
248
251
249
252
// allocate memory from the chunk for this new interned string's data
250
- byte * q_ptr = MP_STATE_VM (qstr_last_chunk ) + MP_STATE_VM (qstr_last_used );
253
+ char * q_ptr = MP_STATE_VM (qstr_last_chunk ) + MP_STATE_VM (qstr_last_used );
251
254
MP_STATE_VM (qstr_last_used ) += n_bytes ;
252
255
253
256
// store the interned strings' data
254
257
mp_uint_t hash = qstr_compute_hash ((const byte * )str , len );
255
- Q_SET_HASH (q_ptr , hash );
256
- Q_SET_LENGTH (q_ptr , len );
257
- memcpy (q_ptr + MICROPY_QSTR_BYTES_IN_HASH + MICROPY_QSTR_BYTES_IN_LEN , str , len );
258
- q_ptr [MICROPY_QSTR_BYTES_IN_HASH + MICROPY_QSTR_BYTES_IN_LEN + len ] = '\0' ;
259
- q = qstr_add (q_ptr );
258
+ memcpy (q_ptr , str , len );
259
+ q_ptr [len ] = '\0' ;
260
+ q = qstr_add (hash , len , q_ptr );
260
261
}
261
262
QSTR_EXIT ();
262
263
return q ;
263
264
}
264
265
265
266
mp_uint_t qstr_hash (qstr q ) {
266
- const byte * qd = find_qstr (q );
267
- return Q_GET_HASH ( qd ) ;
267
+ qstr_pool_t * pool = find_qstr (& q );
268
+ return pool -> hashes [ q ] ;
268
269
}
269
270
270
271
size_t qstr_len (qstr q ) {
271
- const byte * qd = find_qstr (q );
272
- return Q_GET_LENGTH ( qd ) ;
272
+ qstr_pool_t * pool = find_qstr (& q );
273
+ return pool -> lengths [ q ] ;
273
274
}
274
275
275
276
const char * qstr_str (qstr q ) {
276
- const byte * qd = find_qstr (q );
277
- return ( const char * ) Q_GET_DATA ( qd ) ;
277
+ qstr_pool_t * pool = find_qstr (& q );
278
+ return pool -> qstrs [ q ] ;
278
279
}
279
280
280
281
const byte * qstr_data (qstr q , size_t * len ) {
281
- const byte * qd = find_qstr (q );
282
- * len = Q_GET_LENGTH ( qd ) ;
283
- return Q_GET_DATA ( qd ) ;
282
+ qstr_pool_t * pool = find_qstr (& q );
283
+ * len = pool -> lengths [ q ] ;
284
+ return ( byte * ) pool -> qstrs [ q ] ;
284
285
}
285
286
286
287
void qstr_pool_info (size_t * n_pool , size_t * n_qstr , size_t * n_str_data_bytes , size_t * n_total_bytes ) {
@@ -292,13 +293,14 @@ void qstr_pool_info(size_t *n_pool, size_t *n_qstr, size_t *n_str_data_bytes, si
292
293
for (qstr_pool_t * pool = MP_STATE_VM (last_pool ); pool != NULL && pool != & CONST_POOL ; pool = pool -> prev ) {
293
294
* n_pool += 1 ;
294
295
* n_qstr += pool -> len ;
295
- for (const byte * * q = pool -> qstrs , * * q_top = pool -> qstrs + pool -> len ; q < q_top ; q ++ ) {
296
- * n_str_data_bytes += Q_GET_ALLOC ( * q ) ;
296
+ for (qstr_len_t * l = pool -> lengths , * l_top = pool -> lengths + pool -> len ; l < l_top ; l ++ ) {
297
+ * n_str_data_bytes += * l + 1 ;
297
298
}
298
299
#if MICROPY_ENABLE_GC
299
300
* n_total_bytes += gc_nbytes (pool ); // this counts actual bytes used in heap
300
301
#else
301
- * n_total_bytes += sizeof (qstr_pool_t ) + sizeof (qstr ) * pool -> alloc ;
302
+ * n_total_bytes += sizeof (qstr_pool_t )
303
+ + (sizeof (const char * ) + sizeof (qstr_hash_t ) + sizeof (qstr_len_t )) * pool -> alloc ;
302
304
#endif
303
305
}
304
306
* n_total_bytes += * n_str_data_bytes ;
@@ -309,8 +311,8 @@ void qstr_pool_info(size_t *n_pool, size_t *n_qstr, size_t *n_str_data_bytes, si
309
311
void qstr_dump_data (void ) {
310
312
QSTR_ENTER ();
311
313
for (qstr_pool_t * pool = MP_STATE_VM (last_pool ); pool != NULL && pool != & CONST_POOL ; pool = pool -> prev ) {
312
- for (const byte * * q = pool -> qstrs , * * q_top = pool -> qstrs + pool -> len ; q < q_top ; q ++ ) {
313
- mp_printf (& mp_plat_print , "Q(%s)\n" , Q_GET_DATA ( * q ) );
314
+ for (const char * * q = pool -> qstrs , * * q_top = pool -> qstrs + pool -> len ; q < q_top ; q ++ ) {
315
+ mp_printf (& mp_plat_print , "Q(%s)\n" , * q );
314
316
}
315
317
}
316
318
QSTR_EXIT ();
0 commit comments