]> git.proxmox.com Git - ceph.git/blob - ceph/src/civetweb/src/third_party/duktape-1.3.0/src-separate/duk_heap_alloc.c
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / civetweb / src / third_party / duktape-1.3.0 / src-separate / duk_heap_alloc.c
1 /*
2 * duk_heap allocation and freeing.
3 */
4
5 #include "duk_internal.h"
6
7 /* constants for built-in string data depacking */
8 #define DUK__BITPACK_LETTER_LIMIT 26
9 #define DUK__BITPACK_UNDERSCORE 26
10 #define DUK__BITPACK_FF 27
11 #define DUK__BITPACK_SWITCH1 29
12 #define DUK__BITPACK_SWITCH 30
13 #define DUK__BITPACK_SEVENBIT 31
14
15 /*
16 * Free a heap object.
17 *
18 * Free heap object and its internal (non-heap) pointers. Assumes that
19 * caller has removed the object from heap allocated list or the string
20 * intern table, and any weak references (which strings may have) have
21 * been already dealt with.
22 */
23
24 DUK_INTERNAL void duk_free_hobject_inner(duk_heap *heap, duk_hobject *h) {
25 DUK_ASSERT(heap != NULL);
26 DUK_ASSERT(h != NULL);
27
28 DUK_FREE(heap, DUK_HOBJECT_GET_PROPS(heap, h));
29
30 if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) {
31 duk_hcompiledfunction *f = (duk_hcompiledfunction *) h;
32 DUK_UNREF(f);
33 /* Currently nothing to free; 'data' is a heap object */
34 } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
35 duk_hnativefunction *f = (duk_hnativefunction *) h;
36 DUK_UNREF(f);
37 /* Currently nothing to free */
38 } else if (DUK_HOBJECT_IS_THREAD(h)) {
39 duk_hthread *t = (duk_hthread *) h;
40 DUK_FREE(heap, t->valstack);
41 DUK_FREE(heap, t->callstack);
42 DUK_FREE(heap, t->catchstack);
43 /* Don't free h->resumer because it exists in the heap.
44 * Callstack entries also contain function pointers which
45 * are not freed for the same reason.
46 */
47
48 /* XXX: with 'caller' property the callstack would need
49 * to be unwound to update the 'caller' properties of
50 * functions in the callstack.
51 */
52 }
53 }
54
55 DUK_INTERNAL void duk_free_hbuffer_inner(duk_heap *heap, duk_hbuffer *h) {
56 DUK_ASSERT(heap != NULL);
57 DUK_ASSERT(h != NULL);
58
59 if (DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h)) {
60 duk_hbuffer_dynamic *g = (duk_hbuffer_dynamic *) h;
61 DUK_DDD(DUK_DDDPRINT("free dynamic buffer %p", (void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, g)));
62 DUK_FREE(heap, DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, g));
63 }
64 }
65
66 DUK_INTERNAL void duk_free_hstring_inner(duk_heap *heap, duk_hstring *h) {
67 DUK_ASSERT(heap != NULL);
68 DUK_ASSERT(h != NULL);
69
70 DUK_UNREF(heap);
71 DUK_UNREF(h);
72
73 #if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_FREE)
74 if (DUK_HSTRING_HAS_EXTDATA(h)) {
75 DUK_DDD(DUK_DDDPRINT("free extstr: hstring %!O, extdata: %p",
76 h, DUK_HSTRING_GET_EXTDATA((duk_hstring_external *) h)));
77 DUK_USE_EXTSTR_FREE(heap->heap_udata, (const void *) DUK_HSTRING_GET_EXTDATA((duk_hstring_external *) h));
78 }
79 #endif
80 }
81
82 DUK_INTERNAL void duk_heap_free_heaphdr_raw(duk_heap *heap, duk_heaphdr *hdr) {
83 DUK_ASSERT(heap);
84 DUK_ASSERT(hdr);
85
86 DUK_DDD(DUK_DDDPRINT("free heaphdr %p, htype %ld", (void *) hdr, (long) DUK_HEAPHDR_GET_TYPE(hdr)));
87
88 switch ((int) DUK_HEAPHDR_GET_TYPE(hdr)) {
89 case DUK_HTYPE_STRING:
90 duk_free_hstring_inner(heap, (duk_hstring *) hdr);
91 break;
92 case DUK_HTYPE_OBJECT:
93 duk_free_hobject_inner(heap, (duk_hobject *) hdr);
94 break;
95 case DUK_HTYPE_BUFFER:
96 duk_free_hbuffer_inner(heap, (duk_hbuffer *) hdr);
97 break;
98 default:
99 DUK_UNREACHABLE();
100 }
101
102 DUK_FREE(heap, hdr);
103 }
104
105 /*
106 * Free the heap.
107 *
108 * Frees heap-related non-heap-tracked allocations such as the
109 * string intern table; then frees the heap allocated objects;
110 * and finally frees the heap structure itself. Reference counts
111 * and GC markers are ignored (and not updated) in this process,
112 * and finalizers won't be called.
113 *
114 * The heap pointer and heap object pointers must not be used
115 * after this call.
116 */
117
118 DUK_LOCAL void duk__free_allocated(duk_heap *heap) {
119 duk_heaphdr *curr;
120 duk_heaphdr *next;
121
122 curr = heap->heap_allocated;
123 while (curr) {
124 /* We don't log or warn about freeing zero refcount objects
125 * because they may happen with finalizer processing.
126 */
127
128 DUK_DDD(DUK_DDDPRINT("FINALFREE (allocated): %!iO",
129 (duk_heaphdr *) curr));
130 next = DUK_HEAPHDR_GET_NEXT(heap, curr);
131 duk_heap_free_heaphdr_raw(heap, curr);
132 curr = next;
133 }
134 }
135
136 #ifdef DUK_USE_REFERENCE_COUNTING
137 DUK_LOCAL void duk__free_refzero_list(duk_heap *heap) {
138 duk_heaphdr *curr;
139 duk_heaphdr *next;
140
141 curr = heap->refzero_list;
142 while (curr) {
143 DUK_DDD(DUK_DDDPRINT("FINALFREE (refzero_list): %!iO",
144 (duk_heaphdr *) curr));
145 next = DUK_HEAPHDR_GET_NEXT(heap, curr);
146 duk_heap_free_heaphdr_raw(heap, curr);
147 curr = next;
148 }
149 }
150 #endif
151
152 #ifdef DUK_USE_MARK_AND_SWEEP
153 DUK_LOCAL void duk__free_markandsweep_finalize_list(duk_heap *heap) {
154 duk_heaphdr *curr;
155 duk_heaphdr *next;
156
157 curr = heap->finalize_list;
158 while (curr) {
159 DUK_DDD(DUK_DDDPRINT("FINALFREE (finalize_list): %!iO",
160 (duk_heaphdr *) curr));
161 next = DUK_HEAPHDR_GET_NEXT(heap, curr);
162 duk_heap_free_heaphdr_raw(heap, curr);
163 curr = next;
164 }
165 }
166 #endif
167
168 DUK_LOCAL void duk__free_stringtable(duk_heap *heap) {
169 /* strings are only tracked by stringtable */
170 duk_heap_free_strtab(heap);
171 }
172
173 DUK_LOCAL void duk__free_run_finalizers(duk_heap *heap) {
174 duk_hthread *thr;
175 duk_heaphdr *curr;
176 #ifdef DUK_USE_DEBUG
177 duk_size_t count_obj = 0;
178 #endif
179
180 DUK_ASSERT(heap != NULL);
181 DUK_ASSERT(heap->heap_thread != NULL);
182 #ifdef DUK_USE_REFERENCE_COUNTING
183 DUK_ASSERT(heap->refzero_list == NULL); /* refzero not running -> must be empty */
184 #endif
185 #ifdef DUK_USE_MARK_AND_SWEEP
186 DUK_ASSERT(heap->finalize_list == NULL); /* mark-and-sweep not running -> must be empty */
187 #endif
188
189 /* XXX: here again finalizer thread is the heap_thread which needs
190 * to be coordinated with finalizer thread fixes.
191 */
192 thr = heap->heap_thread;
193 DUK_ASSERT(thr != NULL);
194
195 curr = heap->heap_allocated;
196 while (curr) {
197 if (DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT) {
198 /* Only objects in heap_allocated may have finalizers. Check that
199 * the object itself has a _Finalizer property so that we don't
200 * execute finalizers for e.g. Proxy objects.
201 */
202 DUK_ASSERT(thr != NULL);
203 DUK_ASSERT(curr != NULL);
204
205 if (duk_hobject_hasprop_raw(thr, (duk_hobject *) curr, DUK_HTHREAD_STRING_INT_FINALIZER(thr))) {
206 duk_hobject_run_finalizer(thr, (duk_hobject *) curr);
207 }
208 #ifdef DUK_USE_DEBUG
209 count_obj++;
210 #endif
211 }
212 curr = DUK_HEAPHDR_GET_NEXT(heap, curr);
213 }
214
215 /* Note: count includes all objects, not only those with an actual finalizer. */
216 #ifdef DUK_USE_DEBUG
217 DUK_D(DUK_DPRINT("checked %ld objects for finalizers before freeing heap", (long) count_obj));
218 #endif
219 }
220
221 DUK_INTERNAL void duk_heap_free(duk_heap *heap) {
222 DUK_D(DUK_DPRINT("free heap: %p", (void *) heap));
223
224 #if defined(DUK_USE_DEBUG)
225 duk_heap_dump_strtab(heap);
226 #endif
227
228 #if defined(DUK_USE_DEBUGGER_SUPPORT)
229 /* Detach a debugger if attached (can be called multiple times)
230 * safely.
231 */
232 duk_debug_do_detach(heap);
233 #endif
234
235 /* Execute finalizers before freeing the heap, even for reachable
236 * objects, and regardless of whether or not mark-and-sweep is
237 * enabled. This gives finalizers the chance to free any native
238 * resources like file handles, allocations made outside Duktape,
239 * etc.
240 *
241 * XXX: this perhaps requires an execution time limit.
242 */
243 DUK_D(DUK_DPRINT("execute finalizers before freeing heap"));
244 #ifdef DUK_USE_MARK_AND_SWEEP
245 /* run mark-and-sweep a few times just in case (unreachable
246 * object finalizers run already here)
247 */
248 duk_heap_mark_and_sweep(heap, 0);
249 duk_heap_mark_and_sweep(heap, 0);
250 #endif
251 duk__free_run_finalizers(heap);
252
253 /* Note: heap->heap_thread, heap->curr_thread, and heap->heap_object
254 * are on the heap allocated list.
255 */
256
257 DUK_D(DUK_DPRINT("freeing heap objects of heap: %p", (void *) heap));
258 duk__free_allocated(heap);
259
260 #ifdef DUK_USE_REFERENCE_COUNTING
261 DUK_D(DUK_DPRINT("freeing refzero list of heap: %p", (void *) heap));
262 duk__free_refzero_list(heap);
263 #endif
264
265 #ifdef DUK_USE_MARK_AND_SWEEP
266 DUK_D(DUK_DPRINT("freeing mark-and-sweep finalize list of heap: %p", (void *) heap));
267 duk__free_markandsweep_finalize_list(heap);
268 #endif
269
270 DUK_D(DUK_DPRINT("freeing string table of heap: %p", (void *) heap));
271 duk__free_stringtable(heap);
272
273 DUK_D(DUK_DPRINT("freeing heap structure: %p", (void *) heap));
274 heap->free_func(heap->heap_udata, heap);
275 }
276
277 /*
278 * Allocate a heap.
279 *
280 * String table is initialized with built-in strings from genstrings.py.
281 */
282
283 /* intern built-in strings from precooked data (genstrings.py) */
284 DUK_LOCAL duk_bool_t duk__init_heap_strings(duk_heap *heap) {
285 duk_bitdecoder_ctx bd_ctx;
286 duk_bitdecoder_ctx *bd = &bd_ctx; /* convenience */
287 duk_small_uint_t i, j;
288
289 DUK_MEMZERO(&bd_ctx, sizeof(bd_ctx));
290 bd->data = (const duk_uint8_t *) duk_strings_data;
291 bd->length = (duk_size_t) DUK_STRDATA_DATA_LENGTH;
292
293 for (i = 0; i < DUK_HEAP_NUM_STRINGS; i++) {
294 duk_uint8_t tmp[DUK_STRDATA_MAX_STRLEN];
295 duk_hstring *h;
296 duk_small_uint_t len;
297 duk_small_uint_t mode;
298 duk_small_uint_t t;
299
300 len = duk_bd_decode(bd, 5);
301 mode = 32; /* 0 = uppercase, 32 = lowercase (= 'a' - 'A') */
302 for (j = 0; j < len; j++) {
303 t = duk_bd_decode(bd, 5);
304 if (t < DUK__BITPACK_LETTER_LIMIT) {
305 t = t + DUK_ASC_UC_A + mode;
306 } else if (t == DUK__BITPACK_UNDERSCORE) {
307 t = DUK_ASC_UNDERSCORE;
308 } else if (t == DUK__BITPACK_FF) {
309 /* Internal keys are prefixed with 0xFF in the stringtable
310 * (which makes them invalid UTF-8 on purpose).
311 */
312 t = 0xff;
313 } else if (t == DUK__BITPACK_SWITCH1) {
314 t = duk_bd_decode(bd, 5);
315 DUK_ASSERT_DISABLE(t >= 0); /* unsigned */
316 DUK_ASSERT(t <= 25);
317 t = t + DUK_ASC_UC_A + (mode ^ 32);
318 } else if (t == DUK__BITPACK_SWITCH) {
319 mode = mode ^ 32;
320 t = duk_bd_decode(bd, 5);
321 DUK_ASSERT_DISABLE(t >= 0);
322 DUK_ASSERT(t <= 25);
323 t = t + DUK_ASC_UC_A + mode;
324 } else if (t == DUK__BITPACK_SEVENBIT) {
325 t = duk_bd_decode(bd, 7);
326 }
327 tmp[j] = (duk_uint8_t) t;
328 }
329
330 /* No need to length check string: it will never exceed even
331 * the 16-bit length maximum.
332 */
333 DUK_ASSERT(len <= 0xffffUL);
334 DUK_DDD(DUK_DDDPRINT("intern built-in string %ld", (long) i));
335 h = duk_heap_string_intern(heap, tmp, len);
336 if (!h) {
337 goto error;
338 }
339
340 /* Special flags checks. Since these strings are always
341 * reachable and a string cannot appear twice in the string
342 * table, there's no need to check/set these flags elsewhere.
343 * The 'internal' flag is set by string intern code.
344 */
345 if (i == DUK_STRIDX_EVAL || i == DUK_STRIDX_LC_ARGUMENTS) {
346 DUK_HSTRING_SET_EVAL_OR_ARGUMENTS(h);
347 }
348 if (i >= DUK_STRIDX_START_RESERVED && i < DUK_STRIDX_END_RESERVED) {
349 DUK_HSTRING_SET_RESERVED_WORD(h);
350 if (i >= DUK_STRIDX_START_STRICT_RESERVED) {
351 DUK_HSTRING_SET_STRICT_RESERVED_WORD(h);
352 }
353 }
354
355 DUK_DDD(DUK_DDDPRINT("interned: %!O", (duk_heaphdr *) h));
356
357 /* XXX: The incref macro takes a thread pointer but doesn't
358 * use it right now.
359 */
360 DUK_HSTRING_INCREF(_never_referenced_, h);
361
362 #if defined(DUK_USE_HEAPPTR16)
363 heap->strs16[i] = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h);
364 #else
365 heap->strs[i] = h;
366 #endif
367 }
368
369 return 1;
370
371 error:
372 return 0;
373 }
374
375 DUK_LOCAL duk_bool_t duk__init_heap_thread(duk_heap *heap) {
376 duk_hthread *thr;
377
378 DUK_DD(DUK_DDPRINT("heap init: alloc heap thread"));
379 thr = duk_hthread_alloc(heap,
380 DUK_HOBJECT_FLAG_EXTENSIBLE |
381 DUK_HOBJECT_FLAG_THREAD |
382 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_THREAD));
383 if (!thr) {
384 DUK_D(DUK_DPRINT("failed to alloc heap_thread"));
385 return 0;
386 }
387 thr->state = DUK_HTHREAD_STATE_INACTIVE;
388 #if defined(DUK_USE_HEAPPTR16)
389 thr->strs16 = heap->strs16;
390 #else
391 thr->strs = heap->strs;
392 #endif
393
394 heap->heap_thread = thr;
395 DUK_HTHREAD_INCREF(thr, thr); /* Note: first argument not really used */
396
397 /* 'thr' is now reachable */
398
399 if (!duk_hthread_init_stacks(heap, thr)) {
400 return 0;
401 }
402
403 /* XXX: this may now fail, and is not handled correctly */
404 duk_hthread_create_builtin_objects(thr);
405
406 /* default prototype (Note: 'thr' must be reachable) */
407 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) thr, thr->builtins[DUK_BIDX_THREAD_PROTOTYPE]);
408
409 return 1;
410 }
411
412 #ifdef DUK_USE_DEBUG
413 #define DUK__DUMPSZ(t) do { \
414 DUK_D(DUK_DPRINT("" #t "=%ld", (long) sizeof(t))); \
415 } while (0)
416
417 /* These is not 100% because format would need to be non-portable "long long".
418 * Also print out as doubles to catch cases where the "long" type is not wide
419 * enough; the limits will then not be printed accurately but the magnitude
420 * will be correct.
421 */
422 #define DUK__DUMPLM_SIGNED_RAW(t,a,b) do { \
423 DUK_D(DUK_DPRINT(t "=[%ld,%ld]=[%lf,%lf]", \
424 (long) (a), (long) (b), \
425 (double) (a), (double) (b))); \
426 } while(0)
427 #define DUK__DUMPLM_UNSIGNED_RAW(t,a,b) do { \
428 DUK_D(DUK_DPRINT(t "=[%lu,%lu]=[%lf,%lf]", \
429 (unsigned long) (a), (unsigned long) (b), \
430 (double) (a), (double) (b))); \
431 } while(0)
432 #define DUK__DUMPLM_SIGNED(t) do { \
433 DUK__DUMPLM_SIGNED_RAW("DUK_" #t "_{MIN,MAX}", DUK_##t##_MIN, DUK_##t##_MAX); \
434 } while(0)
435 #define DUK__DUMPLM_UNSIGNED(t) do { \
436 DUK__DUMPLM_UNSIGNED_RAW("DUK_" #t "_{MIN,MAX}", DUK_##t##_MIN, DUK_##t##_MAX); \
437 } while(0)
438
439 DUK_LOCAL void duk__dump_type_sizes(void) {
440 DUK_D(DUK_DPRINT("sizeof()"));
441
442 /* basic platform types */
443 DUK__DUMPSZ(char);
444 DUK__DUMPSZ(short);
445 DUK__DUMPSZ(int);
446 DUK__DUMPSZ(long);
447 DUK__DUMPSZ(double);
448 DUK__DUMPSZ(void *);
449 DUK__DUMPSZ(size_t);
450
451 /* basic types from duk_features.h */
452 DUK__DUMPSZ(duk_uint8_t);
453 DUK__DUMPSZ(duk_int8_t);
454 DUK__DUMPSZ(duk_uint16_t);
455 DUK__DUMPSZ(duk_int16_t);
456 DUK__DUMPSZ(duk_uint32_t);
457 DUK__DUMPSZ(duk_int32_t);
458 DUK__DUMPSZ(duk_uint64_t);
459 DUK__DUMPSZ(duk_int64_t);
460 DUK__DUMPSZ(duk_uint_least8_t);
461 DUK__DUMPSZ(duk_int_least8_t);
462 DUK__DUMPSZ(duk_uint_least16_t);
463 DUK__DUMPSZ(duk_int_least16_t);
464 DUK__DUMPSZ(duk_uint_least32_t);
465 DUK__DUMPSZ(duk_int_least32_t);
466 #if defined(DUK_USE_64BIT_OPS)
467 DUK__DUMPSZ(duk_uint_least64_t);
468 DUK__DUMPSZ(duk_int_least64_t);
469 #endif
470 DUK__DUMPSZ(duk_uint_fast8_t);
471 DUK__DUMPSZ(duk_int_fast8_t);
472 DUK__DUMPSZ(duk_uint_fast16_t);
473 DUK__DUMPSZ(duk_int_fast16_t);
474 DUK__DUMPSZ(duk_uint_fast32_t);
475 DUK__DUMPSZ(duk_int_fast32_t);
476 #if defined(DUK_USE_64BIT_OPS)
477 DUK__DUMPSZ(duk_uint_fast64_t);
478 DUK__DUMPSZ(duk_int_fast64_t);
479 #endif
480 DUK__DUMPSZ(duk_uintptr_t);
481 DUK__DUMPSZ(duk_intptr_t);
482 DUK__DUMPSZ(duk_uintmax_t);
483 DUK__DUMPSZ(duk_intmax_t);
484 DUK__DUMPSZ(duk_double_t);
485
486 /* important chosen base types */
487 DUK__DUMPSZ(duk_int_t);
488 DUK__DUMPSZ(duk_uint_t);
489 DUK__DUMPSZ(duk_int_fast_t);
490 DUK__DUMPSZ(duk_uint_fast_t);
491 DUK__DUMPSZ(duk_small_int_t);
492 DUK__DUMPSZ(duk_small_uint_t);
493 DUK__DUMPSZ(duk_small_int_fast_t);
494 DUK__DUMPSZ(duk_small_uint_fast_t);
495
496 /* some derived types */
497 DUK__DUMPSZ(duk_codepoint_t);
498 DUK__DUMPSZ(duk_ucodepoint_t);
499 DUK__DUMPSZ(duk_idx_t);
500 DUK__DUMPSZ(duk_errcode_t);
501 DUK__DUMPSZ(duk_uarridx_t);
502
503 /* tval */
504 DUK__DUMPSZ(duk_double_union);
505 DUK__DUMPSZ(duk_tval);
506
507 /* structs from duk_forwdecl.h */
508 DUK__DUMPSZ(duk_jmpbuf);
509 DUK__DUMPSZ(duk_heaphdr);
510 DUK__DUMPSZ(duk_heaphdr_string);
511 DUK__DUMPSZ(duk_hstring);
512 DUK__DUMPSZ(duk_hstring_external);
513 DUK__DUMPSZ(duk_hobject);
514 DUK__DUMPSZ(duk_hcompiledfunction);
515 DUK__DUMPSZ(duk_hnativefunction);
516 DUK__DUMPSZ(duk_hthread);
517 DUK__DUMPSZ(duk_hbuffer);
518 DUK__DUMPSZ(duk_hbuffer_fixed);
519 DUK__DUMPSZ(duk_hbuffer_dynamic);
520 DUK__DUMPSZ(duk_hbuffer_external);
521 DUK__DUMPSZ(duk_propaccessor);
522 DUK__DUMPSZ(duk_propvalue);
523 DUK__DUMPSZ(duk_propdesc);
524 DUK__DUMPSZ(duk_heap);
525 #if defined(DUK_USE_STRTAB_CHAIN)
526 DUK__DUMPSZ(duk_strtab_entry);
527 #endif
528 DUK__DUMPSZ(duk_activation);
529 DUK__DUMPSZ(duk_catcher);
530 DUK__DUMPSZ(duk_strcache);
531 DUK__DUMPSZ(duk_ljstate);
532 DUK__DUMPSZ(duk_fixedbuffer);
533 DUK__DUMPSZ(duk_bitdecoder_ctx);
534 DUK__DUMPSZ(duk_bitencoder_ctx);
535 DUK__DUMPSZ(duk_token);
536 DUK__DUMPSZ(duk_re_token);
537 DUK__DUMPSZ(duk_lexer_point);
538 DUK__DUMPSZ(duk_lexer_ctx);
539 DUK__DUMPSZ(duk_compiler_instr);
540 DUK__DUMPSZ(duk_compiler_func);
541 DUK__DUMPSZ(duk_compiler_ctx);
542 DUK__DUMPSZ(duk_re_matcher_ctx);
543 DUK__DUMPSZ(duk_re_compiler_ctx);
544 }
545 DUK_LOCAL void duk__dump_type_limits(void) {
546 DUK_D(DUK_DPRINT("limits"));
547
548 /* basic types */
549 DUK__DUMPLM_SIGNED(INT8);
550 DUK__DUMPLM_UNSIGNED(UINT8);
551 DUK__DUMPLM_SIGNED(INT_FAST8);
552 DUK__DUMPLM_UNSIGNED(UINT_FAST8);
553 DUK__DUMPLM_SIGNED(INT_LEAST8);
554 DUK__DUMPLM_UNSIGNED(UINT_LEAST8);
555 DUK__DUMPLM_SIGNED(INT16);
556 DUK__DUMPLM_UNSIGNED(UINT16);
557 DUK__DUMPLM_SIGNED(INT_FAST16);
558 DUK__DUMPLM_UNSIGNED(UINT_FAST16);
559 DUK__DUMPLM_SIGNED(INT_LEAST16);
560 DUK__DUMPLM_UNSIGNED(UINT_LEAST16);
561 DUK__DUMPLM_SIGNED(INT32);
562 DUK__DUMPLM_UNSIGNED(UINT32);
563 DUK__DUMPLM_SIGNED(INT_FAST32);
564 DUK__DUMPLM_UNSIGNED(UINT_FAST32);
565 DUK__DUMPLM_SIGNED(INT_LEAST32);
566 DUK__DUMPLM_UNSIGNED(UINT_LEAST32);
567 #if defined(DUK_USE_64BIT_OPS)
568 DUK__DUMPLM_SIGNED(INT64);
569 DUK__DUMPLM_UNSIGNED(UINT64);
570 DUK__DUMPLM_SIGNED(INT_FAST64);
571 DUK__DUMPLM_UNSIGNED(UINT_FAST64);
572 DUK__DUMPLM_SIGNED(INT_LEAST64);
573 DUK__DUMPLM_UNSIGNED(UINT_LEAST64);
574 #endif
575 DUK__DUMPLM_SIGNED(INTPTR);
576 DUK__DUMPLM_UNSIGNED(UINTPTR);
577 DUK__DUMPLM_SIGNED(INTMAX);
578 DUK__DUMPLM_UNSIGNED(UINTMAX);
579
580 /* derived types */
581 DUK__DUMPLM_SIGNED(INT);
582 DUK__DUMPLM_UNSIGNED(UINT);
583 DUK__DUMPLM_SIGNED(INT_FAST);
584 DUK__DUMPLM_UNSIGNED(UINT_FAST);
585 DUK__DUMPLM_SIGNED(SMALL_INT);
586 DUK__DUMPLM_UNSIGNED(SMALL_UINT);
587 DUK__DUMPLM_SIGNED(SMALL_INT_FAST);
588 DUK__DUMPLM_UNSIGNED(SMALL_UINT_FAST);
589 }
590 #undef DUK__DUMPSZ
591 #undef DUK__DUMPLM_SIGNED_RAW
592 #undef DUK__DUMPLM_UNSIGNED_RAW
593 #undef DUK__DUMPLM_SIGNED
594 #undef DUK__DUMPLM_UNSIGNED
595
596 DUK_LOCAL void duk__dump_misc_options(void) {
597 DUK_D(DUK_DPRINT("DUK_VERSION: %ld", (long) DUK_VERSION));
598 DUK_D(DUK_DPRINT("DUK_GIT_DESCRIBE: %s", DUK_GIT_DESCRIBE));
599 #if defined(DUK_USE_PACKED_TVAL)
600 DUK_D(DUK_DPRINT("DUK_USE_PACKED_TVAL: yes"));
601 #else
602 DUK_D(DUK_DPRINT("DUK_USE_PACKED_TVAL: no"));
603 #endif
604 #if defined(DUK_USE_INTEGER_LE)
605 DUK_D(DUK_DPRINT("Integer endianness: little"));
606 #elif defined(DUK_USE_INTEGER_ME)
607 DUK_D(DUK_DPRINT("Integer endianness: mixed"));
608 #elif defined(DUK_USE_INTEGER_BE)
609 DUK_D(DUK_DPRINT("Integer endianness: big"));
610 #else
611 DUK_D(DUK_DPRINT("Integer endianness: ???"));
612 #endif
613 #if defined(DUK_USE_DOUBLE_LE)
614 DUK_D(DUK_DPRINT("IEEE double endianness: little"));
615 #elif defined(DUK_USE_DOUBLE_ME)
616 DUK_D(DUK_DPRINT("IEEE double endianness: mixed"));
617 #elif defined(DUK_USE_DOUBLE_BE)
618 DUK_D(DUK_DPRINT("IEEE double endianness: big"));
619 #else
620 DUK_D(DUK_DPRINT("IEEE double endianness: ???"));
621 #endif
622 }
623 #endif /* DUK_USE_DEBUG */
624
625 DUK_INTERNAL
626 duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
627 duk_realloc_function realloc_func,
628 duk_free_function free_func,
629 void *heap_udata,
630 duk_fatal_function fatal_func) {
631 duk_heap *res = NULL;
632
633 /* Silence a few global unused warnings here. */
634 DUK_UNREF(duk_str_unsupported);
635
636 DUK_D(DUK_DPRINT("allocate heap"));
637
638 /*
639 * Debug dump type sizes
640 */
641
642 #ifdef DUK_USE_DEBUG
643 duk__dump_misc_options();
644 duk__dump_type_sizes();
645 duk__dump_type_limits();
646 #endif
647
648 /*
649 * If selftests enabled, run them as early as possible
650 */
651 #ifdef DUK_USE_SELF_TESTS
652 DUK_D(DUK_DPRINT("running self tests"));
653 duk_selftest_run_tests();
654 DUK_D(DUK_DPRINT("self tests passed"));
655 #endif
656
657 /*
658 * Computed values (e.g. INFINITY)
659 */
660
661 #ifdef DUK_USE_COMPUTED_NAN
662 do {
663 /* Workaround for some exotic platforms where NAN is missing
664 * and the expression (0.0 / 0.0) does NOT result in a NaN.
665 * Such platforms use the global 'duk_computed_nan' which must
666 * be initialized at runtime. Use 'volatile' to ensure that
667 * the compiler will actually do the computation and not try
668 * to do constant folding which might result in the original
669 * problem.
670 */
671 volatile double dbl1 = 0.0;
672 volatile double dbl2 = 0.0;
673 duk_computed_nan = dbl1 / dbl2;
674 } while (0);
675 #endif
676
677 #ifdef DUK_USE_COMPUTED_INFINITY
678 do {
679 /* Similar workaround for INFINITY. */
680 volatile double dbl1 = 1.0;
681 volatile double dbl2 = 0.0;
682 duk_computed_infinity = dbl1 / dbl2;
683 } while (0);
684 #endif
685
686 /*
687 * Allocate heap struct
688 *
689 * Use a raw call, all macros expect the heap to be initialized
690 */
691
692 res = (duk_heap *) alloc_func(heap_udata, sizeof(duk_heap));
693 if (!res) {
694 goto error;
695 }
696
697 /*
698 * Zero the struct, and start initializing roughly in order
699 */
700
701 DUK_MEMZERO(res, sizeof(*res));
702
703 /* explicit NULL inits */
704 #ifdef DUK_USE_EXPLICIT_NULL_INIT
705 res->heap_udata = NULL;
706 res->heap_allocated = NULL;
707 #ifdef DUK_USE_REFERENCE_COUNTING
708 res->refzero_list = NULL;
709 res->refzero_list_tail = NULL;
710 #endif
711 #ifdef DUK_USE_MARK_AND_SWEEP
712 res->finalize_list = NULL;
713 #endif
714 res->heap_thread = NULL;
715 res->curr_thread = NULL;
716 res->heap_object = NULL;
717 #if defined(DUK_USE_STRTAB_CHAIN)
718 /* nothing to NULL */
719 #elif defined(DUK_USE_STRTAB_PROBE)
720 #if defined(DUK_USE_HEAPPTR16)
721 res->strtable16 = (duk_uint16_t *) NULL;
722 #else
723 res->strtable = (duk_hstring **) NULL;
724 #endif
725 #endif
726 #if defined(DUK_USE_HEAPPTR16)
727 /* res->strs16[] is zeroed and zero decodes to NULL, so no NULL inits. */
728 #else
729 {
730 duk_small_uint_t i;
731 for (i = 0; i < DUK_HEAP_NUM_STRINGS; i++) {
732 res->strs[i] = NULL;
733 }
734 }
735 #endif
736 #if defined(DUK_USE_DEBUGGER_SUPPORT)
737 res->dbg_read_cb = NULL;
738 res->dbg_write_cb = NULL;
739 res->dbg_peek_cb = NULL;
740 res->dbg_read_flush_cb = NULL;
741 res->dbg_write_flush_cb = NULL;
742 res->dbg_udata = NULL;
743 res->dbg_step_thread = NULL;
744 #endif
745 #endif /* DUK_USE_EXPLICIT_NULL_INIT */
746
747 res->alloc_func = alloc_func;
748 res->realloc_func = realloc_func;
749 res->free_func = free_func;
750 res->heap_udata = heap_udata;
751 res->fatal_func = fatal_func;
752
753 #if defined(DUK_USE_HEAPPTR16)
754 /* XXX: zero assumption */
755 res->heapptr_null16 = DUK_USE_HEAPPTR_ENC16(res->heap_udata, (void *) NULL);
756 res->heapptr_deleted16 = DUK_USE_HEAPPTR_ENC16(res->heap_udata, (void *) DUK_STRTAB_DELETED_MARKER(res));
757 #endif
758
759 /* res->mark_and_sweep_trigger_counter == 0 -> now causes immediate GC; which is OK */
760
761 res->call_recursion_depth = 0;
762 res->call_recursion_limit = DUK_USE_NATIVE_CALL_RECLIMIT;
763
764 /* XXX: use the pointer as a seed for now: mix in time at least */
765
766 /* The casts through duk_intr_pt is to avoid the following GCC warning:
767 *
768 * warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
769 *
770 * This still generates a /Wp64 warning on VS2010 when compiling for x86.
771 */
772 res->hash_seed = (duk_uint32_t) (duk_intptr_t) res;
773 res->rnd_state = (duk_uint32_t) (duk_intptr_t) res;
774
775 #ifdef DUK_USE_EXPLICIT_NULL_INIT
776 res->lj.jmpbuf_ptr = NULL;
777 #endif
778 DUK_ASSERT(res->lj.type == DUK_LJ_TYPE_UNKNOWN); /* zero */
779
780 DUK_TVAL_SET_UNDEFINED_UNUSED(&res->lj.value1);
781 DUK_TVAL_SET_UNDEFINED_UNUSED(&res->lj.value2);
782
783 #if (DUK_STRTAB_INITIAL_SIZE < DUK_UTIL_MIN_HASH_PRIME)
784 #error initial heap stringtable size is defined incorrectly
785 #endif
786
787 /*
788 * Init stringtable: fixed variant
789 */
790
791 #if defined(DUK_USE_STRTAB_CHAIN)
792 DUK_MEMZERO(res->strtable, sizeof(duk_strtab_entry) * DUK_STRTAB_CHAIN_SIZE);
793 #ifdef DUK_USE_EXPLICIT_NULL_INIT
794 {
795 duk_small_uint_t i;
796 for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) {
797 #if defined(DUK_USE_HEAPPTR16)
798 res->strtable[i].u.str16 = res->heapptr_null16;
799 #else
800 res->strtable[i].u.str = NULL;
801 #endif
802 }
803 }
804 #endif /* DUK_USE_EXPLICIT_NULL_INIT */
805 #endif /* DUK_USE_STRTAB_CHAIN */
806
807 /*
808 * Init stringtable: probe variant
809 */
810
811 #if defined(DUK_USE_STRTAB_PROBE)
812 #if defined(DUK_USE_HEAPPTR16)
813 res->strtable16 = (duk_uint16_t *) alloc_func(heap_udata, sizeof(duk_uint16_t) * DUK_STRTAB_INITIAL_SIZE);
814 if (!res->strtable16) {
815 goto error;
816 }
817 #else /* DUK_USE_HEAPPTR16 */
818 res->strtable = (duk_hstring **) alloc_func(heap_udata, sizeof(duk_hstring *) * DUK_STRTAB_INITIAL_SIZE);
819 if (!res->strtable) {
820 goto error;
821 }
822 #endif /* DUK_USE_HEAPPTR16 */
823 res->st_size = DUK_STRTAB_INITIAL_SIZE;
824 #ifdef DUK_USE_EXPLICIT_NULL_INIT
825 {
826 duk_small_uint_t i;
827 DUK_ASSERT(res->st_size == DUK_STRTAB_INITIAL_SIZE);
828 for (i = 0; i < DUK_STRTAB_INITIAL_SIZE; i++) {
829 #if defined(DUK_USE_HEAPPTR16)
830 res->strtable16[i] = res->heapptr_null16;
831 #else
832 res->strtable[i] = NULL;
833 #endif
834 }
835 }
836 #else /* DUK_USE_EXPLICIT_NULL_INIT */
837 #if defined(DUK_USE_HEAPPTR16)
838 DUK_MEMZERO(res->strtable16, sizeof(duk_uint16_t) * DUK_STRTAB_INITIAL_SIZE);
839 #else
840 DUK_MEMZERO(res->strtable, sizeof(duk_hstring *) * DUK_STRTAB_INITIAL_SIZE);
841 #endif
842 #endif /* DUK_USE_EXPLICIT_NULL_INIT */
843 #endif /* DUK_USE_STRTAB_PROBE */
844
845 /*
846 * Init stringcache
847 */
848
849 #ifdef DUK_USE_EXPLICIT_NULL_INIT
850 {
851 duk_small_uint_t i;
852 for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
853 res->strcache[i].h = NULL;
854 }
855 }
856 #endif
857
858 /* XXX: error handling is incomplete. It would be cleanest if
859 * there was a setjmp catchpoint, so that all init code could
860 * freely throw errors. If that were the case, the return code
861 * passing here could be removed.
862 */
863
864 /*
865 * Init built-in strings
866 */
867
868 DUK_DD(DUK_DDPRINT("HEAP: INIT STRINGS"));
869 if (!duk__init_heap_strings(res)) {
870 goto error;
871 }
872
873 /*
874 * Init the heap thread
875 */
876
877 DUK_DD(DUK_DDPRINT("HEAP: INIT HEAP THREAD"));
878 if (!duk__init_heap_thread(res)) {
879 goto error;
880 }
881
882 /*
883 * Init the heap object
884 */
885
886 DUK_DD(DUK_DDPRINT("HEAP: INIT HEAP OBJECT"));
887 DUK_ASSERT(res->heap_thread != NULL);
888 res->heap_object = duk_hobject_alloc(res, DUK_HOBJECT_FLAG_EXTENSIBLE |
889 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT));
890 if (!res->heap_object) {
891 goto error;
892 }
893 DUK_HOBJECT_INCREF(res->heap_thread, res->heap_object);
894
895 /*
896 * All done
897 */
898
899 DUK_D(DUK_DPRINT("allocated heap: %p", (void *) res));
900 return res;
901
902 error:
903 DUK_D(DUK_DPRINT("heap allocation failed"));
904
905 if (res) {
906 /* assumes that allocated pointers and alloc funcs are valid
907 * if res exists
908 */
909 DUK_ASSERT(res->alloc_func != NULL);
910 DUK_ASSERT(res->realloc_func != NULL);
911 DUK_ASSERT(res->free_func != NULL);
912 duk_heap_free(res);
913 }
914 return NULL;
915 }