Skip to content

Commit 38a2da6

Browse files
committed
py: Stuff qstr in object pointer; keys for mp_map_t are now always mp_obj_t.
1 parent ea9e441 commit 38a2da6

13 files changed

Lines changed: 135 additions & 123 deletions

File tree

py/builtin.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ mp_obj_t mp_builtin___build_class__(int n_args, const mp_obj_t *args) {
2323

2424
// we differ from CPython: we set the new __locals__ object here
2525
mp_map_t *old_locals = rt_locals_get();
26-
mp_map_t *class_locals = mp_map_new(MP_MAP_QSTR, 0);
26+
mp_map_t *class_locals = mp_map_new(0);
2727
rt_locals_set(class_locals);
2828

2929
// call the class code

py/map.c

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -26,21 +26,22 @@ int get_doubling_prime_greater_or_equal_to(int x) {
2626
/******************************************************************************/
2727
/* map */
2828

29-
void mp_map_init(mp_map_t *map, mp_map_kind_t kind, int n) {
30-
map->kind = kind;
31-
map->used = 0;
29+
void mp_map_init(mp_map_t *map, int n) {
3230
map->alloc = get_doubling_prime_greater_or_equal_to(n + 1);
31+
map->used = 0;
32+
map->all_keys_are_qstrs = 1;
3333
map->table = m_new0(mp_map_elem_t, map->alloc);
3434
}
3535

36-
mp_map_t *mp_map_new(mp_map_kind_t kind, int n) {
36+
mp_map_t *mp_map_new(int n) {
3737
mp_map_t *map = m_new(mp_map_t, 1);
38-
mp_map_init(map, kind, n);
38+
mp_map_init(map, n);
3939
return map;
4040
}
4141

4242
void mp_map_clear(mp_map_t *map) {
4343
map->used = 0;
44+
map->all_keys_are_qstrs = 1;
4445
machine_uint_t a = map->alloc;
4546
map->alloc = 0;
4647
map->table = m_renew(mp_map_elem_t, map->table, a, map->alloc);
@@ -50,30 +51,26 @@ void mp_map_clear(mp_map_t *map) {
5051
}
5152
}
5253

53-
static void mp_map_rehash (mp_map_t *map) {
54+
static void mp_map_rehash(mp_map_t *map) {
5455
int old_alloc = map->alloc;
5556
mp_map_elem_t *old_table = map->table;
5657
map->alloc = get_doubling_prime_greater_or_equal_to(map->alloc + 1);
5758
map->used = 0;
59+
map->all_keys_are_qstrs = 1;
5860
map->table = m_new0(mp_map_elem_t, map->alloc);
5961
for (int i = 0; i < old_alloc; i++) {
6062
if (old_table[i].key != NULL) {
61-
mp_map_lookup_helper(map, old_table[i].key, true, false)->value = old_table[i].value;
63+
mp_map_lookup(map, old_table[i].key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = old_table[i].value;
6264
}
6365
}
6466
m_del(mp_map_elem_t, old_table, old_alloc);
6567
}
6668

67-
mp_map_elem_t* mp_map_lookup_helper(mp_map_t *map, mp_obj_t index, bool add_if_not_found, bool remove_if_found) {
68-
bool is_map_mp_obj = (map->kind == MP_MAP_OBJ);
69+
mp_map_elem_t* mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t lookup_kind) {
6970
machine_uint_t hash;
70-
if (is_map_mp_obj) {
71-
hash = mp_obj_hash(index);
72-
} else {
73-
hash = (machine_uint_t)index;
74-
}
71+
hash = mp_obj_hash(index);
7572
if (map->alloc == 0) {
76-
if (add_if_not_found) {
73+
if (lookup_kind == MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) {
7774
mp_map_rehash(map);
7875
} else {
7976
return NULL;
@@ -84,7 +81,7 @@ mp_map_elem_t* mp_map_lookup_helper(mp_map_t *map, mp_obj_t index, bool add_if_n
8481
mp_map_elem_t *elem = &map->table[pos];
8582
if (elem->key == NULL) {
8683
// not in table
87-
if (add_if_not_found) {
84+
if (lookup_kind == MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) {
8885
if (map->used + 1 >= map->alloc) {
8986
// not enough room in table, rehash it
9087
mp_map_rehash(map);
@@ -93,21 +90,24 @@ mp_map_elem_t* mp_map_lookup_helper(mp_map_t *map, mp_obj_t index, bool add_if_n
9390
} else {
9491
map->used += 1;
9592
elem->key = index;
93+
if (!MP_OBJ_IS_QSTR(index)) {
94+
map->all_keys_are_qstrs = 0;
95+
}
9696
return elem;
9797
}
9898
} else {
9999
return NULL;
100100
}
101-
} else if (elem->key == index || (is_map_mp_obj && mp_obj_equal(elem->key, index))) {
101+
} else if (elem->key == index || (!map->all_keys_are_qstrs && mp_obj_equal(elem->key, index))) {
102102
// found it
103103
/* it seems CPython does not replace the index; try x={True:'true'};x[1]='one';x
104104
if (add_if_not_found) {
105105
elem->key = index;
106106
}
107107
*/
108-
if (remove_if_found) {
108+
if (lookup_kind == MP_MAP_LOOKUP_REMOVE_IF_FOUND) {
109109
map->used--;
110-
/* this leaks this memory (but see dict_get_helper) */
110+
// this leaks this memory (but see dict_get_helper)
111111
mp_map_elem_t *retval = m_new(mp_map_elem_t, 1);
112112
retval->key = elem->key;
113113
retval->value = elem->value;
@@ -123,11 +123,6 @@ mp_map_elem_t* mp_map_lookup_helper(mp_map_t *map, mp_obj_t index, bool add_if_n
123123
}
124124
}
125125

126-
mp_map_elem_t* mp_qstr_map_lookup(mp_map_t *map, qstr index, bool add_if_not_found) {
127-
mp_obj_t o = (mp_obj_t)(machine_uint_t)index;
128-
return mp_map_lookup_helper(map, o, add_if_not_found, false);
129-
}
130-
131126
/******************************************************************************/
132127
/* set */
133128

py/map.h

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,12 @@
1-
typedef enum {
2-
MP_MAP_QSTR,
3-
MP_MAP_OBJ,
4-
} mp_map_kind_t;
5-
61
typedef struct _mp_map_elem_t {
72
mp_obj_t key;
83
mp_obj_t value;
94
} mp_map_elem_t;
105

116
typedef struct _mp_map_t {
127
struct {
13-
mp_map_kind_t kind : 1;
14-
machine_uint_t used : (8 * BYTES_PER_WORD - 1);
8+
machine_uint_t all_keys_are_qstrs : 1;
9+
machine_uint_t used : (8 * sizeof(machine_uint_t) - 1);
1510
};
1611
machine_uint_t alloc;
1712
mp_map_elem_t *table;
@@ -23,11 +18,16 @@ typedef struct _mp_set_t {
2318
mp_obj_t *table;
2419
} mp_set_t;
2520

21+
typedef enum {
22+
MP_MAP_LOOKUP,
23+
MP_MAP_LOOKUP_ADD_IF_NOT_FOUND,
24+
MP_MAP_LOOKUP_REMOVE_IF_FOUND,
25+
} mp_map_lookup_kind_t;
26+
2627
int get_doubling_prime_greater_or_equal_to(int x);
27-
void mp_map_init(mp_map_t *map, mp_map_kind_t kind, int n);
28-
mp_map_t *mp_map_new(mp_map_kind_t kind, int n);
29-
mp_map_elem_t* mp_map_lookup_helper(mp_map_t *map, mp_obj_t index, bool add_if_not_found, bool remove_if_found);
30-
mp_map_elem_t* mp_qstr_map_lookup(mp_map_t *map, qstr index, bool add_if_not_found);
28+
void mp_map_init(mp_map_t *map, int n);
29+
mp_map_t *mp_map_new(int n);
30+
mp_map_elem_t* mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t lookup_kind);
3131
void mp_map_clear(mp_map_t *map);
3232

3333
void mp_set_init(mp_set_t *set, int n);

py/obj.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
mp_obj_t mp_obj_get_type(mp_obj_t o_in) {
1717
if (MP_OBJ_IS_SMALL_INT(o_in)) {
1818
return (mp_obj_t)&int_type;
19+
} else if (MP_OBJ_IS_QSTR(o_in)) {
20+
return (mp_obj_t)&str_type;
1921
} else {
2022
mp_obj_base_t *o = o_in;
2123
return (mp_obj_t)o->type;
@@ -71,6 +73,8 @@ machine_int_t mp_obj_hash(mp_obj_t o_in) {
7173
return 1; // needs to hash to same as the integer 1, since True==1
7274
} else if (MP_OBJ_IS_SMALL_INT(o_in)) {
7375
return MP_OBJ_SMALL_INT_VALUE(o_in);
76+
} else if (MP_OBJ_IS_QSTR(o_in)) {
77+
return MP_OBJ_QSTR_VALUE(o_in);
7478
} else if (MP_OBJ_IS_TYPE(o_in, &none_type)) {
7579
return (machine_int_t)o_in;
7680
} else if (MP_OBJ_IS_TYPE(o_in, &str_type)) {
@@ -107,6 +111,8 @@ bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2) {
107111
return false;
108112
}
109113
}
114+
} else if (MP_OBJ_IS_QSTR(o1) || MP_OBJ_IS_QSTR(o2)) {
115+
return false;
110116
} else if (MP_OBJ_IS_TYPE(o1, &str_type) && MP_OBJ_IS_TYPE(o2, &str_type)) {
111117
return mp_obj_str_get(o1) == mp_obj_str_get(o2);
112118
} else {

py/obj.h

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,21 @@ typedef struct _mp_obj_base_t mp_obj_base_t;
2929

3030
#define MP_OBJ_NULL ((mp_obj_t)NULL)
3131

32-
// These macros check for small int or object, and access small int values
32+
// These macros check for small int, qstr or object, and access small int and qstr values
33+
// - xxxx...xxx1: a small int, bits 1 and above are the value
34+
// - xxxx...xx10: a qstr, bits 2 and above are the value
35+
// - xxxx...xx00: a pointer to an mp_obj_base_t
3336

34-
#define MP_OBJ_IS_OBJ(o) ((((mp_small_int_t)(o)) & 1) == 0)
3537
#define MP_OBJ_IS_SMALL_INT(o) ((((mp_small_int_t)(o)) & 1) != 0)
36-
#define MP_OBJ_IS_TYPE(o, t) (((((mp_small_int_t)(o)) & 1) == 0) && (((mp_obj_base_t*)(o))->type == (t)))
38+
#define MP_OBJ_IS_QSTR(o) ((((mp_small_int_t)(o)) & 3) == 2)
39+
#define MP_OBJ_IS_OBJ(o) ((((mp_small_int_t)(o)) & 3) == 0)
40+
#define MP_OBJ_IS_TYPE(o, t) (MP_OBJ_IS_OBJ(o) && (((mp_obj_base_t*)(o))->type == (t)))
41+
3742
#define MP_OBJ_SMALL_INT_VALUE(o) (((mp_small_int_t)(o)) >> 1)
38-
#define MP_OBJ_NEW_SMALL_INT(o) ((mp_obj_t)(((o) << 1) | 1))
43+
#define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)(((small_int) << 1) | 1))
44+
45+
#define MP_OBJ_QSTR_VALUE(o) (((mp_small_int_t)(o)) >> 2)
46+
#define MP_OBJ_NEW_QSTR(qstr) ((mp_obj_t)((((machine_uint_t)qstr) << 2) | 2))
3947

4048
// These macros are used to declare and define constant function objects
4149
// You can put "static" in front of the definitions to make them local

py/objclass.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ mp_obj_t class_call_n(mp_obj_t self_in, int n_args, const mp_obj_t *args) {
2626
mp_obj_t o = mp_obj_new_instance(self_in);
2727

2828
// look for __init__ function
29-
mp_map_elem_t *init_fn = mp_qstr_map_lookup(self->locals, MP_QSTR___init__, false);
29+
mp_map_elem_t *init_fn = mp_map_lookup(self->locals, MP_OBJ_NEW_QSTR(MP_QSTR___init__), MP_MAP_LOOKUP);
3030

3131
if (init_fn != NULL) {
3232
// call __init__ function

py/objdict.c

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ static mp_obj_t dict_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
5050
case RT_BINARY_OP_SUBSCR:
5151
{
5252
// dict load
53-
mp_map_elem_t *elem = mp_map_lookup_helper(&o->map, rhs_in, false, false);
53+
mp_map_elem_t *elem = mp_map_lookup(&o->map, rhs_in, MP_MAP_LOOKUP);
5454
if (elem == NULL) {
5555
nlr_jump(mp_obj_new_exception_msg(MP_QSTR_KeyError, "<value>"));
5656
} else {
@@ -139,12 +139,12 @@ static mp_obj_t dict_copy(mp_obj_t self_in) {
139139
}
140140
static MP_DEFINE_CONST_FUN_OBJ_1(dict_copy_obj, dict_copy);
141141

142-
static mp_obj_t dict_get_helper(mp_map_t *self, mp_obj_t key, mp_obj_t deflt, bool pop, bool set) {
143-
mp_map_elem_t *elem = mp_map_lookup_helper(self, key, set, pop);
142+
static mp_obj_t dict_get_helper(mp_map_t *self, mp_obj_t key, mp_obj_t deflt, mp_map_lookup_kind_t lookup_kind) {
143+
mp_map_elem_t *elem = mp_map_lookup(self, key, lookup_kind);
144144
mp_obj_t value;
145145
if (elem == NULL || elem->value == NULL) {
146146
if (deflt == NULL) {
147-
if (pop) {
147+
if (lookup_kind == MP_MAP_LOOKUP_REMOVE_IF_FOUND) {
148148
nlr_jump(mp_obj_new_exception_msg(MP_QSTR_KeyError, "<value>"));
149149
} else {
150150
value = mp_const_none;
@@ -154,12 +154,12 @@ static mp_obj_t dict_get_helper(mp_map_t *self, mp_obj_t key, mp_obj_t deflt, bo
154154
}
155155
} else {
156156
value = elem->value;
157-
if (pop) {
158-
/* catch the leak (from mp_map_lookup_helper) */
157+
if (lookup_kind == MP_MAP_LOOKUP_REMOVE_IF_FOUND) {
158+
// catch the leak (from mp_map_lookup)
159159
m_free(elem, sizeof(mp_map_elem_t));
160160
}
161161
}
162-
if (set) {
162+
if (lookup_kind == MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) {
163163
elem->value = value;
164164
}
165165
return value;
@@ -172,7 +172,7 @@ static mp_obj_t dict_get(int n_args, const mp_obj_t *args) {
172172
return dict_get_helper(&((mp_obj_dict_t *)args[0])->map,
173173
args[1],
174174
n_args == 3 ? args[2] : NULL,
175-
false, false);
175+
MP_MAP_LOOKUP);
176176
}
177177
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(dict_get_obj, 2, 3, dict_get);
178178

@@ -183,7 +183,7 @@ static mp_obj_t dict_pop(int n_args, const mp_obj_t *args) {
183183
return dict_get_helper(&((mp_obj_dict_t *)args[0])->map,
184184
args[1],
185185
n_args == 3 ? args[2] : NULL,
186-
true, false);
186+
MP_MAP_LOOKUP_REMOVE_IF_FOUND);
187187
}
188188
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(dict_pop_obj, 2, 3, dict_pop);
189189

@@ -195,7 +195,7 @@ static mp_obj_t dict_setdefault(int n_args, const mp_obj_t *args) {
195195
return dict_get_helper(&((mp_obj_dict_t *)args[0])->map,
196196
args[1],
197197
n_args == 3 ? args[2] : NULL,
198-
false, true);
198+
MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
199199
}
200200
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(dict_setdefault_obj, 2, 3, dict_setdefault);
201201

@@ -237,7 +237,7 @@ static mp_obj_t dict_update(mp_obj_t self_in, mp_obj_t iterable) {
237237
MP_QSTR_ValueError,
238238
"dictionary update sequence has the wrong length"));
239239
} else {
240-
mp_map_lookup_helper(&self->map, key, true, false)->value = value;
240+
mp_map_lookup(&self->map, key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;
241241
}
242242
}
243243

@@ -273,7 +273,7 @@ const mp_obj_type_t dict_type = {
273273
mp_obj_t mp_obj_new_dict(int n_args) {
274274
mp_obj_dict_t *o = m_new_obj(mp_obj_dict_t);
275275
o->base.type = &dict_type;
276-
mp_map_init(&o->map, MP_MAP_OBJ, n_args);
276+
mp_map_init(&o->map, n_args);
277277
return o;
278278
}
279279

@@ -284,6 +284,6 @@ uint mp_obj_dict_len(mp_obj_t self_in) {
284284
mp_obj_t mp_obj_dict_store(mp_obj_t self_in, mp_obj_t key, mp_obj_t value) {
285285
assert(MP_OBJ_IS_TYPE(self_in, &dict_type));
286286
mp_obj_dict_t *self = self_in;
287-
mp_map_lookup_helper(&self->map, key, true, false)->value = value;
287+
mp_map_lookup(&self->map, key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;
288288
return self_in;
289289
}

py/objfun.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,13 +81,13 @@ mp_obj_t fun_native_call_n_kw(mp_obj_t self_in, int n_args, int n_kw, const mp_o
8181
}
8282

8383
mp_obj_t *vargs = mp_obj_new_tuple_reverse(n_args, args + 2*n_kw);
84-
mp_map_t *kw_args = mp_map_new(MP_MAP_QSTR, n_kw);
84+
mp_map_t *kw_args = mp_map_new(n_kw);
8585
for (int i = 0; i < 2*n_kw; i+=2) {
8686
qstr name = mp_obj_str_get(args[i+1]);
87-
mp_qstr_map_lookup(kw_args, name, true)->value = args[i];
87+
mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(name), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = args[i];
8888
}
8989
mp_obj_t res = ((mp_fun_kw_t)self->fun)(vargs, kw_args);
90-
/* TODO clean up vargs and kw_args */
90+
// TODO clean up vargs and kw_args
9191
return res;
9292
}
9393

py/objinstance.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,12 @@ type needs to be specified dynamically
3030
mp_obj_t mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr) {
3131
// logic: look in obj members then class locals (TODO check this against CPython)
3232
mp_obj_instance_t *self = self_in;
33-
mp_map_elem_t *elem = mp_qstr_map_lookup(self->members, attr, false);
33+
mp_map_elem_t *elem = mp_map_lookup(self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP);
3434
if (elem != NULL) {
3535
// object member, always treated as a value
3636
return elem->value;
3737
}
38-
elem = mp_qstr_map_lookup(mp_obj_class_get_locals(self->class), attr, false);
38+
elem = mp_map_lookup(mp_obj_class_get_locals(self->class), MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP);
3939
if (elem != NULL) {
4040
if (mp_obj_is_callable(elem->value)) {
4141
// class member is callable so build a bound method
@@ -51,14 +51,14 @@ mp_obj_t mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr) {
5151
void mp_obj_instance_load_method(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
5252
// logic: look in obj members then class locals (TODO check this against CPython)
5353
mp_obj_instance_t *self = self_in;
54-
mp_map_elem_t *elem = mp_qstr_map_lookup(self->members, attr, false);
54+
mp_map_elem_t *elem = mp_map_lookup(self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP);
5555
if (elem != NULL) {
5656
// object member, always treated as a value
5757
dest[1] = elem->value;
5858
dest[0] = NULL;
5959
return;
6060
}
61-
elem = mp_qstr_map_lookup(mp_obj_class_get_locals(self->class), attr, false);
61+
elem = mp_map_lookup(mp_obj_class_get_locals(self->class), MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP);
6262
if (elem != NULL) {
6363
if (mp_obj_is_callable(elem->value)) {
6464
// class member is callable so build a bound method
@@ -81,11 +81,11 @@ void mp_obj_instance_load_method(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
8181
void mp_obj_instance_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) {
8282
// logic: look in class locals (no add) then obj members (add) (TODO check this against CPython)
8383
mp_obj_instance_t *self = self_in;
84-
mp_map_elem_t *elem = mp_qstr_map_lookup(mp_obj_class_get_locals(self->class), attr, false);
84+
mp_map_elem_t *elem = mp_map_lookup(mp_obj_class_get_locals(self->class), MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP);
8585
if (elem != NULL) {
8686
elem->value = value;
8787
} else {
88-
mp_qstr_map_lookup(self->members, attr, true)->value = value;
88+
mp_map_lookup(self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;
8989
}
9090
}
9191

@@ -98,6 +98,6 @@ mp_obj_t mp_obj_new_instance(mp_obj_t class) {
9898
mp_obj_instance_t *o = m_new_obj(mp_obj_instance_t);
9999
o->base.type = &instance_type;
100100
o->class = class;
101-
o->members = mp_map_new(MP_MAP_QSTR, 0);
101+
o->members = mp_map_new(0);
102102
return o;
103103
}

0 commit comments

Comments
 (0)