MIRROR: javascript for 馃悳's, a tiny runtime with big ambitions
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at master 416 lines 14 kB view raw
1#include "gc.h" 2#include "utils.h" 3#include "shapes.h" 4#include "internal.h" 5#include "descriptors.h" 6#include "silver/engine.h" 7 8#include <assert.h> 9#include <string.h> 10 11descriptor_entry_t *desc_registry = NULL; 12 13static descriptor_entry_t arr_length_desc = { 14 .key = 0, 15 .obj_off = 0, 16 .prop_name = "length", 17 .prop_len = 6, 18 .writable = true, 19 .enumerable = false, 20 .configurable = false, 21 .has_getter = false, 22 .has_setter = false, 23 .getter = 0, 24 .setter = 0, 25}; 26 27static inline bool is_canonical_desc_obj(ant_value_t obj) { 28 return vtype(obj) == T_OBJ; 29} 30 31static inline bool is_exotic_desc_obj(ant_value_t obj) { 32 ant_object_t *ptr = js_obj_ptr(obj); 33 return ptr && ptr->is_exotic; 34} 35 36static inline bool desc_registry_allowed(ant_value_t obj) { 37 if (is_exotic_desc_obj(obj)) return true; 38#ifndef NDEBUG 39 assert(false && "desc_registry is exotic-only; ordinary objects must use shape metadata"); 40#endif 41 return false; 42} 43 44static bool ensure_added_shape_slot_storage(ant_object_t *ptr, uint32_t slot) { 45 if (!ptr || !ptr->shape) return false; 46 if (!js_obj_ensure_prop_capacity(ptr, ant_shape_count(ptr->shape))) return false; 47 if (slot >= ptr->prop_count && !js_obj_ensure_prop_capacity(ptr, slot + 1)) return false; 48 49 return true; 50} 51 52static inline uint8_t attrs_from_flags(int flags, bool include_writable) { 53 uint8_t attrs = 0; 54 if (include_writable && (flags & JS_DESC_W)) attrs |= ANT_PROP_ATTR_WRITABLE; 55 if (flags & JS_DESC_E) attrs |= ANT_PROP_ATTR_ENUMERABLE; 56 if (flags & JS_DESC_C) attrs |= ANT_PROP_ATTR_CONFIGURABLE; 57 return attrs; 58} 59 60uint64_t make_desc_key(ant_value_t obj, const char *key, size_t klen) { 61 assert(is_canonical_desc_obj(obj) && "descriptor APIs require canonical js_as_obj(...) value"); 62 if (!is_canonical_desc_obj(obj)) return hash_key(key, klen); 63 uintptr_t obj_off = (uintptr_t)vdata(obj); 64 uint64_t key_hash = hash_key(key, klen); 65 uint64_t h = (uint64_t)obj_off ^ ((uint64_t)obj_off >> 33); 66 h ^= key_hash + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2); 67 return h; 68} 69 70uint64_t make_sym_desc_key(ant_value_t obj, ant_offset_t sym_off) { 71 assert(is_canonical_desc_obj(obj) && "descriptor APIs require canonical js_as_obj(...) value"); 72 if (!is_canonical_desc_obj(obj)) return ((uint64_t)sym_off << 1) | 1u; 73 uintptr_t obj_off = (uintptr_t)vdata(obj); 74 uint64_t h = (uint64_t)obj_off ^ ((uint64_t)obj_off >> 33); 75 h ^= ((uint64_t)sym_off << 1) | 1u; 76 h += 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2); 77 return h; 78} 79 80static descriptor_entry_t *registry_lookup_desc(ant_value_t obj, const char *key, size_t klen) { 81 descriptor_entry_t *entry = NULL; 82 uint64_t desc_key = make_desc_key(obj, key, klen); 83 HASH_FIND(hh, desc_registry, &desc_key, sizeof(uint64_t), entry); 84 return entry; 85} 86 87static descriptor_entry_t *registry_lookup_sym_desc(ant_value_t obj, ant_offset_t sym_off) { 88 descriptor_entry_t *entry = NULL; 89 uint64_t k = make_sym_desc_key(obj, sym_off); 90 HASH_FIND(hh, desc_registry, &k, sizeof(uint64_t), entry); 91 return entry; 92} 93 94descriptor_entry_t *lookup_descriptor(ant_value_t obj, const char *key, size_t klen) { 95 assert(is_canonical_desc_obj(obj) && "lookup_descriptor expects js_as_obj(...)"); 96 if (!is_canonical_desc_obj(obj)) return NULL; 97 98 ant_object_t *ptr = js_obj_ptr(obj); 99 if (klen == 6 && memcmp(key, "length", 6) == 0 && ptr && ptr->type_tag == T_ARR) 100 return &arr_length_desc; 101 102 if (!is_exotic_desc_obj(obj)) return NULL; 103 return registry_lookup_desc(obj, key, klen); 104} 105 106descriptor_entry_t *lookup_sym_descriptor(ant_value_t obj, ant_offset_t sym_off) { 107 assert(is_canonical_desc_obj(obj) && "lookup_sym_descriptor expects js_as_obj(...)"); 108 if (!is_canonical_desc_obj(obj)) return NULL; 109 110 if (!is_exotic_desc_obj(obj)) return NULL; 111 return registry_lookup_sym_desc(obj, sym_off); 112} 113 114static descriptor_entry_t *get_or_create_desc(ant_t *js, ant_value_t obj, const char *key, size_t klen) { 115 if (!desc_registry_allowed(obj)) return NULL; 116 descriptor_entry_t *entry = registry_lookup_desc(obj, key, klen); 117 if (entry) return entry; 118 119 entry = (descriptor_entry_t *)ant_calloc(sizeof(descriptor_entry_t) + klen + 1); 120 if (!entry) return NULL; 121 122 entry->key = make_desc_key(obj, key, klen); 123 entry->obj_off = (uintptr_t)vdata(obj); 124 entry->prop_name = (char *)(entry + 1); 125 memcpy(entry->prop_name, key, klen); 126 entry->prop_name[klen] = '\0'; 127 entry->prop_len = klen; 128 entry->writable = true; 129 entry->enumerable = true; 130 entry->configurable = true; 131 entry->has_getter = false; 132 entry->has_setter = false; 133 entry->getter = js_mkundef(); 134 entry->setter = js_mkundef(); 135 136 HASH_ADD(hh, desc_registry, key, sizeof(uint64_t), entry); 137 return entry; 138} 139 140static descriptor_entry_t *get_or_create_sym_desc(ant_value_t obj, ant_offset_t sym_off) { 141 if (!desc_registry_allowed(obj)) return NULL; 142 descriptor_entry_t *entry = registry_lookup_sym_desc(obj, sym_off); 143 if (entry) return entry; 144 145 entry = (descriptor_entry_t *)ant_calloc(sizeof(descriptor_entry_t)); 146 if (!entry) return NULL; 147 148 entry->key = make_sym_desc_key(obj, sym_off); 149 entry->obj_off = (uintptr_t)vdata(obj); 150 entry->sym_off = sym_off; 151 entry->writable = true; 152 entry->enumerable = true; 153 entry->configurable = true; 154 entry->has_getter = false; 155 entry->has_setter = false; 156 entry->getter = js_mkundef(); 157 entry->setter = js_mkundef(); 158 159 HASH_ADD(hh, desc_registry, key, sizeof(uint64_t), entry); 160 return entry; 161} 162 163static bool ensure_string_shape_slot(ant_t *js, ant_value_t obj, const char *key, size_t klen, uint32_t *out_slot) { 164 ant_object_t *ptr = js_obj_ptr(obj); 165 if (!ptr || !ptr->shape) return false; 166 167 const char *interned = intern_string(key, klen); 168 if (!interned) return false; 169 170 int32_t slot = ant_shape_lookup_interned(ptr->shape, interned); 171 if (slot < 0) { 172 uint32_t added_slot = 0; 173 if (!ant_shape_add_interned_tr(&ptr->shape, interned, ANT_PROP_ATTR_DEFAULT, &added_slot)) return false; 174 if (!ensure_added_shape_slot_storage(ptr, added_slot)) return false; 175 slot = (int32_t)added_slot; 176 } 177 178 if (out_slot) *out_slot = (uint32_t)slot; 179 return true; 180} 181 182static bool ensure_symbol_shape_slot(ant_t *js, ant_value_t obj, ant_offset_t sym_off, uint32_t *out_slot) { 183 ant_object_t *ptr = js_obj_ptr(obj); 184 if (!ptr || !ptr->shape) return false; 185 186 int32_t slot = ant_shape_lookup_symbol(ptr->shape, sym_off); 187 if (slot < 0) { 188 ant_value_t sym = mkval(T_SYMBOL, sym_off); 189 if (is_err(mkprop(js, obj, sym, js_mkundef(), 0))) return false; 190 slot = ant_shape_lookup_symbol(ptr->shape, sym_off); 191 if (slot < 0) return false; 192 } 193 194 if (out_slot) *out_slot = (uint32_t)slot; 195 return true; 196} 197 198static ant_shape_prop_t *ensure_string_shape_prop(ant_t *js, ant_value_t obj, const char *key, size_t klen) { 199 uint32_t slot = 0; 200 if (!ensure_string_shape_slot(js, obj, key, klen, &slot)) return NULL; 201 ant_object_t *ptr = js_obj_ptr(obj); 202 if (!ptr || !ptr->shape) return NULL; 203 if (!js_obj_ensure_unique_shape(ptr)) return NULL; 204 return ant_shape_prop_mut_at(ptr->shape, slot); 205} 206 207static ant_shape_prop_t *ensure_symbol_shape_prop(ant_t *js, ant_value_t obj, ant_offset_t sym_off) { 208 uint32_t slot = 0; 209 if (!ensure_symbol_shape_slot(js, obj, sym_off, &slot)) return NULL; 210 ant_object_t *ptr = js_obj_ptr(obj); 211 if (!ptr || !ptr->shape) return NULL; 212 if (!js_obj_ensure_unique_shape(ptr)) return NULL; 213 return ant_shape_prop_mut_at(ptr->shape, slot); 214} 215 216static void apply_shape_desc_update( 217 ant_shape_prop_t *prop, 218 int flags, 219 bool include_writable, 220 bool set_getter_flag, 221 bool has_getter, 222 ant_value_t getter, 223 bool set_setter_flag, 224 bool has_setter, 225 ant_value_t setter 226) { 227 if (!prop) return; 228 prop->attrs = attrs_from_flags(flags, include_writable); 229 if (set_getter_flag) { 230 prop->has_getter = has_getter ? 1 : 0; 231 prop->getter = has_getter ? getter : js_mkundef(); 232 } 233 if (set_setter_flag) { 234 prop->has_setter = has_setter ? 1 : 0; 235 prop->setter = has_setter ? setter : js_mkundef(); 236 } 237} 238 239static void apply_registry_desc_update( 240 descriptor_entry_t *entry, 241 int flags, 242 bool include_writable, 243 bool set_getter_flag, 244 bool has_getter, 245 ant_value_t getter, 246 bool set_setter_flag, 247 bool has_setter, 248 ant_value_t setter 249) { 250 if (!entry) return; 251 if (include_writable) entry->writable = (flags & JS_DESC_W) != 0; 252 entry->enumerable = (flags & JS_DESC_E) != 0; 253 entry->configurable = (flags & JS_DESC_C) != 0; 254 if (set_getter_flag) { 255 entry->has_getter = has_getter; 256 entry->getter = has_getter ? getter : js_mkundef(); 257 } 258 if (set_setter_flag) { 259 entry->has_setter = has_setter; 260 entry->setter = has_setter ? setter : js_mkundef(); 261 } 262} 263 264void js_set_descriptor(ant_t *js, ant_value_t obj, const char *key, size_t klen, int flags) { 265 assert(is_canonical_desc_obj(obj) && "js_set_descriptor expects js_as_obj(...)"); 266 if (!is_canonical_desc_obj(obj)) return; 267 268 ant_shape_prop_t *prop = ensure_string_shape_prop(js, obj, key, klen); 269 if (prop) { 270 apply_shape_desc_update( 271 prop, flags, true, 272 false, false, js_mkundef(), 273 false, false, js_mkundef() 274 ); 275 ant_ic_epoch_bump(); 276 return; 277 } 278 279 if (!desc_registry_allowed(obj)) return; 280 descriptor_entry_t *entry = get_or_create_desc(js, obj, key, klen); 281 apply_registry_desc_update( 282 entry, flags, true, 283 false, false, js_mkundef(), 284 false, false, js_mkundef() 285 ); 286} 287 288void js_set_getter_desc(ant_t *js, ant_value_t obj, const char *key, size_t klen, ant_value_t getter, int flags) { 289 assert(is_canonical_desc_obj(obj) && "js_set_getter_desc expects js_as_obj(...)"); 290 if (!is_canonical_desc_obj(obj)) return; 291 292 ant_shape_prop_t *prop = ensure_string_shape_prop(js, obj, key, klen); 293 if (prop) { 294 apply_shape_desc_update( 295 prop, flags, false, 296 true, true, getter, 297 false, false, js_mkundef() 298 ); 299 ant_ic_epoch_bump(); 300 gc_write_barrier(js, js_obj_ptr(js_as_obj(obj)), getter); 301 return; 302 } 303 304 if (!desc_registry_allowed(obj)) return; 305 descriptor_entry_t *entry = get_or_create_desc(js, obj, key, klen); 306 apply_registry_desc_update( 307 entry, flags, false, 308 true, true, getter, 309 false, false, js_mkundef() 310 ); 311} 312 313void js_set_setter_desc(ant_t *js, ant_value_t obj, const char *key, size_t klen, ant_value_t setter, int flags) { 314 assert(is_canonical_desc_obj(obj) && "js_set_setter_desc expects js_as_obj(...)"); 315 if (!is_canonical_desc_obj(obj)) return; 316 317 ant_shape_prop_t *prop = ensure_string_shape_prop(js, obj, key, klen); 318 if (prop) { 319 apply_shape_desc_update( 320 prop, flags, false, 321 false, false, js_mkundef(), 322 true, true, setter 323 ); 324 ant_ic_epoch_bump(); 325 gc_write_barrier(js, js_obj_ptr(js_as_obj(obj)), setter); 326 return; 327 } 328 329 if (!desc_registry_allowed(obj)) return; 330 descriptor_entry_t *entry = get_or_create_desc(js, obj, key, klen); 331 apply_registry_desc_update( 332 entry, flags, false, 333 false, false, js_mkundef(), 334 true, true, setter 335 ); 336} 337 338void js_set_accessor_desc(ant_t *js, ant_value_t obj, const char *key, size_t klen, ant_value_t getter, ant_value_t setter, int flags) { 339 assert(is_canonical_desc_obj(obj) && "js_set_accessor_desc expects js_as_obj(...)"); 340 if (!is_canonical_desc_obj(obj)) return; 341 342 ant_shape_prop_t *prop = ensure_string_shape_prop(js, obj, key, klen); 343 if (prop) { 344 apply_shape_desc_update( 345 prop, flags, false, 346 true, true, getter, 347 true, true, setter 348 ); 349 ant_ic_epoch_bump(); 350 gc_write_barrier(js, js_obj_ptr(js_as_obj(obj)), getter); 351 gc_write_barrier(js, js_obj_ptr(js_as_obj(obj)), setter); 352 return; 353 } 354 355 if (!desc_registry_allowed(obj)) return; 356 descriptor_entry_t *entry = get_or_create_desc(js, obj, key, klen); 357 apply_registry_desc_update( 358 entry, flags, false, 359 true, true, getter, 360 true, true, setter 361 ); 362} 363 364void js_set_sym_getter_desc(ant_t *js, ant_value_t obj, ant_value_t sym, ant_value_t getter, int flags) { 365 assert(is_canonical_desc_obj(obj) && "js_set_sym_getter_desc expects js_as_obj(...)"); 366 if (!is_canonical_desc_obj(obj)) return; 367 if (vtype(sym) != T_SYMBOL) return; 368 ant_offset_t sym_off = (ant_offset_t)vdata(sym); 369 370 ant_shape_prop_t *prop = ensure_symbol_shape_prop(js, obj, sym_off); 371 if (prop) { 372 apply_shape_desc_update( 373 prop, flags, false, 374 true, true, getter, 375 false, false, js_mkundef() 376 ); 377 ant_ic_epoch_bump(); 378 gc_write_barrier(js, js_obj_ptr(js_as_obj(obj)), getter); 379 return; 380 } 381 382 if (!desc_registry_allowed(obj)) return; 383 descriptor_entry_t *entry = get_or_create_sym_desc(obj, sym_off); 384 apply_registry_desc_update( 385 entry, flags, false, 386 true, true, getter, 387 false, false, js_mkundef() 388 ); 389} 390 391void js_set_sym_setter_desc(ant_t *js, ant_value_t obj, ant_value_t sym, ant_value_t setter, int flags) { 392 assert(is_canonical_desc_obj(obj) && "js_set_sym_setter_desc expects js_as_obj(...)"); 393 if (!is_canonical_desc_obj(obj)) return; 394 if (vtype(sym) != T_SYMBOL) return; 395 ant_offset_t sym_off = (ant_offset_t)vdata(sym); 396 397 ant_shape_prop_t *prop = ensure_symbol_shape_prop(js, obj, sym_off); 398 if (prop) { 399 apply_shape_desc_update( 400 prop, flags, false, 401 false, false, js_mkundef(), 402 true, true, setter 403 ); 404 ant_ic_epoch_bump(); 405 gc_write_barrier(js, js_obj_ptr(js_as_obj(obj)), setter); 406 return; 407 } 408 409 if (!desc_registry_allowed(obj)) return; 410 descriptor_entry_t *entry = get_or_create_sym_desc(obj, sym_off); 411 apply_registry_desc_update( 412 entry, flags, false, 413 false, false, js_mkundef(), 414 true, true, setter 415 ); 416}