49
49
PROXY_KIND_MP_GENERATOR = 7 ,
50
50
PROXY_KIND_MP_OBJECT = 8 ,
51
51
PROXY_KIND_MP_JSPROXY = 9 ,
52
+ PROXY_KIND_MP_EXISTING = 10 ,
52
53
};
53
54
54
55
enum {
@@ -79,40 +80,76 @@ static size_t proxy_c_ref_next;
79
80
80
81
void proxy_c_init (void ) {
81
82
MP_STATE_PORT (proxy_c_ref ) = mp_obj_new_list (0 , NULL );
83
+ MP_STATE_PORT (proxy_c_dict ) = mp_obj_new_dict (0 );
82
84
mp_obj_list_append (MP_STATE_PORT (proxy_c_ref ), MP_OBJ_NULL );
83
85
proxy_c_ref_next = PROXY_C_REF_NUM_STATIC ;
84
86
}
85
87
86
88
MP_REGISTER_ROOT_POINTER (mp_obj_t proxy_c_ref );
89
+ MP_REGISTER_ROOT_POINTER (mp_obj_t proxy_c_dict );
87
90
88
91
// obj cannot be MP_OBJ_NULL.
89
92
static inline size_t proxy_c_add_obj (mp_obj_t obj ) {
90
93
// Search for the first free slot in proxy_c_ref.
94
+ size_t id = 0 ;
91
95
mp_obj_list_t * l = (mp_obj_list_t * )MP_OBJ_TO_PTR (MP_STATE_PORT (proxy_c_ref ));
92
96
while (proxy_c_ref_next < l -> len ) {
93
97
if (l -> items [proxy_c_ref_next ] == MP_OBJ_NULL ) {
94
98
// Free slot found, reuse it.
95
- size_t id = proxy_c_ref_next ;
99
+ id = proxy_c_ref_next ;
96
100
++ proxy_c_ref_next ;
97
101
l -> items [id ] = obj ;
98
- return id ;
102
+ break ;
99
103
}
100
104
++ proxy_c_ref_next ;
101
105
}
102
106
103
- // No free slots, so grow proxy_c_ref by one (append at the end of the list).
104
- size_t id = l -> len ;
105
- mp_obj_list_append (MP_STATE_PORT (proxy_c_ref ), obj );
106
- proxy_c_ref_next = l -> len ;
107
+ if (id == 0 ) {
108
+ // No free slots, so grow proxy_c_ref by one (append at the end of the list).
109
+ id = l -> len ;
110
+ mp_obj_list_append (MP_STATE_PORT (proxy_c_ref ), obj );
111
+ proxy_c_ref_next = l -> len ;
112
+ }
113
+
114
+ // Add the object to proxy_c_dict, keyed by the object pointer, with value the object id.
115
+ mp_obj_t obj_key = mp_obj_new_int_from_uint ((uintptr_t )obj );
116
+ mp_map_elem_t * elem = mp_map_lookup (mp_obj_dict_get_map (MP_STATE_PORT (proxy_c_dict )), obj_key , MP_MAP_LOOKUP_ADD_IF_NOT_FOUND );
117
+ elem -> value = mp_obj_new_int_from_uint (id );
118
+
107
119
return id ;
108
120
}
109
121
122
+ EM_JS (int , js_check_existing , (int c_ref ), {
123
+ return proxy_js_check_existing (c_ref );
124
+ });
125
+
126
+ // obj cannot be MP_OBJ_NULL.
127
+ static inline int proxy_c_check_existing (mp_obj_t obj ) {
128
+ mp_obj_t obj_key = mp_obj_new_int_from_uint ((uintptr_t )obj );
129
+ mp_map_elem_t * elem = mp_map_lookup (mp_obj_dict_get_map (MP_STATE_PORT (proxy_c_dict )), obj_key , MP_MAP_LOOKUP );
130
+ if (elem == NULL ) {
131
+ return -1 ;
132
+ }
133
+ uint32_t c_ref = mp_obj_int_get_truncated (elem -> value );
134
+ return js_check_existing (c_ref );
135
+ }
136
+
110
137
static inline mp_obj_t proxy_c_get_obj (uint32_t c_ref ) {
111
138
return ((mp_obj_list_t * )MP_OBJ_TO_PTR (MP_STATE_PORT (proxy_c_ref )))-> items [c_ref ];
112
139
}
113
140
114
141
void proxy_c_free_obj (uint32_t c_ref ) {
115
142
if (c_ref >= PROXY_C_REF_NUM_STATIC ) {
143
+ // Remove the object from proxy_c_dict if the c_ref in that dict corresponds to this object.
144
+ // (It may be that this object exists in the dict but with a different c_ref from a more
145
+ // recent proxy of this object.)
146
+ mp_obj_t obj_key = mp_obj_new_int_from_uint ((uintptr_t )proxy_c_get_obj (c_ref ));
147
+ mp_map_elem_t * elem = mp_map_lookup (mp_obj_dict_get_map (MP_STATE_PORT (proxy_c_dict )), obj_key , MP_MAP_LOOKUP );
148
+ if (elem != NULL && mp_obj_int_get_truncated (elem -> value ) == c_ref ) {
149
+ mp_map_lookup (mp_obj_dict_get_map (MP_STATE_PORT (proxy_c_dict )), obj_key , MP_MAP_LOOKUP_REMOVE_IF_FOUND );
150
+ }
151
+
152
+ // Clear the slot in proxy_c_ref used by this object, so the GC can reclaim the object.
116
153
((mp_obj_list_t * )MP_OBJ_TO_PTR (MP_STATE_PORT (proxy_c_ref )))-> items [c_ref ] = MP_OBJ_NULL ;
117
154
proxy_c_ref_next = MIN (proxy_c_ref_next , c_ref );
118
155
}
@@ -143,6 +180,7 @@ mp_obj_t proxy_convert_js_to_mp_obj_cside(uint32_t *value) {
143
180
144
181
void proxy_convert_mp_to_js_obj_cside (mp_obj_t obj , uint32_t * out ) {
145
182
uint32_t kind ;
183
+ int js_ref ;
146
184
if (obj == MP_OBJ_NULL ) {
147
185
kind = PROXY_KIND_MP_NULL ;
148
186
} else if (obj == mp_const_none ) {
@@ -168,6 +206,9 @@ void proxy_convert_mp_to_js_obj_cside(mp_obj_t obj, uint32_t *out) {
168
206
} else if (mp_obj_is_jsproxy (obj )) {
169
207
kind = PROXY_KIND_MP_JSPROXY ;
170
208
out [1 ] = mp_obj_jsproxy_get_ref (obj );
209
+ } else if ((js_ref = proxy_c_check_existing (obj )) >= 0 ) {
210
+ kind = PROXY_KIND_MP_EXISTING ;
211
+ out [1 ] = js_ref ;
171
212
} else if (mp_obj_get_type (obj ) == & mp_type_JsException ) {
172
213
mp_obj_exception_t * exc = MP_OBJ_TO_PTR (obj );
173
214
if (exc -> args -> len > 0 && mp_obj_is_jsproxy (exc -> args -> items [0 ])) {
0 commit comments