MIRROR: javascript for 馃悳's, a tiny runtime with big ambitions
1#ifndef ANT_OBJECT_H
2#define ANT_OBJECT_H
3
4#include "types.h"
5#include "sugar.h"
6#include "shapes.h"
7
8#include <utarray.h>
9#include <stdbool.h>
10#include <stddef.h>
11#include <stdint.h>
12#include <stdlib.h>
13
14typedef struct {
15 ant_value_t (*getter)(ant_t *, ant_value_t, const char *, size_t);
16 bool (*setter)(ant_t *, ant_value_t, const char *, size_t, ant_value_t);
17 bool (*deleter)(ant_t *, ant_value_t, const char *, size_t);
18} ant_exotic_ops_t;
19
20typedef struct promise_handler {
21 ant_value_t onFulfilled;
22 ant_value_t onRejected;
23 ant_value_t nextPromise;
24 struct coroutine *await_coro;
25} promise_handler_t;
26
27typedef struct {
28 ant_value_t value;
29 ant_value_t trigger_parent;
30
31 struct ant_object *gc_pending_next;
32 promise_handler_t inline_handler;
33
34 UT_array *handlers;
35 uint32_t promise_id;
36 uint16_t handler_count;
37 uint8_t state;
38
39 bool trigger_queued;
40 bool has_rejection_handler;
41 bool processing;
42 bool unhandled_reported;
43 bool gc_pending_rooted;
44} ant_promise_state_t;
45
46typedef struct {
47 ant_value_t target;
48 ant_value_t handler;
49 bool revoked;
50} ant_proxy_state_t;
51
52typedef struct {
53 uint8_t slot;
54 ant_value_t value;
55} ant_extra_slot_t;
56
57typedef struct {
58 ant_value_t token;
59 ant_value_t value;
60 ant_value_t getter;
61 ant_value_t setter;
62
63 uint32_t hash;
64 uint8_t kind;
65 uint8_t occupied;
66} ant_private_entry_t;
67
68typedef struct {
69 ant_private_entry_t *entries;
70 uint32_t count;
71 uint32_t cap;
72} ant_private_table_t;
73
74typedef struct {
75 void *ptr;
76 uint32_t tag;
77} ant_native_entry_t;
78
79typedef struct {
80 ant_extra_slot_t *extra_slots;
81 ant_native_entry_t *native_entries;
82 ant_private_table_t private_table;
83 ant_proxy_state_t *proxy_state;
84
85 uint8_t native_count;
86 uint8_t native_cap;
87 uint8_t extra_count;
88 uint8_t flags;
89} ant_object_sidecar_t;
90
91_Static_assert(
92 _Alignof(ant_object_sidecar_t) > ant_sidecar,
93 "object sidecar pointer uses low-bit tag"
94);
95
96typedef struct ant_prop_ref {
97 ant_object_t *obj;
98 uint32_t slot;
99 bool valid;
100} ant_prop_ref_t;
101
102typedef struct ant_object {
103 struct ant_object *next;
104
105 ant_value_t proto;
106 ant_shape_t *shape;
107 ant_value_t *overflow_prop;
108
109 const ant_exotic_ops_t *exotic_ops;
110 ant_value_t (*exotic_keys)(ant_t *, ant_value_t);
111
112 ant_promise_state_t *promise_state;
113 ant_extra_slot_t *extra_slots;
114
115 void (*finalizer)(ant_t *, struct ant_object *);
116 ant_value_t inobj[ANT_INOBJ_MAX_SLOTS];
117 ant_native_entry_t native;
118
119 union {
120 struct { ant_value_t *data; uint32_t len; uint32_t cap; } array;
121 struct { sv_closure_t *closure; } func;
122 struct { ant_value_t value; } data;
123 } u;
124
125 uint32_t prop_count;
126 uint32_t propref_count;
127
128 uint8_t mark_epoch;
129 uint8_t type_tag;
130 uint8_t inobj_limit;
131 uint8_t extra_count;
132 uint8_t overflow_cap;
133
134 uint8_t extensible: 1;
135 uint8_t frozen: 1;
136 uint8_t sealed: 1;
137 uint8_t is_exotic: 1;
138 uint8_t is_constructor: 1;
139 uint8_t fast_array: 1;
140 uint8_t may_have_holes: 1;
141 uint8_t may_have_dense_elements: 1;
142 uint8_t gc_permanent: 1;
143 uint8_t generation: 1;
144 uint8_t in_remember_set: 1;
145} ant_object_t;
146
147static inline bool ant_object_has_sidecar(const ant_object_t *obj) {
148 return obj && (((uintptr_t)obj->extra_slots & ant_sidecar) != 0);
149}
150
151static inline ant_object_sidecar_t *ant_object_sidecar(const ant_object_t *obj) {
152 if (!ant_object_has_sidecar(obj)) return NULL;
153 return (ant_object_sidecar_t *)((uintptr_t)obj->extra_slots & ~ant_sidecar);
154}
155
156static inline ant_extra_slot_t *ant_object_extra_slots_ptr(const ant_object_t *obj) {
157 if (!obj) return NULL;
158 uintptr_t raw = (uintptr_t)obj->extra_slots;
159 if ((raw & ant_sidecar) == 0) return obj->extra_slots;
160 return ((ant_object_sidecar_t *)(raw & ~ant_sidecar))->extra_slots;
161}
162
163static inline uint8_t ant_object_extra_count(const ant_object_t *obj) {
164 if (!obj) return 0;
165 uintptr_t raw = (uintptr_t)obj->extra_slots;
166 if ((raw & ant_sidecar) == 0) return obj->extra_count;
167 return ((ant_object_sidecar_t *)(raw & ~ant_sidecar))->extra_count;
168}
169
170static inline ant_extra_slot_t *ant_object_extra_slots(const ant_object_t *obj, uint8_t *count) {
171 if (!obj) {
172 if (count) *count = 0;
173 return NULL;
174 }
175
176 uintptr_t raw = (uintptr_t)obj->extra_slots;
177 if ((raw & ant_sidecar) == 0) {
178 if (count) *count = obj->extra_count;
179 return obj->extra_slots;
180 }
181
182 ant_object_sidecar_t *sidecar = (ant_object_sidecar_t *)(raw & ~ant_sidecar);
183 if (count) *count = sidecar->extra_count;
184 return sidecar->extra_slots;
185}
186
187static inline ant_extra_slot_t *ant_object_extra_slot(const ant_object_t *obj, uint8_t slot) {
188 if (!obj) return NULL;
189
190 uint8_t count = obj->extra_count;
191 ant_extra_slot_t *entries = obj->extra_slots;
192
193 uintptr_t raw = (uintptr_t)obj->extra_slots;
194 if ((raw & ant_sidecar) != 0) {
195 ant_object_sidecar_t *sidecar = (ant_object_sidecar_t *)(raw & ~ant_sidecar);
196 count = sidecar->extra_count;
197 entries = sidecar->extra_slots;
198 }
199
200 for (uint8_t i = 0; i < count; i++)
201 if (entries[i].slot == slot) return &entries[i];
202
203 return NULL;
204}
205
206static inline ant_object_sidecar_t *ant_object_ensure_sidecar(ant_object_t *obj) {
207 if (!obj) return NULL;
208
209 ant_object_sidecar_t *sidecar = ant_object_sidecar(obj);
210 if (sidecar) return sidecar;
211
212 sidecar = (ant_object_sidecar_t *)calloc(1, sizeof(*sidecar));
213 if (!sidecar) return NULL;
214
215 sidecar->extra_slots = obj->extra_slots;
216 sidecar->extra_count = obj->extra_count;
217
218 obj->extra_slots = (ant_extra_slot_t *)((uintptr_t)sidecar | ant_sidecar);
219 obj->extra_count = 0;
220
221 return sidecar;
222}
223
224static inline ant_proxy_state_t *ant_object_proxy_state(const ant_object_t *obj) {
225 ant_object_sidecar_t *sidecar = ant_object_sidecar(obj);
226 return sidecar ? sidecar->proxy_state : NULL;
227}
228
229static inline ant_private_table_t *ant_object_private_table(const ant_object_t *obj) {
230 ant_object_sidecar_t *sidecar = ant_object_sidecar(obj);
231 return sidecar ? (ant_private_table_t *)&sidecar->private_table : NULL;
232}
233
234static inline uint32_t ant_object_inobj_limit(const ant_object_t *obj) {
235 if (!obj) return ANT_INOBJ_MAX_SLOTS;
236 uint32_t limit = obj->inobj_limit;
237 return (limit > ANT_INOBJ_MAX_SLOTS) ? ANT_INOBJ_MAX_SLOTS : limit;
238}
239
240static inline ant_value_t ant_object_prop_get_unchecked(const ant_object_t *obj, uint32_t slot) {
241 uint32_t inobj_limit = ant_object_inobj_limit(obj);
242 return (slot < inobj_limit)
243 ? obj->inobj[slot]
244 : obj->overflow_prop[slot - inobj_limit];
245}
246
247static inline void ant_object_prop_set_unchecked(ant_object_t *obj, uint32_t slot, ant_value_t value) {
248 uint32_t inobj_limit = ant_object_inobj_limit(obj);
249 if (slot < inobj_limit) obj->inobj[slot] = value;
250 else obj->overflow_prop[slot - inobj_limit] = value;
251}
252
253#endif