37
37
38
38
// NOTE: we are using linear arrays to store and search for qstr's (unique strings, interned strings)
39
39
// ultimately we will replace this with a static hash table of some kind
40
- // also probably need to include the length in the string data, to allow null bytes in the string
41
40
42
41
#if MICROPY_DEBUG_VERBOSE // print debugging info
43
42
#define DEBUG_printf DEBUG_printf
46
45
#endif
47
46
48
47
// A qstr is an index into the qstr pool.
49
- // The data for a qstr contains (hash, length, data):
50
- // - hash (configurable number of bytes)
51
- // - length (configurable number of bytes)
52
- // - data ("length" number of bytes)
53
- // - \0 terminated (so they can be printed using printf)
54
-
55
- #if MICROPY_QSTR_BYTES_IN_HASH == 1
56
- #define Q_HASH_MASK (0xff)
57
- #define Q_GET_HASH (q ) ((mp_uint_t)(q)[0])
58
- #define Q_SET_HASH (q , hash ) do { (q)[0] = (hash); } while (0)
59
- #elif MICROPY_QSTR_BYTES_IN_HASH == 2
60
- #define Q_HASH_MASK (0xffff)
61
- #define Q_GET_HASH (q ) ((mp_uint_t)(q)[0] | ((mp_uint_t)(q)[1] << 8))
62
- #define Q_SET_HASH (q , hash ) do { (q)[0] = (hash); (q)[1] = (hash) >> 8; } while (0)
63
- #else
64
- #error unimplemented qstr hash decoding
65
- #endif
66
- #define Q_GET_ALLOC (q ) (MICROPY_QSTR_BYTES_IN_HASH + MICROPY_QSTR_BYTES_IN_LEN + Q_GET_LENGTH(q) + 1)
67
- #define Q_GET_DATA (q ) ((q) + MICROPY_QSTR_BYTES_IN_HASH + MICROPY_QSTR_BYTES_IN_LEN)
68
- #if MICROPY_QSTR_BYTES_IN_LEN == 1
69
- #define Q_GET_LENGTH (q ) ((q)[MICROPY_QSTR_BYTES_IN_HASH])
70
- #define Q_SET_LENGTH (q , len ) do { (q)[MICROPY_QSTR_BYTES_IN_HASH] = (len); } while (0)
71
- #elif MICROPY_QSTR_BYTES_IN_LEN == 2
72
- #define Q_GET_LENGTH (q ) ((q)[MICROPY_QSTR_BYTES_IN_HASH] | ((q)[MICROPY_QSTR_BYTES_IN_HASH + 1] << 8))
73
- #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)
74
- #else
75
- #error unimplemented qstr length decoding
76
- #endif
48
+ // The data for a qstr is \0 terminated (so they can be printed using printf)
49
+
50
+ #define Q_HASH_MASK ((1 << (8 * MICROPY_QSTR_BYTES_IN_HASH)) - 1)
77
51
78
52
#if MICROPY_PY_THREAD && !MICROPY_PY_THREAD_GIL
79
53
#define QSTR_ENTER () mp_thread_mutex_lock(&MP_STATE_VM(qstr_mutex), 1)
@@ -98,14 +72,25 @@ mp_uint_t qstr_compute_hash(const byte *data, size_t len) {
98
72
return hash ;
99
73
}
100
74
75
+ const qstr_attr_t mp_qstr_const_attr [] = {
76
+ #ifndef NO_QSTR
77
+ #define QDEF (id , hash , len , str ) { hash , len },
78
+ #define TRANSLATION (id , length , compressed ...)
79
+ #include "genhdr/qstrdefs.generated.h"
80
+ #undef TRANSLATION
81
+ #undef QDEF
82
+ #endif
83
+ };
84
+
101
85
const qstr_pool_t mp_qstr_const_pool = {
102
86
NULL , // no previous pool
103
87
0 , // no previous pool
104
88
10 , // set so that the first dynamically allocated pool is twice this size; must be <= the len (just below)
105
89
MP_QSTRnumber_of , // corresponds to number of strings in array just below
90
+ (qstr_attr_t * )mp_qstr_const_attr ,
106
91
{
107
92
#ifndef NO_QSTR
108
- #define QDEF (id , str ) str ,
93
+ #define QDEF (id , hash , len , str ) str ,
109
94
#define TRANSLATION (id , length , compressed ...)
110
95
#include "genhdr/qstrdefs.generated.h"
111
96
#undef TRANSLATION
@@ -130,32 +115,37 @@ void qstr_init(void) {
130
115
#endif
131
116
}
132
117
133
- STATIC const byte * find_qstr (qstr q ) {
118
+ STATIC const char * find_qstr (qstr q , qstr_attr_t * attr ) {
134
119
// search pool for this qstr
135
120
// total_prev_len==0 in the final pool, so the loop will always terminate
136
121
qstr_pool_t * pool = MP_STATE_VM (last_pool );
137
122
while (q < pool -> total_prev_len ) {
138
123
pool = pool -> prev ;
139
124
}
140
- assert (q - pool -> total_prev_len < pool -> len );
141
- return pool -> qstrs [q - pool -> total_prev_len ];
125
+ q -= pool -> total_prev_len ;
126
+ assert (q < pool -> len );
127
+ * attr = pool -> attrs [q ];
128
+ return pool -> qstrs [q ];
142
129
}
143
130
144
131
// qstr_mutex must be taken while in this function
145
- STATIC qstr qstr_add (const byte * q_ptr ) {
146
- 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 ) );
132
+ STATIC qstr qstr_add (mp_uint_t hash , mp_uint_t len , const char * q_ptr ) {
133
+ DEBUG_printf ("QSTR: add hash=%d len=%d data=%.*s\n" , hash , len , len , q_ptr );
147
134
148
135
// make sure we have room in the pool for a new qstr
149
136
if (MP_STATE_VM (last_pool )-> len >= MP_STATE_VM (last_pool )-> alloc ) {
150
137
uint32_t new_pool_length = MP_STATE_VM (last_pool )-> alloc * 2 ;
151
138
if (new_pool_length > MICROPY_QSTR_POOL_MAX_ENTRIES ) {
152
139
new_pool_length = MICROPY_QSTR_POOL_MAX_ENTRIES ;
153
140
}
154
- qstr_pool_t * pool = m_new_ll_obj_var_maybe (qstr_pool_t , const char * , new_pool_length );
155
- if (pool == NULL ) {
141
+ mp_uint_t pool_size = sizeof (qstr_pool_t ) + sizeof (const char * ) * new_pool_length ;
142
+ void * chunk = m_malloc_maybe (pool_size + sizeof (qstr_attr_t ) * new_pool_length , true);
143
+ if (chunk == NULL ) {
156
144
QSTR_EXIT ();
157
145
m_malloc_fail (new_pool_length );
158
146
}
147
+ qstr_pool_t * pool = (qstr_pool_t * )chunk ;
148
+ pool -> attrs = (qstr_attr_t * )(void * )((char * )chunk + pool_size );
159
149
pool -> prev = MP_STATE_VM (last_pool );
160
150
pool -> total_prev_len = MP_STATE_VM (last_pool )-> total_prev_len + MP_STATE_VM (last_pool )-> len ;
161
151
pool -> alloc = new_pool_length ;
@@ -165,10 +155,14 @@ STATIC qstr qstr_add(const byte *q_ptr) {
165
155
}
166
156
167
157
// add the new qstr
168
- MP_STATE_VM (last_pool )-> qstrs [MP_STATE_VM (last_pool )-> len ++ ] = q_ptr ;
158
+ mp_uint_t at = MP_STATE_VM (last_pool )-> len ;
159
+ MP_STATE_VM (last_pool )-> attrs [at ].hash = hash ;
160
+ MP_STATE_VM (last_pool )-> attrs [at ].len = len ;
161
+ MP_STATE_VM (last_pool )-> qstrs [at ] = q_ptr ;
162
+ MP_STATE_VM (last_pool )-> len ++ ;
169
163
170
164
// return id for the newly-added qstr
171
- return MP_STATE_VM (last_pool )-> total_prev_len + MP_STATE_VM ( last_pool ) -> len - 1 ;
165
+ return MP_STATE_VM (last_pool )-> total_prev_len + at ;
172
166
}
173
167
174
168
qstr qstr_find_strn (const char * str , size_t str_len ) {
@@ -177,9 +171,10 @@ qstr qstr_find_strn(const char *str, size_t str_len) {
177
171
178
172
// search pools for the data
179
173
for (qstr_pool_t * pool = MP_STATE_VM (last_pool ); pool != NULL ; pool = pool -> prev ) {
180
- for (const byte * * q = pool -> qstrs , * * q_top = pool -> qstrs + pool -> len ; q < q_top ; q ++ ) {
181
- if (Q_GET_HASH (* q ) == str_hash && Q_GET_LENGTH (* q ) == str_len && memcmp (Q_GET_DATA (* q ), str , str_len ) == 0 ) {
182
- return pool -> total_prev_len + (q - pool -> qstrs );
174
+ qstr_attr_t * attrs = pool -> attrs ;
175
+ for (mp_uint_t at = 0 , top = pool -> len ; at < top ; at ++ ) {
176
+ if (attrs [at ].hash == str_hash && attrs [at ].len == str_len && memcmp (pool -> qstrs [at ], str , str_len ) == 0 ) {
177
+ return pool -> total_prev_len + at ;
183
178
}
184
179
}
185
180
}
@@ -200,14 +195,14 @@ qstr qstr_from_strn(const char *str, size_t len) {
200
195
// qstr does not exist in interned pool so need to add it
201
196
202
197
// compute number of bytes needed to intern this string
203
- size_t n_bytes = MICROPY_QSTR_BYTES_IN_HASH + MICROPY_QSTR_BYTES_IN_LEN + len + 1 ;
198
+ size_t n_bytes = len + 1 ;
204
199
205
200
if (MP_STATE_VM (qstr_last_chunk ) != NULL && MP_STATE_VM (qstr_last_used ) + n_bytes > MP_STATE_VM (qstr_last_alloc )) {
206
201
// not enough room at end of previously interned string so try to grow
207
- 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);
202
+ 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);
208
203
if (new_p == NULL ) {
209
204
// could not grow existing memory; shrink it to fit previous
210
- (void )m_renew_maybe (byte , MP_STATE_VM (qstr_last_chunk ), MP_STATE_VM (qstr_last_alloc ), MP_STATE_VM (qstr_last_used ), false);
205
+ (void )m_renew_maybe (char , MP_STATE_VM (qstr_last_chunk ), MP_STATE_VM (qstr_last_alloc ), MP_STATE_VM (qstr_last_used ), false);
211
206
MP_STATE_VM (qstr_last_chunk ) = NULL ;
212
207
} else {
213
208
// could grow existing memory
@@ -221,10 +216,10 @@ qstr qstr_from_strn(const char *str, size_t len) {
221
216
if (al < MICROPY_ALLOC_QSTR_CHUNK_INIT ) {
222
217
al = MICROPY_ALLOC_QSTR_CHUNK_INIT ;
223
218
}
224
- MP_STATE_VM (qstr_last_chunk ) = m_new_ll_maybe (byte , al );
219
+ MP_STATE_VM (qstr_last_chunk ) = m_new_ll_maybe (char , al );
225
220
if (MP_STATE_VM (qstr_last_chunk ) == NULL ) {
226
221
// failed to allocate a large chunk so try with exact size
227
- MP_STATE_VM (qstr_last_chunk ) = m_new_ll_maybe (byte , n_bytes );
222
+ MP_STATE_VM (qstr_last_chunk ) = m_new_ll_maybe (char , n_bytes );
228
223
if (MP_STATE_VM (qstr_last_chunk ) == NULL ) {
229
224
QSTR_EXIT ();
230
225
m_malloc_fail (n_bytes );
@@ -236,39 +231,41 @@ qstr qstr_from_strn(const char *str, size_t len) {
236
231
}
237
232
238
233
// allocate memory from the chunk for this new interned string's data
239
- byte * q_ptr = MP_STATE_VM (qstr_last_chunk ) + MP_STATE_VM (qstr_last_used );
234
+ char * q_ptr = MP_STATE_VM (qstr_last_chunk ) + MP_STATE_VM (qstr_last_used );
240
235
MP_STATE_VM (qstr_last_used ) += n_bytes ;
241
236
242
237
// store the interned strings' data
243
238
mp_uint_t hash = qstr_compute_hash ((const byte * )str , len );
244
- Q_SET_HASH (q_ptr , hash );
245
- Q_SET_LENGTH (q_ptr , len );
246
- memcpy (q_ptr + MICROPY_QSTR_BYTES_IN_HASH + MICROPY_QSTR_BYTES_IN_LEN , str , len );
247
- q_ptr [MICROPY_QSTR_BYTES_IN_HASH + MICROPY_QSTR_BYTES_IN_LEN + len ] = '\0' ;
248
- q = qstr_add (q_ptr );
239
+ memcpy (q_ptr , str , len );
240
+ q_ptr [len ] = '\0' ;
241
+ q = qstr_add (hash , len , q_ptr );
249
242
}
250
243
QSTR_EXIT ();
251
244
return q ;
252
245
}
253
246
254
247
mp_uint_t PLACE_IN_ITCM (qstr_hash )(qstr q ) {
255
- return Q_GET_HASH (find_qstr (q ));
248
+ qstr_attr_t attr ;
249
+ find_qstr (q , & attr );
250
+ return attr .hash ;
256
251
}
257
252
258
253
size_t qstr_len (qstr q ) {
259
- const byte * qd = find_qstr (q );
260
- return Q_GET_LENGTH (qd );
254
+ qstr_attr_t attr ;
255
+ find_qstr (q , & attr );
256
+ return attr .len ;
261
257
}
262
258
263
259
const char * qstr_str (qstr q ) {
264
- const byte * qd = find_qstr ( q ) ;
265
- return ( const char * ) Q_GET_DATA ( qd );
260
+ qstr_attr_t attr ;
261
+ return find_qstr ( q , & attr );
266
262
}
267
263
268
264
const byte * qstr_data (qstr q , size_t * len ) {
269
- const byte * qd = find_qstr (q );
270
- * len = Q_GET_LENGTH (qd );
271
- return Q_GET_DATA (qd );
265
+ qstr_attr_t attr ;
266
+ const char * qd = find_qstr (q , & attr );
267
+ * len = attr .len ;
268
+ return (byte * )qd ;
272
269
}
273
270
274
271
void qstr_pool_info (size_t * n_pool , size_t * n_qstr , size_t * n_str_data_bytes , size_t * n_total_bytes ) {
@@ -280,13 +277,14 @@ void qstr_pool_info(size_t *n_pool, size_t *n_qstr, size_t *n_str_data_bytes, si
280
277
for (qstr_pool_t * pool = MP_STATE_VM (last_pool ); pool != NULL && pool != & CONST_POOL ; pool = pool -> prev ) {
281
278
* n_pool += 1 ;
282
279
* n_qstr += pool -> len ;
283
- for (const byte * * q = pool -> qstrs , * * q_top = pool -> qstrs + pool -> len ; q < q_top ; q ++ ) {
284
- * n_str_data_bytes += Q_GET_ALLOC (* q );
280
+ for (const qstr_attr_t * q = pool -> attrs , * q_top = pool -> attrs + pool -> len ; q < q_top ; q ++ ) {
281
+ * n_str_data_bytes += sizeof (* q ) + q -> len + 1 ;
285
282
}
286
283
#if MICROPY_ENABLE_GC
287
- * n_total_bytes += gc_nbytes (pool ); // this counts actual bytes used in heap
284
+ // this counts actual bytes used in heap
285
+ * n_total_bytes += gc_nbytes (pool ) - sizeof (qstr_attr_t ) * pool -> alloc ;
288
286
#else
289
- * n_total_bytes += sizeof (qstr_pool_t ) + sizeof (qstr ) * pool -> alloc ;
287
+ * n_total_bytes += sizeof (qstr_pool_t ) + sizeof (const char * ) * pool -> alloc ;
290
288
#endif
291
289
}
292
290
* n_total_bytes += * n_str_data_bytes ;
@@ -297,8 +295,8 @@ void qstr_pool_info(size_t *n_pool, size_t *n_qstr, size_t *n_str_data_bytes, si
297
295
void qstr_dump_data (void ) {
298
296
QSTR_ENTER ();
299
297
for (qstr_pool_t * pool = MP_STATE_VM (last_pool ); pool != NULL && pool != & CONST_POOL ; pool = pool -> prev ) {
300
- for (const byte * * q = pool -> qstrs , * * q_top = pool -> qstrs + pool -> len ; q < q_top ; q ++ ) {
301
- mp_printf (& mp_plat_print , "Q(%s)\n" , Q_GET_DATA ( * q ) );
298
+ for (const char * * q = pool -> qstrs , * * q_top = pool -> qstrs + pool -> len ; q < q_top ; q ++ ) {
299
+ mp_printf (& mp_plat_print , "Q(%s)\n" , * q );
302
300
}
303
301
}
304
302
QSTR_EXIT ();
0 commit comments