forked from svaarala/duktape
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathconcepts.html
More file actions
179 lines (143 loc) · 7.02 KB
/
concepts.html
File metadata and controls
179 lines (143 loc) · 7.02 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
<h1 id="concepts">Concepts</h1>
<h2>Heap</h2>
<p>A single region for garbage collection. Shared by one or more
contexts.</p>
<h2>Context</h2>
<p>A handle used in the Duktape API, associated with a Duktape thread
(coroutine) and its call and value stacks.</p>
<h2>Call stack (of a context)</h2>
<p>Book-keeping of the active function call chain of a context.
Includes both ECMAScript and Duktape/C function calls.</p>
<h2>Value stack (of a context)</h2>
<p>Storage for tagged values belonging to current activations in a
context's call stack.</p>
<p>The values kept in a value stack are traditional tagged <a href="#stack-type">types</a>.
Stack entries are indexed either from the bottom (>= 0) or from the top
(< 0) of the most recent function call.
</p>
<h2>Value stack index</h2>
<p>Non-negative (>= 0) indices refer to stack entries in the
current stack frame, relative to the frame bottom:</p>
<pre class="stack">
[ 0 1 2 3 4 5! ]
</pre>
<p>Negative (< 0) indices refer to stack entries relative to the top:</p>
<pre class="stack">
[ -6 -5 -4 -3 -2 -1! ]
</pre>
<p>The special constant <code>DUK_INVALID_INDEX</code> is a negative integer
which denotes an invalid stack index. It can be returned from API calls
and can also be given to some API calls to indicate a "no value".</p>
<p>The <i>value stack top</i> (or just "top") is the non-negative index of
an imaginary element just above the highest used index. For instance, above
the highest used index is 5, so the stack top is 6. The top indicates the
current stack size, and is also the index of the next element pushed to the
stack.</p>
<pre class="stack">
[ 0 1 2 3 4 5! 6? ]
</pre>
<div class="note">
<p>API stack operations are always confined to the current stack frame.
There is no way to refer to stack entries below the current frame. This
is intentional, as it protects functions in the call stack from affecting
each other's values.</p>
</div>
<h2 id="stack-type">Stack type</h2>
<div class="table-wrap">
<table>
<tr class="header"><th>Type</th><th>Type constant</th><th>Type mask constant</th><th>Description</th><th>Heap alloc</th></tr>
<tr><td>(none)</td><td>DUK_TYPE_NONE</td><td>DUK_TYPE_MASK_NONE</td><td>no type (missing value, invalid index, etc)</td><td>no</td></tr>
<tr><td>undefined</td><td>DUK_TYPE_UNDEFINED</td><td>DUK_TYPE_MASK_UNDEFINED</td><td><code>undefined</code></td><td>no</td></tr>
<tr><td>null</td><td>DUK_TYPE_NULL</td><td>DUK_TYPE_MASK_NULL</td><td><code>null</code></td><td>no</td></tr>
<tr><td>boolean</td><td>DUK_TYPE_BOOLEAN</td><td>DUK_TYPE_MASK_BOOLEAN</td><td><code>true</code> and <code>false</code></td><td>no</td></tr>
<tr><td>number</td><td>DUK_TYPE_NUMBER</td><td>DUK_TYPE_MASK_NUMBER</td><td>IEEE double</td><td>no</td></tr>
<tr><td>string</td><td>DUK_TYPE_STRING</td><td>DUK_TYPE_MASK_STRING</td><td>immutable string</td><td>yes</td></tr>
<tr><td>object</td><td>DUK_TYPE_OBJECT</td><td>DUK_TYPE_MASK_OBJECT</td><td>object with properties</td><td>yes</td></tr>
<tr><td>buffer</td><td>DUK_TYPE_BUFFER</td><td>DUK_TYPE_MASK_BUFFER</td><td>mutable byte buffer, fixed/dynamic</td><td>yes</td></tr>
<tr><td>pointer</td><td>DUK_TYPE_POINTER</td><td>DUK_TYPE_MASK_POINTER</td><td>opaque pointer (void *)</td><td>no</td></tr>
<tr><td>lightfunc</td><td>DUK_TYPE_LIGHTFUNC</td><td>DUK_TYPE_MASK_LIGHTFUNC</td><td>plain Duktape/C pointer (non-object)</td><td>no</td></tr>
</table>
</div>
<p>The "Heap alloc" column indicates whether the tagged value points to
a heap allocated object with possibly additional allocations (like object
property table).</p>
<h2>Stack type mask</h2>
<p>Each stack type has a bit index which allows a set of stack types to be
represented as a bit mask. Calling code can use such bit sets to e.g. check
whether or not a certain stack value belongs to a set of types. Example:</p>
<pre class="c-code">
if (duk_get_type_mask(ctx, -3) & (DUK_TYPE_MASK_NUMBER |
DUK_TYPE_MASK_STRING |
DUK_TYPE_MASK_OBJECT)) {
printf("type is number, string, or object\n");
}
</pre>
<p>There is a specific API call for matching a set of types even more
conveniently:</p>
<pre class="c-code">
if (duk_check_type_mask(ctx, -3, DUK_TYPE_MASK_NUMBER |
DUK_TYPE_MASK_STRING |
DUK_TYPE_MASK_OBJECT)) {
printf("type is number, string, or object\n");
}
</pre>
<h2>Array index</h2>
<p>ECMAScript object and array keys can only be strings; this includes
array indices (0, 1, 2, ...) which are expressed as canonical string
representations ("0", "1", "2", ...) of the respective numbers for all
integers in the range [0, 2**32-2]. Conceptually any key used in a
property lookup is first coerced to a string, so that <code>obj[123]</code>
is really just a shorthand for <code>obj["123"]</code>.</p>
<p>Duktape tries to avoid explicit number-to-string conversions for array
accesses whenever possible, so it is preferable to use numeric array
indices in both ECMAScript code and C code using the Duktape API. There
are typically API call variants accepting strings and numeric indices.</p>
<h2>Duktape/C function</h2>
<p>A C function with a Duktape/C API signature can be associated with an
ECMAScript function object or a lightfunc value, and gets called when
the associated value is called from ECMAScript code. Example:</p>
<pre class="c-code">
duk_ret_t my_func(duk_context *ctx) {
duk_push_int(ctx, 123);
return 1;
}
</pre>
<p>Argument count given in value stack is specified when the corresponding
ECMAScript function object is created: either a fixed number of arguments
of <code>DUK_VARARGS</code> for getting arguments "as is":
<p>
<ul>
<li>When using a fixed number of arguments, extra arguments are dropped and
missing arguments padded with <code>undefined</code> as necessary.</li>
<li>When using <code>DUK_VARARGS</code>, use
<code><a href="#duk_get_top">duk_get_top()</a></code> to determine the
number of actual arguments.</li>
</ul>
<p>Function return values:</p>
<ul>
<li>Return value 1: stack top contains return value.</li>
<li>Return value 0: return value is <code>undefined</code>.</li>
<li>Return value <0: shorthand for throwing errors, use <code>DUK_RET_xxx</code>
constants which are negative variants of <code>DUK_ERR_xxx</code>.</li>
<li>Return value >1: reserved, currently invalid.</li>
</ul>
<p>No error message can be given when using the error shorthand:</p>
<pre class="c-code">
duk_ret_t my_func(duk_context *ctx) {
if (duk_get_top(ctx) == 0) {
/* throw TypeError if no arguments given */
return DUK_RET_TYPE_ERROR;
}
/* ... */
}
</pre>
<h2>Stashes</h2>
<p>A stash is an object reachable from C code using the Duktape/C API, but
which is unreachable from ECMAScript code. Stashes allow C code to store
internal state which can be safely isolated from ECMAScript code. There are
three stashes:</p>
<ul>
<li>Heap stash: shared by all threads in the same heap.</li>
<li>Global stash: shared by all threads which share a global object.</li>
<li>Thread stash: specific to a certain thread.</li>
</ul>