1 #include "be_inl.h"
2 
3 /*
4  * Create a global array refs in the heap stash.
5  */
be_ref_setup(duk_context * ctx)6 void be_ref_setup(duk_context *ctx)
7 {
8     duk_push_heap_stash(ctx);
9 
10     /* Create a new array with one `0` at index `0`. */
11     duk_push_array(ctx);
12     duk_push_int(ctx, 0);
13     duk_put_prop_index(ctx, -2, 0);
14     /* Store it as "refs" in the heap stash */
15     duk_put_prop_string(ctx, -2, "refs");
16 
17     duk_pop(ctx);
18 }
19 
be_ref(duk_context * ctx)20 int be_ref(duk_context *ctx)
21 {
22     int ref;
23     if (duk_is_undefined(ctx, -1)) {
24         duk_pop(ctx);
25         return 0;
26     }
27     /* Get the "refs" array in the heap stash */
28     duk_push_heap_stash(ctx);
29     duk_get_prop_string(ctx, -1, "refs");
30     duk_remove(ctx, -2);
31 
32     /* ref = refs[0] */
33     duk_get_prop_index(ctx, -1, 0);
34     ref = duk_get_int(ctx, -1);
35     duk_pop(ctx);
36 
37     /* If there was a free slot, remove it from the list */
38     if (ref != 0) {
39         /* refs[0] = refs[ref] */
40         duk_get_prop_index(ctx, -1, ref);
41         duk_put_prop_index(ctx, -2, 0);
42     }
43     /* Otherwise use the end of the list */
44     else {
45         /* ref = refs.length; */
46         ref = duk_get_length(ctx, -1);
47     }
48 
49     /* swap the array and the user value in the stack */
50     duk_insert(ctx, -2);
51 
52     /* refs[ref] = value */
53     duk_put_prop_index(ctx, -2, ref);
54 
55     /* Remove the refs array from the stack. */
56     duk_pop(ctx);
57 
58     return ref;
59 }
60 
be_push_ref(duk_context * ctx,int ref)61 void be_push_ref(duk_context *ctx, int ref)
62 {
63     if (!ref) {
64         duk_push_undefined(ctx);
65         return;
66     }
67     /* Get the "refs" array in the heap stash */
68     duk_push_heap_stash(ctx);
69     duk_get_prop_string(ctx, -1, "refs");
70     duk_remove(ctx, -2);
71 
72     duk_get_prop_index(ctx, -1, ref);
73 
74     duk_remove(ctx, -2);
75 }
76 
be_unref(duk_context * ctx,int ref)77 void be_unref(duk_context *ctx, int ref)
78 {
79     if (!ref) return;
80 
81     /* Get the "refs" array in the heap stash */
82     duk_push_heap_stash(ctx);
83     duk_get_prop_string(ctx, -1, "refs");
84     duk_remove(ctx, -2);
85 
86     /* Insert a new link in the freelist */
87 
88     /* refs[ref] = refs[0] */
89     duk_get_prop_index(ctx, -1, 0);
90     duk_put_prop_index(ctx, -2, ref);
91     /* refs[0] = ref */
92     duk_push_int(ctx, ref);
93     duk_put_prop_index(ctx, -2, 0);
94 
95     duk_pop(ctx);
96 }
97