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 302 lines 7.7 kB view raw
1#include "ant.h" 2#include "runtime.h" 3#include "descriptors.h" 4 5#include <stdio.h> 6#include <stdlib.h> 7#include <string.h> 8#include <uthash.h> 9#include <argtable3.h> 10 11#ifdef _WIN32 12#include <process.h> 13#define ant_getpid _getpid 14#else 15#include <unistd.h> 16#define ant_getpid getpid 17#endif 18 19typedef struct { 20 const char *ptr; 21 size_t len; 22 UT_hash_handle hh; 23} intern_entry_t; 24 25typedef struct code_block { 26 struct code_block *next; 27 size_t used; 28 size_t capacity; 29 char data[]; 30} code_block_t; 31 32static struct ant_runtime runtime = {0}; 33struct ant_runtime *const rt = &runtime; 34static intern_entry_t *code_interns = NULL; 35 36static code_block_t *code_arena_head = NULL; 37static code_block_t *code_arena_current = NULL; 38static code_block_t *parse_arena_head = NULL; 39static code_block_t *parse_arena_current = NULL; 40 41static void code_interns_prune_for_block_range( 42 const code_block_t *block, 43 size_t start_offset 44) { 45 if (!block) return; 46 47 const char *start = block->data + start_offset; 48 const char *end = block->data + block->capacity; 49 intern_entry_t *entry = NULL; 50 intern_entry_t *tmp = NULL; 51 52 HASH_ITER(hh, code_interns, entry, tmp) 53 if (entry->ptr >= start && entry->ptr < end) { 54 HASH_DEL(code_interns, entry); 55 free(entry); 56 } 57} 58 59static void code_interns_prune_for_blocks(code_block_t *first) { 60 for ( 61 code_block_t *block = first; 62 block; block = block->next 63 ) code_interns_prune_for_block_range(block, 0); 64} 65 66static code_block_t *code_arena_new_block(size_t min_size) { 67 size_t capacity = CODE_ARENA_BLOCK_SIZE; 68 if (min_size > capacity) capacity = min_size; 69 70 code_block_t *block = malloc(sizeof(code_block_t) + capacity); 71 if (!block) return NULL; 72 73 block->next = NULL; 74 block->used = 0; 75 block->capacity = capacity; 76 return block; 77} 78 79static void *arena_bump( 80 code_block_t **head, 81 code_block_t **current, 82 size_t size 83) { 84 size = (size + 7) & ~(size_t)7; 85 if (!*current || (*current)->used + size > (*current)->capacity) { 86 code_block_t *new_block = code_arena_new_block(size); 87 if (!new_block) return NULL; 88 if (!*head) *head = new_block; 89 else if (*current) (*current)->next = new_block; 90 *current = new_block; 91 } 92 93 void *ptr = &(*current)->data[(*current)->used]; 94 (*current)->used += size; 95 return ptr; 96} 97 98static size_t arena_get_memory(code_block_t *head) { 99 size_t total = 0; 100 for (code_block_t *b = head; b; b = b->next) 101 total += sizeof(code_block_t) + b->capacity; 102 return total; 103} 104 105static code_arena_mark_t arena_mark(code_block_t *current) { 106 code_arena_mark_t mark = {0}; 107 mark.block = current; 108 mark.used = current ? current->used : 0; 109 return mark; 110} 111 112static void arena_rewind_plain( 113 code_block_t **head, 114 code_block_t **current, 115 code_arena_mark_t mark 116) { 117 code_block_t *target = (code_block_t *)mark.block; 118 119 if (!target) { 120 code_block_t *block = *head; 121 while (block) { 122 code_block_t *next = block->next; 123 free(block); 124 block = next; 125 } 126 *head = NULL; 127 *current = NULL; 128 return; 129 } 130 131 size_t clamped_used = mark.used <= target->capacity ? mark.used : target->capacity; 132 target->used = clamped_used; 133 134 code_block_t *b = target->next; 135 while (b) { 136 code_block_t *next = b->next; 137 free(b); 138 b = next; 139 } 140 141 target->next = NULL; 142 *current = target; 143} 144 145const char *code_arena_alloc(const char *code, size_t len) { 146 if (!code || len == 0) return NULL; 147 148 intern_entry_t *found = NULL; 149 HASH_FIND(hh, code_interns, code, len, found); 150 if (found) return found->ptr; 151 152 size_t alloc_size = len + 1; 153 if (!code_arena_current || code_arena_current->used + alloc_size > code_arena_current->capacity) { 154 code_block_t *new_block = code_arena_new_block(alloc_size); 155 if (!new_block) return NULL; 156 if (!code_arena_head) code_arena_head = new_block; 157 else if (code_arena_current) code_arena_current->next = new_block; 158 code_arena_current = new_block; 159 } 160 161 char *dest = &code_arena_current->data[code_arena_current->used]; 162 memcpy(dest, code, len); 163 dest[len] = '\0'; 164 code_arena_current->used += alloc_size; 165 166 intern_entry_t *entry = malloc(sizeof(*entry)); 167 if (entry) { 168 entry->ptr = dest; 169 entry->len = len; 170 HASH_ADD_KEYPTR(hh, code_interns, entry->ptr, entry->len, entry); 171 } 172 173 return dest; 174} 175 176void *code_arena_bump(size_t size) { 177 return arena_bump(&code_arena_head, &code_arena_current, size); 178} 179 180size_t code_arena_get_memory(void) { 181 return arena_get_memory(code_arena_head); 182} 183 184code_arena_mark_t code_arena_mark(void) { 185 return arena_mark(code_arena_current); 186} 187 188void code_arena_rewind(code_arena_mark_t mark) { 189 code_block_t *target = (code_block_t *)mark.block; 190 191 if (!target) { 192 code_interns_prune_for_blocks(code_arena_head); 193 code_block_t *block = code_arena_head; 194 195 while (block) { 196 code_block_t *next = block->next; 197 free(block); block = next; 198 } 199 200 code_arena_head = NULL; 201 code_arena_current = NULL; 202 203 return; 204 } 205 206 size_t clamped_used = mark.used <= target->capacity ? mark.used : target->capacity; 207 code_interns_prune_for_block_range(target, clamped_used); 208 code_interns_prune_for_blocks(target->next); 209 210 if (mark.used <= target->capacity) target->used = mark.used; 211 code_block_t *b = target->next; 212 213 while (b) { 214 code_block_t *next = b->next; 215 free(b); b = next; 216 } 217 218 target->next = NULL; 219 code_arena_current = target; 220} 221 222void *parse_arena_bump(size_t size) { 223 return arena_bump(&parse_arena_head, &parse_arena_current, size); 224} 225 226size_t parse_arena_get_memory(void) { 227 return arena_get_memory(parse_arena_head); 228} 229 230code_arena_mark_t parse_arena_mark(void) { 231 return arena_mark(parse_arena_current); 232} 233 234void parse_arena_rewind(code_arena_mark_t mark) { 235 arena_rewind_plain(&parse_arena_head, &parse_arena_current, mark); 236} 237 238void parse_arena_reset(void) { 239 parse_arena_rewind((code_arena_mark_t){0}); 240} 241 242void code_arena_reset(void) { 243 intern_entry_t *entry, *tmp; 244 HASH_ITER(hh, code_interns, entry, tmp) { 245 HASH_DEL(code_interns, entry); 246 free(entry); 247 } 248 code_interns = NULL; 249 250 code_block_t *block = code_arena_head; 251 while (block) { 252 code_block_t *next = block->next; 253 free(block); 254 block = next; 255 } 256 257 code_arena_head = NULL; 258 code_arena_current = NULL; 259 parse_arena_reset(); 260} 261 262void destroy_runtime(ant_t *js) { 263 if (rt->js == js) memset(&runtime, 0, sizeof(runtime)); 264} 265 266struct ant_runtime *ant_runtime_init(ant_t *js, int argc, char **argv, struct arg_file *ls_p) { 267 ant_value_t global = js_glob(js); 268 269 runtime = (struct ant_runtime){ 270 .js = js, 271 .ant_obj = js_newobj(js), 272 .flags = 0, .argc = argc, .argv = argv, 273 .pid = (int)ant_getpid(), 274 .ls_fp = (ls_p && ls_p->count > 0) ? ls_p->filename[0] : NULL, 275 }; 276 277 js_set(js, global, "onerror", js_mknull()); 278 js_set_descriptor(js, global, "onerror", 7, JS_DESC_W | JS_DESC_C); 279 280 js_set(js, global, "onunhandledrejection", js_mknull()); 281 js_set_descriptor(js, global, "onunhandledrejection", 20, JS_DESC_W | JS_DESC_C); 282 283 js_set(js, global, "onrejectionhandled", js_mknull()); 284 js_set_descriptor(js, global, "onrejectionhandled", 18, JS_DESC_W | JS_DESC_C); 285 286 js_set(js, global, "self", global); 287 js_set_descriptor(js, global, "self", 4, JS_DESC_W | JS_DESC_C); 288 289 js_set(js, global, "window", global); 290 js_set_descriptor(js, global, "window", 6, JS_DESC_W | JS_DESC_C); 291 292 js_set(js, global, "global", global); 293 js_set_descriptor(js, global, "global", 6, JS_DESC_W | JS_DESC_C); 294 295 js_set(js, global, "globalThis", global); 296 js_set_descriptor(js, global, "globalThis", 10, JS_DESC_W | JS_DESC_C); 297 298 js_set(js, global, "Ant", runtime.ant_obj); 299 js_set_descriptor(js, global, "Ant", 3, JS_DESC_E); 300 301 return &runtime; 302}