]>
Commit | Line | Data |
---|---|---|
1e59de90 TL |
1 | /* |
2 | * Heap object representation. | |
3 | * | |
4 | * Heap objects are used for Ecmascript objects, arrays, and functions, | |
5 | * but also for internal control like declarative and object environment | |
6 | * records. Compiled functions, native functions, and threads are also | |
7 | * objects but with an extended C struct. | |
8 | * | |
9 | * Objects provide the required Ecmascript semantics and exotic behaviors | |
10 | * especially for property access. | |
11 | * | |
12 | * Properties are stored in three conceptual parts: | |
13 | * | |
14 | * 1. A linear 'entry part' contains ordered key-value-attributes triples | |
15 | * and is the main method of string properties. | |
16 | * | |
17 | * 2. An optional linear 'array part' is used for array objects to store a | |
18 | * (dense) range of [0,N[ array indexed entries with default attributes | |
19 | * (writable, enumerable, configurable). If the array part would become | |
20 | * sparse or non-default attributes are required, the array part is | |
21 | * abandoned and moved to the 'entry part'. | |
22 | * | |
23 | * 3. An optional 'hash part' is used to optimize lookups of the entry | |
24 | * part; it is used only for objects with sufficiently many properties | |
25 | * and can be abandoned without loss of information. | |
26 | * | |
27 | * These three conceptual parts are stored in a single memory allocated area. | |
28 | * This minimizes memory allocation overhead but also means that all three | |
29 | * parts are resized together, and makes property access a bit complicated. | |
30 | */ | |
31 | ||
32 | #ifndef DUK_HOBJECT_H_INCLUDED | |
33 | #define DUK_HOBJECT_H_INCLUDED | |
34 | ||
35 | /* Object flag. There are currently 26 flag bits available. Make sure | |
36 | * this stays in sync with debugger object inspection code. | |
37 | */ | |
38 | #define DUK_HOBJECT_FLAG_EXTENSIBLE DUK_HEAPHDR_USER_FLAG(0) /* object is extensible */ | |
39 | #define DUK_HOBJECT_FLAG_CONSTRUCTABLE DUK_HEAPHDR_USER_FLAG(1) /* object is constructable */ | |
40 | #define DUK_HOBJECT_FLAG_BOUND DUK_HEAPHDR_USER_FLAG(2) /* object established using Function.prototype.bind() */ | |
41 | #define DUK_HOBJECT_FLAG_COMPILEDFUNCTION DUK_HEAPHDR_USER_FLAG(4) /* object is a compiled function (duk_hcompiledfunction) */ | |
42 | #define DUK_HOBJECT_FLAG_NATIVEFUNCTION DUK_HEAPHDR_USER_FLAG(5) /* object is a native function (duk_hnativefunction) */ | |
43 | #define DUK_HOBJECT_FLAG_BUFFEROBJECT DUK_HEAPHDR_USER_FLAG(6) /* object is a buffer object (duk_hbufferobject) (always exotic) */ | |
44 | #define DUK_HOBJECT_FLAG_THREAD DUK_HEAPHDR_USER_FLAG(7) /* object is a thread (duk_hthread) */ | |
45 | #define DUK_HOBJECT_FLAG_ARRAY_PART DUK_HEAPHDR_USER_FLAG(8) /* object has an array part (a_size may still be 0) */ | |
46 | #define DUK_HOBJECT_FLAG_STRICT DUK_HEAPHDR_USER_FLAG(9) /* function: function object is strict */ | |
47 | #define DUK_HOBJECT_FLAG_NOTAIL DUK_HEAPHDR_USER_FLAG(10) /* function: function must not be tail called */ | |
48 | #define DUK_HOBJECT_FLAG_NEWENV DUK_HEAPHDR_USER_FLAG(11) /* function: create new environment when called (see duk_hcompiledfunction) */ | |
49 | #define DUK_HOBJECT_FLAG_NAMEBINDING DUK_HEAPHDR_USER_FLAG(12) /* function: create binding for func name (function templates only, used for named function expressions) */ | |
50 | #define DUK_HOBJECT_FLAG_CREATEARGS DUK_HEAPHDR_USER_FLAG(13) /* function: create an arguments object on function call */ | |
51 | #define DUK_HOBJECT_FLAG_ENVRECCLOSED DUK_HEAPHDR_USER_FLAG(14) /* envrec: (declarative) record is closed */ | |
52 | #define DUK_HOBJECT_FLAG_EXOTIC_ARRAY DUK_HEAPHDR_USER_FLAG(15) /* 'Array' object, array length and index exotic behavior */ | |
53 | #define DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ DUK_HEAPHDR_USER_FLAG(16) /* 'String' object, array index exotic behavior */ | |
54 | #define DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS DUK_HEAPHDR_USER_FLAG(17) /* 'Arguments' object and has arguments exotic behavior (non-strict callee) */ | |
55 | #define DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC DUK_HEAPHDR_USER_FLAG(18) /* Duktape/C (nativefunction) object, exotic 'length' */ | |
56 | #define DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ DUK_HEAPHDR_USER_FLAG(19) /* 'Proxy' object */ | |
57 | ||
58 | #define DUK_HOBJECT_FLAG_CLASS_BASE DUK_HEAPHDR_USER_FLAG_NUMBER(20) | |
59 | #define DUK_HOBJECT_FLAG_CLASS_BITS 5 | |
60 | ||
61 | #define DUK_HOBJECT_GET_CLASS_NUMBER(h) \ | |
62 | DUK_HEAPHDR_GET_FLAG_RANGE(&(h)->hdr, DUK_HOBJECT_FLAG_CLASS_BASE, DUK_HOBJECT_FLAG_CLASS_BITS) | |
63 | #define DUK_HOBJECT_SET_CLASS_NUMBER(h,v) \ | |
64 | DUK_HEAPHDR_SET_FLAG_RANGE(&(h)->hdr, DUK_HOBJECT_FLAG_CLASS_BASE, DUK_HOBJECT_FLAG_CLASS_BITS, (v)) | |
65 | ||
66 | #define DUK_HOBJECT_GET_CLASS_MASK(h) \ | |
67 | (1UL << DUK_HEAPHDR_GET_FLAG_RANGE(&(h)->hdr, DUK_HOBJECT_FLAG_CLASS_BASE, DUK_HOBJECT_FLAG_CLASS_BITS)) | |
68 | ||
69 | /* Macro for creating flag initializer from a class number. | |
70 | * Unsigned type cast is needed to avoid warnings about coercing | |
71 | * a signed integer to an unsigned one; the largest class values | |
72 | * have the highest bit (bit 31) set which causes this. | |
73 | */ | |
74 | #define DUK_HOBJECT_CLASS_AS_FLAGS(v) (((duk_uint_t) (v)) << DUK_HOBJECT_FLAG_CLASS_BASE) | |
75 | ||
76 | /* E5 Section 8.6.2 + custom classes */ | |
77 | #define DUK_HOBJECT_CLASS_UNUSED 0 | |
78 | #define DUK_HOBJECT_CLASS_ARGUMENTS 1 | |
79 | #define DUK_HOBJECT_CLASS_ARRAY 2 | |
80 | #define DUK_HOBJECT_CLASS_BOOLEAN 3 | |
81 | #define DUK_HOBJECT_CLASS_DATE 4 | |
82 | #define DUK_HOBJECT_CLASS_ERROR 5 | |
83 | #define DUK_HOBJECT_CLASS_FUNCTION 6 | |
84 | #define DUK_HOBJECT_CLASS_JSON 7 | |
85 | #define DUK_HOBJECT_CLASS_MATH 8 | |
86 | #define DUK_HOBJECT_CLASS_NUMBER 9 | |
87 | #define DUK_HOBJECT_CLASS_OBJECT 10 | |
88 | #define DUK_HOBJECT_CLASS_REGEXP 11 | |
89 | #define DUK_HOBJECT_CLASS_STRING 12 | |
90 | #define DUK_HOBJECT_CLASS_GLOBAL 13 | |
91 | #define DUK_HOBJECT_CLASS_OBJENV 14 /* custom */ | |
92 | #define DUK_HOBJECT_CLASS_DECENV 15 /* custom */ | |
93 | #define DUK_HOBJECT_CLASS_BUFFER 16 /* custom; implies DUK_HOBJECT_IS_BUFFEROBJECT */ | |
94 | #define DUK_HOBJECT_CLASS_POINTER 17 /* custom */ | |
95 | #define DUK_HOBJECT_CLASS_THREAD 18 /* custom; implies DUK_HOBJECT_IS_THREAD */ | |
96 | #define DUK_HOBJECT_CLASS_ARRAYBUFFER 19 /* implies DUK_HOBJECT_IS_BUFFEROBJECT */ | |
97 | #define DUK_HOBJECT_CLASS_DATAVIEW 20 | |
98 | #define DUK_HOBJECT_CLASS_INT8ARRAY 21 | |
99 | #define DUK_HOBJECT_CLASS_UINT8ARRAY 22 | |
100 | #define DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY 23 | |
101 | #define DUK_HOBJECT_CLASS_INT16ARRAY 24 | |
102 | #define DUK_HOBJECT_CLASS_UINT16ARRAY 25 | |
103 | #define DUK_HOBJECT_CLASS_INT32ARRAY 26 | |
104 | #define DUK_HOBJECT_CLASS_UINT32ARRAY 27 | |
105 | #define DUK_HOBJECT_CLASS_FLOAT32ARRAY 28 | |
106 | #define DUK_HOBJECT_CLASS_FLOAT64ARRAY 29 | |
107 | #define DUK_HOBJECT_CLASS_MAX 29 | |
108 | ||
109 | /* class masks */ | |
110 | #define DUK_HOBJECT_CMASK_ALL ((1UL << (DUK_HOBJECT_CLASS_MAX + 1)) - 1UL) | |
111 | #define DUK_HOBJECT_CMASK_UNUSED (1UL << DUK_HOBJECT_CLASS_UNUSED) | |
112 | #define DUK_HOBJECT_CMASK_ARGUMENTS (1UL << DUK_HOBJECT_CLASS_ARGUMENTS) | |
113 | #define DUK_HOBJECT_CMASK_ARRAY (1UL << DUK_HOBJECT_CLASS_ARRAY) | |
114 | #define DUK_HOBJECT_CMASK_BOOLEAN (1UL << DUK_HOBJECT_CLASS_BOOLEAN) | |
115 | #define DUK_HOBJECT_CMASK_DATE (1UL << DUK_HOBJECT_CLASS_DATE) | |
116 | #define DUK_HOBJECT_CMASK_ERROR (1UL << DUK_HOBJECT_CLASS_ERROR) | |
117 | #define DUK_HOBJECT_CMASK_FUNCTION (1UL << DUK_HOBJECT_CLASS_FUNCTION) | |
118 | #define DUK_HOBJECT_CMASK_JSON (1UL << DUK_HOBJECT_CLASS_JSON) | |
119 | #define DUK_HOBJECT_CMASK_MATH (1UL << DUK_HOBJECT_CLASS_MATH) | |
120 | #define DUK_HOBJECT_CMASK_NUMBER (1UL << DUK_HOBJECT_CLASS_NUMBER) | |
121 | #define DUK_HOBJECT_CMASK_OBJECT (1UL << DUK_HOBJECT_CLASS_OBJECT) | |
122 | #define DUK_HOBJECT_CMASK_REGEXP (1UL << DUK_HOBJECT_CLASS_REGEXP) | |
123 | #define DUK_HOBJECT_CMASK_STRING (1UL << DUK_HOBJECT_CLASS_STRING) | |
124 | #define DUK_HOBJECT_CMASK_GLOBAL (1UL << DUK_HOBJECT_CLASS_GLOBAL) | |
125 | #define DUK_HOBJECT_CMASK_OBJENV (1UL << DUK_HOBJECT_CLASS_OBJENV) | |
126 | #define DUK_HOBJECT_CMASK_DECENV (1UL << DUK_HOBJECT_CLASS_DECENV) | |
127 | #define DUK_HOBJECT_CMASK_BUFFER (1UL << DUK_HOBJECT_CLASS_BUFFER) | |
128 | #define DUK_HOBJECT_CMASK_POINTER (1UL << DUK_HOBJECT_CLASS_POINTER) | |
129 | #define DUK_HOBJECT_CMASK_THREAD (1UL << DUK_HOBJECT_CLASS_THREAD) | |
130 | #define DUK_HOBJECT_CMASK_ARRAYBUFFER (1UL << DUK_HOBJECT_CLASS_ARRAYBUFFER) | |
131 | #define DUK_HOBJECT_CMASK_DATAVIEW (1UL << DUK_HOBJECT_CLASS_DATAVIEW) | |
132 | #define DUK_HOBJECT_CMASK_INT8ARRAY (1UL << DUK_HOBJECT_CLASS_INT8ARRAY) | |
133 | #define DUK_HOBJECT_CMASK_UINT8ARRAY (1UL << DUK_HOBJECT_CLASS_UINT8ARRAY) | |
134 | #define DUK_HOBJECT_CMASK_UINT8CLAMPEDARRAY (1UL << DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY) | |
135 | #define DUK_HOBJECT_CMASK_INT16ARRAY (1UL << DUK_HOBJECT_CLASS_INT16ARRAY) | |
136 | #define DUK_HOBJECT_CMASK_UINT16ARRAY (1UL << DUK_HOBJECT_CLASS_UINT16ARRAY) | |
137 | #define DUK_HOBJECT_CMASK_INT32ARRAY (1UL << DUK_HOBJECT_CLASS_INT32ARRAY) | |
138 | #define DUK_HOBJECT_CMASK_UINT32ARRAY (1UL << DUK_HOBJECT_CLASS_UINT32ARRAY) | |
139 | #define DUK_HOBJECT_CMASK_FLOAT32ARRAY (1UL << DUK_HOBJECT_CLASS_FLOAT32ARRAY) | |
140 | #define DUK_HOBJECT_CMASK_FLOAT64ARRAY (1UL << DUK_HOBJECT_CLASS_FLOAT64ARRAY) | |
141 | ||
142 | #define DUK_HOBJECT_CMASK_ALL_BUFFEROBJECTS \ | |
143 | (DUK_HOBJECT_CMASK_BUFFER | \ | |
144 | DUK_HOBJECT_CMASK_ARRAYBUFFER | \ | |
145 | DUK_HOBJECT_CMASK_DATAVIEW | \ | |
146 | DUK_HOBJECT_CMASK_INT8ARRAY | \ | |
147 | DUK_HOBJECT_CMASK_UINT8ARRAY | \ | |
148 | DUK_HOBJECT_CMASK_UINT8CLAMPEDARRAY | \ | |
149 | DUK_HOBJECT_CMASK_INT16ARRAY | \ | |
150 | DUK_HOBJECT_CMASK_UINT16ARRAY | \ | |
151 | DUK_HOBJECT_CMASK_INT32ARRAY | \ | |
152 | DUK_HOBJECT_CMASK_UINT32ARRAY | \ | |
153 | DUK_HOBJECT_CMASK_FLOAT32ARRAY | \ | |
154 | DUK_HOBJECT_CMASK_FLOAT64ARRAY) | |
155 | ||
156 | #define DUK_HOBJECT_IS_OBJENV(h) (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_OBJENV) | |
157 | #define DUK_HOBJECT_IS_DECENV(h) (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_DECENV) | |
158 | #define DUK_HOBJECT_IS_ENV(h) (DUK_HOBJECT_IS_OBJENV((h)) || DUK_HOBJECT_IS_DECENV((h))) | |
159 | #define DUK_HOBJECT_IS_ARRAY(h) (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_ARRAY) | |
160 | #define DUK_HOBJECT_IS_COMPILEDFUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPILEDFUNCTION) | |
161 | #define DUK_HOBJECT_IS_NATIVEFUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATIVEFUNCTION) | |
162 | #define DUK_HOBJECT_IS_BUFFEROBJECT(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFFEROBJECT) | |
163 | #define DUK_HOBJECT_IS_THREAD(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD) | |
164 | ||
165 | #define DUK_HOBJECT_IS_NONBOUND_FUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, \ | |
166 | DUK_HOBJECT_FLAG_COMPILEDFUNCTION | \ | |
167 | DUK_HOBJECT_FLAG_NATIVEFUNCTION) | |
168 | ||
169 | #define DUK_HOBJECT_IS_FUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, \ | |
170 | DUK_HOBJECT_FLAG_BOUND | \ | |
171 | DUK_HOBJECT_FLAG_COMPILEDFUNCTION | \ | |
172 | DUK_HOBJECT_FLAG_NATIVEFUNCTION) | |
173 | ||
174 | #define DUK_HOBJECT_IS_CALLABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, \ | |
175 | DUK_HOBJECT_FLAG_BOUND | \ | |
176 | DUK_HOBJECT_FLAG_COMPILEDFUNCTION | \ | |
177 | DUK_HOBJECT_FLAG_NATIVEFUNCTION) | |
178 | ||
179 | /* object has any exotic behavior(s) */ | |
180 | #define DUK_HOBJECT_EXOTIC_BEHAVIOR_FLAGS (DUK_HOBJECT_FLAG_EXOTIC_ARRAY | \ | |
181 | DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS | \ | |
182 | DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ | \ | |
183 | DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC | \ | |
184 | DUK_HOBJECT_FLAG_BUFFEROBJECT | \ | |
185 | DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ) | |
186 | ||
187 | #define DUK_HOBJECT_HAS_EXOTIC_BEHAVIOR(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_EXOTIC_BEHAVIOR_FLAGS) | |
188 | ||
189 | #define DUK_HOBJECT_HAS_EXTENSIBLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE) | |
190 | #define DUK_HOBJECT_HAS_CONSTRUCTABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE) | |
191 | #define DUK_HOBJECT_HAS_BOUND(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUND) | |
192 | #define DUK_HOBJECT_HAS_COMPILEDFUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPILEDFUNCTION) | |
193 | #define DUK_HOBJECT_HAS_NATIVEFUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATIVEFUNCTION) | |
194 | #define DUK_HOBJECT_HAS_BUFFEROBJECT(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFFEROBJECT) | |
195 | #define DUK_HOBJECT_HAS_THREAD(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD) | |
196 | #define DUK_HOBJECT_HAS_ARRAY_PART(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART) | |
197 | #define DUK_HOBJECT_HAS_STRICT(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT) | |
198 | #define DUK_HOBJECT_HAS_NOTAIL(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NOTAIL) | |
199 | #define DUK_HOBJECT_HAS_NEWENV(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NEWENV) | |
200 | #define DUK_HOBJECT_HAS_NAMEBINDING(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NAMEBINDING) | |
201 | #define DUK_HOBJECT_HAS_CREATEARGS(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CREATEARGS) | |
202 | #define DUK_HOBJECT_HAS_ENVRECCLOSED(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ENVRECCLOSED) | |
203 | #define DUK_HOBJECT_HAS_EXOTIC_ARRAY(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARRAY) | |
204 | #define DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ) | |
205 | #define DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS) | |
206 | #define DUK_HOBJECT_HAS_EXOTIC_DUKFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC) | |
207 | #define DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ) | |
208 | ||
209 | #define DUK_HOBJECT_SET_EXTENSIBLE(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE) | |
210 | #define DUK_HOBJECT_SET_CONSTRUCTABLE(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE) | |
211 | #define DUK_HOBJECT_SET_BOUND(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUND) | |
212 | #define DUK_HOBJECT_SET_COMPILEDFUNCTION(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPILEDFUNCTION) | |
213 | #define DUK_HOBJECT_SET_NATIVEFUNCTION(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATIVEFUNCTION) | |
214 | #define DUK_HOBJECT_SET_BUFFEROBJECT(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFFEROBJECT) | |
215 | #define DUK_HOBJECT_SET_THREAD(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD) | |
216 | #define DUK_HOBJECT_SET_ARRAY_PART(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART) | |
217 | #define DUK_HOBJECT_SET_STRICT(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT) | |
218 | #define DUK_HOBJECT_SET_NOTAIL(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NOTAIL) | |
219 | #define DUK_HOBJECT_SET_NEWENV(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NEWENV) | |
220 | #define DUK_HOBJECT_SET_NAMEBINDING(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NAMEBINDING) | |
221 | #define DUK_HOBJECT_SET_CREATEARGS(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CREATEARGS) | |
222 | #define DUK_HOBJECT_SET_ENVRECCLOSED(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ENVRECCLOSED) | |
223 | #define DUK_HOBJECT_SET_EXOTIC_ARRAY(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARRAY) | |
224 | #define DUK_HOBJECT_SET_EXOTIC_STRINGOBJ(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ) | |
225 | #define DUK_HOBJECT_SET_EXOTIC_ARGUMENTS(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS) | |
226 | #define DUK_HOBJECT_SET_EXOTIC_DUKFUNC(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC) | |
227 | #define DUK_HOBJECT_SET_EXOTIC_PROXYOBJ(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ) | |
228 | ||
229 | #define DUK_HOBJECT_CLEAR_EXTENSIBLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE) | |
230 | #define DUK_HOBJECT_CLEAR_CONSTRUCTABLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE) | |
231 | #define DUK_HOBJECT_CLEAR_BOUND(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUND) | |
232 | #define DUK_HOBJECT_CLEAR_COMPILEDFUNCTION(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPILEDFUNCTION) | |
233 | #define DUK_HOBJECT_CLEAR_NATIVEFUNCTION(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATIVEFUNCTION) | |
234 | #define DUK_HOBJECT_CLEAR_BUFFEROBJECT(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFFEROBJECT) | |
235 | #define DUK_HOBJECT_CLEAR_THREAD(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD) | |
236 | #define DUK_HOBJECT_CLEAR_ARRAY_PART(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART) | |
237 | #define DUK_HOBJECT_CLEAR_STRICT(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT) | |
238 | #define DUK_HOBJECT_CLEAR_NOTAIL(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NOTAIL) | |
239 | #define DUK_HOBJECT_CLEAR_NEWENV(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NEWENV) | |
240 | #define DUK_HOBJECT_CLEAR_NAMEBINDING(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NAMEBINDING) | |
241 | #define DUK_HOBJECT_CLEAR_CREATEARGS(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CREATEARGS) | |
242 | #define DUK_HOBJECT_CLEAR_ENVRECCLOSED(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ENVRECCLOSED) | |
243 | #define DUK_HOBJECT_CLEAR_EXOTIC_ARRAY(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARRAY) | |
244 | #define DUK_HOBJECT_CLEAR_EXOTIC_STRINGOBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ) | |
245 | #define DUK_HOBJECT_CLEAR_EXOTIC_ARGUMENTS(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS) | |
246 | #define DUK_HOBJECT_CLEAR_EXOTIC_DUKFUNC(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC) | |
247 | #define DUK_HOBJECT_CLEAR_EXOTIC_PROXYOBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ) | |
248 | ||
249 | /* flags used for property attributes in duk_propdesc and packed flags */ | |
250 | #define DUK_PROPDESC_FLAG_WRITABLE (1 << 0) /* E5 Section 8.6.1 */ | |
251 | #define DUK_PROPDESC_FLAG_ENUMERABLE (1 << 1) /* E5 Section 8.6.1 */ | |
252 | #define DUK_PROPDESC_FLAG_CONFIGURABLE (1 << 2) /* E5 Section 8.6.1 */ | |
253 | #define DUK_PROPDESC_FLAG_ACCESSOR (1 << 3) /* accessor */ | |
254 | #define DUK_PROPDESC_FLAG_VIRTUAL (1 << 4) /* property is virtual: used in duk_propdesc, never stored | |
255 | * (used by e.g. buffer virtual properties) | |
256 | */ | |
257 | #define DUK_PROPDESC_FLAGS_MASK (DUK_PROPDESC_FLAG_WRITABLE | \ | |
258 | DUK_PROPDESC_FLAG_ENUMERABLE | \ | |
259 | DUK_PROPDESC_FLAG_CONFIGURABLE | \ | |
260 | DUK_PROPDESC_FLAG_ACCESSOR) | |
261 | ||
262 | /* additional flags which are passed in the same flags argument as property | |
263 | * flags but are not stored in object properties. | |
264 | */ | |
265 | #define DUK_PROPDESC_FLAG_NO_OVERWRITE (1 << 4) /* internal define property: skip write silently if exists */ | |
266 | ||
267 | /* convenience */ | |
268 | #define DUK_PROPDESC_FLAGS_NONE 0 | |
269 | #define DUK_PROPDESC_FLAGS_W (DUK_PROPDESC_FLAG_WRITABLE) | |
270 | #define DUK_PROPDESC_FLAGS_E (DUK_PROPDESC_FLAG_ENUMERABLE) | |
271 | #define DUK_PROPDESC_FLAGS_C (DUK_PROPDESC_FLAG_CONFIGURABLE) | |
272 | #define DUK_PROPDESC_FLAGS_WE (DUK_PROPDESC_FLAG_WRITABLE | DUK_PROPDESC_FLAG_ENUMERABLE) | |
273 | #define DUK_PROPDESC_FLAGS_WC (DUK_PROPDESC_FLAG_WRITABLE | DUK_PROPDESC_FLAG_CONFIGURABLE) | |
274 | #define DUK_PROPDESC_FLAGS_EC (DUK_PROPDESC_FLAG_ENUMERABLE | DUK_PROPDESC_FLAG_CONFIGURABLE) | |
275 | #define DUK_PROPDESC_FLAGS_WEC (DUK_PROPDESC_FLAG_WRITABLE | \ | |
276 | DUK_PROPDESC_FLAG_ENUMERABLE | \ | |
277 | DUK_PROPDESC_FLAG_CONFIGURABLE) | |
278 | ||
279 | /* flags for duk_hobject_get_own_propdesc() and variants */ | |
280 | #define DUK_GETDESC_FLAG_PUSH_VALUE (1 << 0) /* push value to stack */ | |
281 | #define DUK_GETDESC_FLAG_IGNORE_PROTOLOOP (1 << 1) /* don't throw for prototype loop */ | |
282 | ||
283 | /* | |
284 | * Macro for object validity check | |
285 | * | |
286 | * Assert for currently guaranteed relations between flags, for instance. | |
287 | */ | |
288 | ||
289 | #define DUK_ASSERT_HOBJECT_VALID(h) do { \ | |
290 | DUK_ASSERT((h) != NULL); \ | |
291 | DUK_ASSERT(!DUK_HOBJECT_IS_CALLABLE((h)) || \ | |
292 | DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_FUNCTION); \ | |
293 | DUK_ASSERT(!DUK_HOBJECT_IS_BUFFEROBJECT((h)) || \ | |
294 | (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_BUFFER || \ | |
295 | DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_ARRAYBUFFER || \ | |
296 | DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_DATAVIEW || \ | |
297 | DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_INT8ARRAY || \ | |
298 | DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_UINT8ARRAY || \ | |
299 | DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY || \ | |
300 | DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_INT16ARRAY || \ | |
301 | DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_UINT16ARRAY || \ | |
302 | DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_INT32ARRAY || \ | |
303 | DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_UINT32ARRAY || \ | |
304 | DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_FLOAT32ARRAY || \ | |
305 | DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_FLOAT64ARRAY)); \ | |
306 | } while (0) | |
307 | ||
308 | /* | |
309 | * Macros to access the 'props' allocation. | |
310 | */ | |
311 | ||
312 | #if defined(DUK_USE_HEAPPTR16) | |
313 | #define DUK_HOBJECT_GET_PROPS(heap,h) \ | |
314 | ((duk_uint8_t *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, ((duk_heaphdr *) (h))->h_extra16)) | |
315 | #define DUK_HOBJECT_SET_PROPS(heap,h,x) do { \ | |
316 | ((duk_heaphdr *) (h))->h_extra16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (x)); \ | |
317 | } while (0) | |
318 | #else | |
319 | #define DUK_HOBJECT_GET_PROPS(heap,h) \ | |
320 | ((h)->props) | |
321 | #define DUK_HOBJECT_SET_PROPS(heap,h,x) do { \ | |
322 | (h)->props = (duk_uint8_t *) (x); \ | |
323 | } while (0) | |
324 | #endif | |
325 | ||
326 | #if defined(DUK_USE_HOBJECT_LAYOUT_1) | |
327 | /* LAYOUT 1 */ | |
328 | #define DUK_HOBJECT_E_GET_KEY_BASE(heap,h) \ | |
329 | ((duk_hstring **) (void *) ( \ | |
330 | DUK_HOBJECT_GET_PROPS((heap), (h)) \ | |
331 | )) | |
332 | #define DUK_HOBJECT_E_GET_VALUE_BASE(heap,h) \ | |
333 | ((duk_propvalue *) (void *) ( \ | |
334 | DUK_HOBJECT_GET_PROPS((heap), (h)) + \ | |
335 | DUK_HOBJECT_GET_ESIZE((h)) * sizeof(duk_hstring *) \ | |
336 | )) | |
337 | #define DUK_HOBJECT_E_GET_FLAGS_BASE(heap,h) \ | |
338 | ((duk_uint8_t *) (void *) ( \ | |
339 | DUK_HOBJECT_GET_PROPS((heap), (h)) + DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue)) \ | |
340 | )) | |
341 | #define DUK_HOBJECT_A_GET_BASE(heap,h) \ | |
342 | ((duk_tval *) (void *) ( \ | |
343 | DUK_HOBJECT_GET_PROPS((heap), (h)) + \ | |
344 | DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) \ | |
345 | )) | |
346 | #define DUK_HOBJECT_H_GET_BASE(heap,h) \ | |
347 | ((duk_uint32_t *) (void *) ( \ | |
348 | DUK_HOBJECT_GET_PROPS((heap), (h)) + \ | |
349 | DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \ | |
350 | DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) \ | |
351 | )) | |
352 | #define DUK_HOBJECT_P_COMPUTE_SIZE(n_ent,n_arr,n_hash) \ | |
353 | ( \ | |
354 | (n_ent) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \ | |
355 | (n_arr) * sizeof(duk_tval) + \ | |
356 | (n_hash) * sizeof(duk_uint32_t) \ | |
357 | ) | |
358 | #define DUK_HOBJECT_P_SET_REALLOC_PTRS(p_base,set_e_k,set_e_pv,set_e_f,set_a,set_h,n_ent,n_arr,n_hash) do { \ | |
359 | (set_e_k) = (duk_hstring **) (void *) (p_base); \ | |
360 | (set_e_pv) = (duk_propvalue *) (void *) ((set_e_k) + (n_ent)); \ | |
361 | (set_e_f) = (duk_uint8_t *) (void *) ((set_e_pv) + (n_ent)); \ | |
362 | (set_a) = (duk_tval *) (void *) ((set_e_f) + (n_ent)); \ | |
363 | (set_h) = (duk_uint32_t *) (void *) ((set_a) + (n_arr)); \ | |
364 | } while (0) | |
365 | #elif defined(DUK_USE_HOBJECT_LAYOUT_2) | |
366 | /* LAYOUT 2 */ | |
367 | #if (DUK_USE_ALIGN_BY == 4) | |
368 | #define DUK_HOBJECT_E_FLAG_PADDING(e_sz) ((4 - (e_sz)) & 0x03) | |
369 | #elif (DUK_USE_ALIGN_BY == 8) | |
370 | #define DUK_HOBJECT_E_FLAG_PADDING(e_sz) ((8 - (e_sz)) & 0x07) | |
371 | #elif (DUK_USE_ALIGN_BY == 1) | |
372 | #define DUK_HOBJECT_E_FLAG_PADDING(e_sz) 0 | |
373 | #else | |
374 | #error invalid DUK_USE_ALIGN_BY | |
375 | #endif | |
376 | #define DUK_HOBJECT_E_GET_KEY_BASE(heap,h) \ | |
377 | ((duk_hstring **) (void *) ( \ | |
378 | DUK_HOBJECT_GET_PROPS((heap), (h)) + \ | |
379 | DUK_HOBJECT_GET_ESIZE((h)) * sizeof(duk_propvalue) \ | |
380 | )) | |
381 | #define DUK_HOBJECT_E_GET_VALUE_BASE(heap,h) \ | |
382 | ((duk_propvalue *) (void *) ( \ | |
383 | DUK_HOBJECT_GET_PROPS((heap), (h)) \ | |
384 | )) | |
385 | #define DUK_HOBJECT_E_GET_FLAGS_BASE(heap,h) \ | |
386 | ((duk_uint8_t *) (void *) ( \ | |
387 | DUK_HOBJECT_GET_PROPS((heap), (h)) + DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue)) \ | |
388 | )) | |
389 | #define DUK_HOBJECT_A_GET_BASE(heap,h) \ | |
390 | ((duk_tval *) (void *) ( \ | |
391 | DUK_HOBJECT_GET_PROPS((heap), (h)) + \ | |
392 | DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \ | |
393 | DUK_HOBJECT_E_FLAG_PADDING(DUK_HOBJECT_GET_ESIZE((h))) \ | |
394 | )) | |
395 | #define DUK_HOBJECT_H_GET_BASE(heap,h) \ | |
396 | ((duk_uint32_t *) (void *) ( \ | |
397 | DUK_HOBJECT_GET_PROPS((heap), (h)) + \ | |
398 | DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \ | |
399 | DUK_HOBJECT_E_FLAG_PADDING(DUK_HOBJECT_GET_ESIZE((h))) + \ | |
400 | DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) \ | |
401 | )) | |
402 | #define DUK_HOBJECT_P_COMPUTE_SIZE(n_ent,n_arr,n_hash) \ | |
403 | ( \ | |
404 | (n_ent) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \ | |
405 | DUK_HOBJECT_E_FLAG_PADDING((n_ent)) + \ | |
406 | (n_arr) * sizeof(duk_tval) + \ | |
407 | (n_hash) * sizeof(duk_uint32_t) \ | |
408 | ) | |
409 | #define DUK_HOBJECT_P_SET_REALLOC_PTRS(p_base,set_e_k,set_e_pv,set_e_f,set_a,set_h,n_ent,n_arr,n_hash) do { \ | |
410 | (set_e_pv) = (duk_propvalue *) (void *) (p_base); \ | |
411 | (set_e_k) = (duk_hstring **) (void *) ((set_e_pv) + (n_ent)); \ | |
412 | (set_e_f) = (duk_uint8_t *) (void *) ((set_e_k) + (n_ent)); \ | |
413 | (set_a) = (duk_tval *) (void *) (((duk_uint8_t *) (set_e_f)) + \ | |
414 | sizeof(duk_uint8_t) * (n_ent) + \ | |
415 | DUK_HOBJECT_E_FLAG_PADDING((n_ent))); \ | |
416 | (set_h) = (duk_uint32_t *) (void *) ((set_a) + (n_arr)); \ | |
417 | } while (0) | |
418 | #elif defined(DUK_USE_HOBJECT_LAYOUT_3) | |
419 | /* LAYOUT 3 */ | |
420 | #define DUK_HOBJECT_E_GET_KEY_BASE(heap,h) \ | |
421 | ((duk_hstring **) (void *) ( \ | |
422 | DUK_HOBJECT_GET_PROPS((heap), (h)) + \ | |
423 | DUK_HOBJECT_GET_ESIZE((h)) * sizeof(duk_propvalue) + \ | |
424 | DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) \ | |
425 | )) | |
426 | #define DUK_HOBJECT_E_GET_VALUE_BASE(heap,h) \ | |
427 | ((duk_propvalue *) (void *) ( \ | |
428 | DUK_HOBJECT_GET_PROPS((heap), (h)) \ | |
429 | )) | |
430 | #define DUK_HOBJECT_E_GET_FLAGS_BASE(heap,h) \ | |
431 | ((duk_uint8_t *) (void *) ( \ | |
432 | DUK_HOBJECT_GET_PROPS((heap), (h)) + \ | |
433 | DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_propvalue) + sizeof(duk_hstring *)) + \ | |
434 | DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) + \ | |
435 | DUK_HOBJECT_GET_HSIZE((h)) * sizeof(duk_uint32_t) \ | |
436 | )) | |
437 | #define DUK_HOBJECT_A_GET_BASE(heap,h) \ | |
438 | ((duk_tval *) (void *) ( \ | |
439 | DUK_HOBJECT_GET_PROPS((heap), (h)) + \ | |
440 | DUK_HOBJECT_GET_ESIZE((h)) * sizeof(duk_propvalue) \ | |
441 | )) | |
442 | #define DUK_HOBJECT_H_GET_BASE(heap,h) \ | |
443 | ((duk_uint32_t *) (void *) ( \ | |
444 | DUK_HOBJECT_GET_PROPS((heap), (h)) + \ | |
445 | DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_propvalue) + sizeof(duk_hstring *)) + \ | |
446 | DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) \ | |
447 | )) | |
448 | #define DUK_HOBJECT_P_COMPUTE_SIZE(n_ent,n_arr,n_hash) \ | |
449 | ( \ | |
450 | (n_ent) * (sizeof(duk_propvalue) + sizeof(duk_hstring *) + sizeof(duk_uint8_t)) + \ | |
451 | (n_arr) * sizeof(duk_tval) + \ | |
452 | (n_hash) * sizeof(duk_uint32_t) \ | |
453 | ) | |
454 | #define DUK_HOBJECT_P_SET_REALLOC_PTRS(p_base,set_e_k,set_e_pv,set_e_f,set_a,set_h,n_ent,n_arr,n_hash) do { \ | |
455 | (set_e_pv) = (duk_propvalue *) (void *) (p_base); \ | |
456 | (set_a) = (duk_tval *) (void *) ((set_e_pv) + (n_ent)); \ | |
457 | (set_e_k) = (duk_hstring **) (void *) ((set_a) + (n_arr)); \ | |
458 | (set_h) = (duk_uint32_t *) (void *) ((set_e_k) + (n_ent)); \ | |
459 | (set_e_f) = (duk_uint8_t *) (void *) ((set_h) + (n_hash)); \ | |
460 | } while (0) | |
461 | #else | |
462 | #error invalid hobject layout defines | |
463 | #endif /* hobject property layout */ | |
464 | ||
465 | #define DUK_HOBJECT_P_ALLOC_SIZE(h) \ | |
466 | DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE((h)), DUK_HOBJECT_GET_ASIZE((h)), DUK_HOBJECT_GET_HSIZE((h))) | |
467 | ||
468 | #define DUK_HOBJECT_E_GET_KEY(heap,h,i) (DUK_HOBJECT_E_GET_KEY_BASE((heap), (h))[(i)]) | |
469 | #define DUK_HOBJECT_E_GET_KEY_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_KEY_BASE((heap), (h))[(i)]) | |
470 | #define DUK_HOBJECT_E_GET_VALUE(heap,h,i) (DUK_HOBJECT_E_GET_VALUE_BASE((heap), (h))[(i)]) | |
471 | #define DUK_HOBJECT_E_GET_VALUE_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_VALUE_BASE((heap), (h))[(i)]) | |
472 | #define DUK_HOBJECT_E_GET_VALUE_TVAL(heap,h,i) (DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).v) | |
473 | #define DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).v) | |
474 | #define DUK_HOBJECT_E_GET_VALUE_GETTER(heap,h,i) (DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.get) | |
475 | #define DUK_HOBJECT_E_GET_VALUE_GETTER_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.get) | |
476 | #define DUK_HOBJECT_E_GET_VALUE_SETTER(heap,h,i) (DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.set) | |
477 | #define DUK_HOBJECT_E_GET_VALUE_SETTER_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.set) | |
478 | #define DUK_HOBJECT_E_GET_FLAGS(heap,h,i) (DUK_HOBJECT_E_GET_FLAGS_BASE((heap), (h))[(i)]) | |
479 | #define DUK_HOBJECT_E_GET_FLAGS_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_FLAGS_BASE((heap), (h))[(i)]) | |
480 | #define DUK_HOBJECT_A_GET_VALUE(heap,h,i) (DUK_HOBJECT_A_GET_BASE((heap), (h))[(i)]) | |
481 | #define DUK_HOBJECT_A_GET_VALUE_PTR(heap,h,i) (&DUK_HOBJECT_A_GET_BASE((heap), (h))[(i)]) | |
482 | #define DUK_HOBJECT_H_GET_INDEX(heap,h,i) (DUK_HOBJECT_H_GET_BASE((heap), (h))[(i)]) | |
483 | #define DUK_HOBJECT_H_GET_INDEX_PTR(heap,h,i) (&DUK_HOBJECT_H_GET_BASE((heap), (h))[(i)]) | |
484 | ||
485 | #define DUK_HOBJECT_E_SET_KEY(heap,h,i,k) do { \ | |
486 | DUK_HOBJECT_E_GET_KEY((heap), (h), (i)) = (k); \ | |
487 | } while (0) | |
488 | #define DUK_HOBJECT_E_SET_VALUE(heap,h,i,v) do { \ | |
489 | DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)) = (v); \ | |
490 | } while (0) | |
491 | #define DUK_HOBJECT_E_SET_VALUE_TVAL(heap,h,i,v) do { \ | |
492 | DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).v = (v); \ | |
493 | } while (0) | |
494 | #define DUK_HOBJECT_E_SET_VALUE_GETTER(heap,h,i,v) do { \ | |
495 | DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.get = (v); \ | |
496 | } while (0) | |
497 | #define DUK_HOBJECT_E_SET_VALUE_SETTER(heap,h,i,v) do { \ | |
498 | DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.set = (v); \ | |
499 | } while (0) | |
500 | #define DUK_HOBJECT_E_SET_FLAGS(heap,h,i,f) do { \ | |
501 | DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) = (duk_uint8_t) (f); \ | |
502 | } while (0) | |
503 | #define DUK_HOBJECT_A_SET_VALUE(heap,h,i,v) do { \ | |
504 | DUK_HOBJECT_A_GET_VALUE((heap), (h), (i)) = (v); \ | |
505 | } while (0) | |
506 | #define DUK_HOBJECT_A_SET_VALUE_TVAL(heap,h,i,v) \ | |
507 | DUK_HOBJECT_A_SET_VALUE((heap), (h), (i), (v)) /* alias for above */ | |
508 | #define DUK_HOBJECT_H_SET_INDEX(heap,h,i,v) do { \ | |
509 | DUK_HOBJECT_H_GET_INDEX((heap), (h), (i)) = (v); \ | |
510 | } while (0) | |
511 | ||
512 | #define DUK_HOBJECT_E_SET_FLAG_BITS(heap,h,i,mask) do { \ | |
513 | DUK_HOBJECT_E_GET_FLAGS_BASE((heap), (h))[(i)] |= (mask); \ | |
514 | } while (0) | |
515 | ||
516 | #define DUK_HOBJECT_E_CLEAR_FLAG_BITS(heap,h,i,mask) do { \ | |
517 | DUK_HOBJECT_E_GET_FLAGS_BASE((heap), (h))[(i)] &= ~(mask); \ | |
518 | } while (0) | |
519 | ||
520 | #define DUK_HOBJECT_E_SLOT_IS_WRITABLE(heap,h,i) ((DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) & DUK_PROPDESC_FLAG_WRITABLE) != 0) | |
521 | #define DUK_HOBJECT_E_SLOT_IS_ENUMERABLE(heap,h,i) ((DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) & DUK_PROPDESC_FLAG_ENUMERABLE) != 0) | |
522 | #define DUK_HOBJECT_E_SLOT_IS_CONFIGURABLE(heap,h,i) ((DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) & DUK_PROPDESC_FLAG_CONFIGURABLE) != 0) | |
523 | #define DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap,h,i) ((DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) & DUK_PROPDESC_FLAG_ACCESSOR) != 0) | |
524 | ||
525 | #define DUK_HOBJECT_E_SLOT_SET_WRITABLE(heap,h,i) DUK_HOBJECT_E_SET_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_WRITABLE) | |
526 | #define DUK_HOBJECT_E_SLOT_SET_ENUMERABLE(heap,h,i) DUK_HOBJECT_E_SET_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_ENUMERABLE) | |
527 | #define DUK_HOBJECT_E_SLOT_SET_CONFIGURABLE(heap,h,i) DUK_HOBJECT_E_SET_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_CONFIGURABLE) | |
528 | #define DUK_HOBJECT_E_SLOT_SET_ACCESSOR(heap,h,i) DUK_HOBJECT_E_SET_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_ACCESSOR) | |
529 | ||
530 | #define DUK_HOBJECT_E_SLOT_CLEAR_WRITABLE(heap,h,i) DUK_HOBJECT_E_CLEAR_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_WRITABLE) | |
531 | #define DUK_HOBJECT_E_SLOT_CLEAR_ENUMERABLE(heap,h,i) DUK_HOBJECT_E_CLEAR_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_ENUMERABLE) | |
532 | #define DUK_HOBJECT_E_SLOT_CLEAR_CONFIGURABLE(heap,h,i) DUK_HOBJECT_E_CLEAR_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_CONFIGURABLE) | |
533 | #define DUK_HOBJECT_E_SLOT_CLEAR_ACCESSOR(heap,h,i) DUK_HOBJECT_E_CLEAR_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_ACCESSOR) | |
534 | ||
535 | #define DUK_PROPDESC_IS_WRITABLE(p) (((p)->flags & DUK_PROPDESC_FLAG_WRITABLE) != 0) | |
536 | #define DUK_PROPDESC_IS_ENUMERABLE(p) (((p)->flags & DUK_PROPDESC_FLAG_ENUMERABLE) != 0) | |
537 | #define DUK_PROPDESC_IS_CONFIGURABLE(p) (((p)->flags & DUK_PROPDESC_FLAG_CONFIGURABLE) != 0) | |
538 | #define DUK_PROPDESC_IS_ACCESSOR(p) (((p)->flags & DUK_PROPDESC_FLAG_ACCESSOR) != 0) | |
539 | ||
540 | #define DUK_HOBJECT_HASHIDX_UNUSED 0xffffffffUL | |
541 | #define DUK_HOBJECT_HASHIDX_DELETED 0xfffffffeUL | |
542 | ||
543 | /* | |
544 | * Macros for accessing size fields | |
545 | */ | |
546 | ||
547 | #if defined(DUK_USE_OBJSIZES16) | |
548 | #define DUK_HOBJECT_GET_ESIZE(h) ((h)->e_size16) | |
549 | #define DUK_HOBJECT_SET_ESIZE(h,v) do { (h)->e_size16 = (v); } while (0) | |
550 | #define DUK_HOBJECT_GET_ENEXT(h) ((h)->e_next16) | |
551 | #define DUK_HOBJECT_SET_ENEXT(h,v) do { (h)->e_next16 = (v); } while (0) | |
552 | #define DUK_HOBJECT_POSTINC_ENEXT(h) ((h)->e_next16++) | |
553 | #define DUK_HOBJECT_GET_ASIZE(h) ((h)->a_size16) | |
554 | #define DUK_HOBJECT_SET_ASIZE(h,v) do { (h)->a_size16 = (v); } while (0) | |
555 | #if defined(DUK_USE_HOBJECT_HASH_PART) | |
556 | #define DUK_HOBJECT_GET_HSIZE(h) ((h)->h_size16) | |
557 | #define DUK_HOBJECT_SET_HSIZE(h,v) do { (h)->h_size16 = (v); } while (0) | |
558 | #else | |
559 | #define DUK_HOBJECT_GET_HSIZE(h) 0 | |
560 | #define DUK_HOBJECT_SET_HSIZE(h,v) do { DUK_ASSERT((v) == 0); } while (0) | |
561 | #endif | |
562 | #else | |
563 | #define DUK_HOBJECT_GET_ESIZE(h) ((h)->e_size) | |
564 | #define DUK_HOBJECT_SET_ESIZE(h,v) do { (h)->e_size = (v); } while (0) | |
565 | #define DUK_HOBJECT_GET_ENEXT(h) ((h)->e_next) | |
566 | #define DUK_HOBJECT_SET_ENEXT(h,v) do { (h)->e_next = (v); } while (0) | |
567 | #define DUK_HOBJECT_POSTINC_ENEXT(h) ((h)->e_next++) | |
568 | #define DUK_HOBJECT_GET_ASIZE(h) ((h)->a_size) | |
569 | #define DUK_HOBJECT_SET_ASIZE(h,v) do { (h)->a_size = (v); } while (0) | |
570 | #if defined(DUK_USE_HOBJECT_HASH_PART) | |
571 | #define DUK_HOBJECT_GET_HSIZE(h) ((h)->h_size) | |
572 | #define DUK_HOBJECT_SET_HSIZE(h,v) do { (h)->h_size = (v); } while (0) | |
573 | #else | |
574 | #define DUK_HOBJECT_GET_HSIZE(h) 0 | |
575 | #define DUK_HOBJECT_SET_HSIZE(h,v) do { DUK_ASSERT((v) == 0); } while (0) | |
576 | #endif | |
577 | #endif | |
578 | ||
579 | /* | |
580 | * Misc | |
581 | */ | |
582 | ||
583 | /* Maximum prototype traversal depth. Sanity limit which handles e.g. | |
584 | * prototype loops (even complex ones like 1->2->3->4->2->3->4->2->3->4). | |
585 | */ | |
586 | #define DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY 10000L | |
587 | ||
588 | /* Maximum traversal depth for "bound function" chains. */ | |
589 | #define DUK_HOBJECT_BOUND_CHAIN_SANITY 10000L | |
590 | ||
591 | /* | |
592 | * Ecmascript [[Class]] | |
593 | */ | |
594 | ||
595 | /* range check not necessary because all 4-bit values are mapped */ | |
596 | #define DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(n) duk_class_number_to_stridx[(n)] | |
597 | ||
598 | #define DUK_HOBJECT_GET_CLASS_STRING(heap,h) \ | |
599 | DUK_HEAP_GET_STRING( \ | |
600 | (heap), \ | |
601 | DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(DUK_HOBJECT_GET_CLASS_NUMBER((h))) \ | |
602 | ) | |
603 | ||
604 | /* | |
605 | * Macros for property handling | |
606 | */ | |
607 | ||
608 | #if defined(DUK_USE_HEAPPTR16) | |
609 | #define DUK_HOBJECT_GET_PROTOTYPE(heap,h) \ | |
610 | ((duk_hobject *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->prototype16)) | |
611 | #define DUK_HOBJECT_SET_PROTOTYPE(heap,h,x) do { \ | |
612 | (h)->prototype16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (x)); \ | |
613 | } while (0) | |
614 | #else | |
615 | #define DUK_HOBJECT_GET_PROTOTYPE(heap,h) \ | |
616 | ((h)->prototype) | |
617 | #define DUK_HOBJECT_SET_PROTOTYPE(heap,h,x) do { \ | |
618 | (h)->prototype = (x); \ | |
619 | } while (0) | |
620 | #endif | |
621 | ||
622 | /* note: this updates refcounts */ | |
623 | #define DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr,h,p) duk_hobject_set_prototype_updref((thr), (h), (p)) | |
624 | ||
625 | /* | |
626 | * Resizing and hash behavior | |
627 | */ | |
628 | ||
629 | /* Sanity limit on max number of properties (allocated, not necessarily used). | |
630 | * This is somewhat arbitrary, but if we're close to 2**32 properties some | |
631 | * algorithms will fail (e.g. hash size selection, next prime selection). | |
632 | * Also, we use negative array/entry table indices to indicate 'not found', | |
633 | * so anything above 0x80000000 will cause trouble now. | |
634 | */ | |
635 | #if defined(DUK_USE_OBJSIZES16) | |
636 | #define DUK_HOBJECT_MAX_PROPERTIES 0x0000ffffUL | |
637 | #else | |
638 | #define DUK_HOBJECT_MAX_PROPERTIES 0x7fffffffUL /* 2**31-1 ~= 2G properties */ | |
639 | #endif | |
640 | ||
641 | /* higher value conserves memory; also note that linear scan is cache friendly */ | |
642 | #define DUK_HOBJECT_E_USE_HASH_LIMIT 32 | |
643 | ||
644 | /* hash size relative to entries size: for value X, approx. hash_prime(e_size + e_size / X) */ | |
645 | #define DUK_HOBJECT_H_SIZE_DIVISOR 4 /* hash size approx. 1.25 times entries size */ | |
646 | ||
647 | /* if new_size < L * old_size, resize without abandon check; L = 3-bit fixed point, e.g. 9 -> 9/8 = 112.5% */ | |
648 | #define DUK_HOBJECT_A_FAST_RESIZE_LIMIT 9 /* 112.5%, i.e. new size less than 12.5% higher -> fast resize */ | |
649 | ||
650 | /* if density < L, abandon array part, L = 3-bit fixed point, e.g. 2 -> 2/8 = 25% */ | |
651 | /* limit is quite low: one array entry is 8 bytes, one normal entry is 4+1+8+4 = 17 bytes (with hash entry) */ | |
652 | #define DUK_HOBJECT_A_ABANDON_LIMIT 2 /* 25%, i.e. less than 25% used -> abandon */ | |
653 | ||
654 | /* internal align target for props allocation, must be 2*n for some n */ | |
655 | #if (DUK_USE_ALIGN_BY == 4) | |
656 | #define DUK_HOBJECT_ALIGN_TARGET 4 | |
657 | #elif (DUK_USE_ALIGN_BY == 8) | |
658 | #define DUK_HOBJECT_ALIGN_TARGET 8 | |
659 | #elif (DUK_USE_ALIGN_BY == 1) | |
660 | #define DUK_HOBJECT_ALIGN_TARGET 1 | |
661 | #else | |
662 | #error invalid DUK_USE_ALIGN_BY | |
663 | #endif | |
664 | ||
665 | /* controls for minimum entry part growth */ | |
666 | #define DUK_HOBJECT_E_MIN_GROW_ADD 16 | |
667 | #define DUK_HOBJECT_E_MIN_GROW_DIVISOR 8 /* 2^3 -> 1/8 = 12.5% min growth */ | |
668 | ||
669 | /* controls for minimum array part growth */ | |
670 | #define DUK_HOBJECT_A_MIN_GROW_ADD 16 | |
671 | #define DUK_HOBJECT_A_MIN_GROW_DIVISOR 8 /* 2^3 -> 1/8 = 12.5% min growth */ | |
672 | ||
673 | /* probe sequence */ | |
674 | #define DUK_HOBJECT_HASH_INITIAL(hash,h_size) ((hash) % (h_size)) | |
675 | #define DUK_HOBJECT_HASH_PROBE_STEP(hash) DUK_UTIL_GET_HASH_PROBE_STEP((hash)) | |
676 | ||
677 | /* | |
678 | * PC-to-line constants | |
679 | */ | |
680 | ||
681 | #define DUK_PC2LINE_SKIP 64 | |
682 | ||
683 | /* maximum length for a SKIP-1 diffstream: 35 bits per entry, rounded up to bytes */ | |
684 | #define DUK_PC2LINE_MAX_DIFF_LENGTH (((DUK_PC2LINE_SKIP - 1) * 35 + 7) / 8) | |
685 | ||
686 | /* | |
687 | * Struct defs | |
688 | */ | |
689 | ||
690 | struct duk_propaccessor { | |
691 | duk_hobject *get; | |
692 | duk_hobject *set; | |
693 | }; | |
694 | ||
695 | union duk_propvalue { | |
696 | /* The get/set pointers could be 16-bit pointer compressed but it | |
697 | * would make no difference on 32-bit platforms because duk_tval is | |
698 | * 8 bytes or more anyway. | |
699 | */ | |
700 | duk_tval v; | |
701 | duk_propaccessor a; | |
702 | }; | |
703 | ||
704 | struct duk_propdesc { | |
705 | /* read-only values 'lifted' for ease of use */ | |
706 | duk_small_int_t flags; | |
707 | duk_hobject *get; | |
708 | duk_hobject *set; | |
709 | ||
710 | /* for updating (all are set to < 0 for virtual properties) */ | |
711 | duk_int_t e_idx; /* prop index in 'entry part', < 0 if not there */ | |
712 | duk_int_t h_idx; /* prop index in 'hash part', < 0 if not there */ | |
713 | duk_int_t a_idx; /* prop index in 'array part', < 0 if not there */ | |
714 | }; | |
715 | ||
716 | struct duk_hobject { | |
717 | duk_heaphdr hdr; | |
718 | ||
719 | /* | |
720 | * 'props' contains {key,value,flags} entries, optional array entries, and | |
721 | * an optional hash lookup table for non-array entries in a single 'sliced' | |
722 | * allocation. There are several layout options, which differ slightly in | |
723 | * generated code size/speed and alignment/padding; duk_features.h selects | |
724 | * the layout used. | |
725 | * | |
726 | * Layout 1 (DUK_USE_HOBJECT_LAYOUT_1): | |
727 | * | |
728 | * e_size * sizeof(duk_hstring *) bytes of entry keys (e_next gc reachable) | |
729 | * e_size * sizeof(duk_propvalue) bytes of entry values (e_next gc reachable) | |
730 | * e_size * sizeof(duk_uint8_t) bytes of entry flags (e_next gc reachable) | |
731 | * a_size * sizeof(duk_tval) bytes of (opt) array values (plain only) (all gc reachable) | |
732 | * h_size * sizeof(duk_uint32_t) bytes of (opt) hash indexes to entries (e_size), | |
733 | * 0xffffffffUL = unused, 0xfffffffeUL = deleted | |
734 | * | |
735 | * Layout 2 (DUK_USE_HOBJECT_LAYOUT_2): | |
736 | * | |
737 | * e_size * sizeof(duk_propvalue) bytes of entry values (e_next gc reachable) | |
738 | * e_size * sizeof(duk_hstring *) bytes of entry keys (e_next gc reachable) | |
739 | * e_size * sizeof(duk_uint8_t) + pad bytes of entry flags (e_next gc reachable) | |
740 | * a_size * sizeof(duk_tval) bytes of (opt) array values (plain only) (all gc reachable) | |
741 | * h_size * sizeof(duk_uint32_t) bytes of (opt) hash indexes to entries (e_size), | |
742 | * 0xffffffffUL = unused, 0xfffffffeUL = deleted | |
743 | * | |
744 | * Layout 3 (DUK_USE_HOBJECT_LAYOUT_3): | |
745 | * | |
746 | * e_size * sizeof(duk_propvalue) bytes of entry values (e_next gc reachable) | |
747 | * a_size * sizeof(duk_tval) bytes of (opt) array values (plain only) (all gc reachable) | |
748 | * e_size * sizeof(duk_hstring *) bytes of entry keys (e_next gc reachable) | |
749 | * h_size * sizeof(duk_uint32_t) bytes of (opt) hash indexes to entries (e_size), | |
750 | * 0xffffffffUL = unused, 0xfffffffeUL = deleted | |
751 | * e_size * sizeof(duk_uint8_t) bytes of entry flags (e_next gc reachable) | |
752 | * | |
753 | * In layout 1, the 'e_next' count is rounded to 4 or 8 on platforms | |
754 | * requiring 4 or 8 byte alignment. This ensures proper alignment | |
755 | * for the entries, at the cost of memory footprint. However, it's | |
756 | * probably preferable to use another layout on such platforms instead. | |
757 | * | |
758 | * In layout 2, the key and value parts are swapped to avoid padding | |
759 | * the key array on platforms requiring alignment by 8. The flags part | |
760 | * is padded to get alignment for array entries. The 'e_next' count does | |
761 | * not need to be rounded as in layout 1. | |
762 | * | |
763 | * In layout 3, entry values and array values are always aligned properly, | |
764 | * and assuming pointers are at most 8 bytes, so are the entry keys. Hash | |
765 | * indices will be properly aligned (assuming pointers are at least 4 bytes). | |
766 | * Finally, flags don't need additional alignment. This layout provides | |
767 | * compact allocations without padding (even on platforms with alignment | |
768 | * requirements) at the cost of a bit slower lookups. | |
769 | * | |
770 | * Objects with few keys don't have a hash index; keys are looked up linearly, | |
771 | * which is cache efficient because the keys are consecutive. Larger objects | |
772 | * have a hash index part which contains integer indexes to the entries part. | |
773 | * | |
774 | * A single allocation reduces memory allocation overhead but requires more | |
775 | * work when any part needs to be resized. A sliced allocation for entries | |
776 | * makes linear key matching faster on most platforms (more locality) and | |
777 | * skimps on flags size (which would be followed by 3 bytes of padding in | |
778 | * most architectures if entries were placed in a struct). | |
779 | * | |
780 | * 'props' also contains internal properties distinguished with a non-BMP | |
781 | * prefix. Often used properties should be placed early in 'props' whenever | |
782 | * possible to make accessing them as fast a possible. | |
783 | */ | |
784 | ||
785 | #if defined(DUK_USE_HEAPPTR16) | |
786 | /* Located in duk_heaphdr h_extra16. Subclasses of duk_hobject (like | |
787 | * duk_hcompiledfunction) are not free to use h_extra16 for this reason. | |
788 | */ | |
789 | #else | |
790 | duk_uint8_t *props; | |
791 | #endif | |
792 | ||
793 | /* prototype: the only internal property lifted outside 'e' as it is so central */ | |
794 | #if defined(DUK_USE_HEAPPTR16) | |
795 | duk_uint16_t prototype16; | |
796 | #else | |
797 | duk_hobject *prototype; | |
798 | #endif | |
799 | ||
800 | #if defined(DUK_USE_OBJSIZES16) | |
801 | duk_uint16_t e_size16; | |
802 | duk_uint16_t e_next16; | |
803 | duk_uint16_t a_size16; | |
804 | #if defined(DUK_USE_HOBJECT_HASH_PART) | |
805 | duk_uint16_t h_size16; | |
806 | #endif | |
807 | #else | |
808 | duk_uint32_t e_size; /* entry part size */ | |
809 | duk_uint32_t e_next; /* index for next new key ([0,e_next[ are gc reachable) */ | |
810 | duk_uint32_t a_size; /* array part size (entirely gc reachable) */ | |
811 | #if defined(DUK_USE_HOBJECT_HASH_PART) | |
812 | duk_uint32_t h_size; /* hash part size or 0 if unused */ | |
813 | #endif | |
814 | #endif | |
815 | }; | |
816 | ||
817 | /* | |
818 | * Exposed data | |
819 | */ | |
820 | ||
821 | #if !defined(DUK_SINGLE_FILE) | |
822 | DUK_INTERNAL_DECL duk_uint8_t duk_class_number_to_stridx[32]; | |
823 | #endif /* !DUK_SINGLE_FILE */ | |
824 | ||
825 | /* | |
826 | * Prototypes | |
827 | */ | |
828 | ||
829 | /* alloc and init */ | |
830 | DUK_INTERNAL_DECL duk_hobject *duk_hobject_alloc(duk_heap *heap, duk_uint_t hobject_flags); | |
831 | #if 0 /* unused */ | |
832 | DUK_INTERNAL_DECL duk_hobject *duk_hobject_alloc_checked(duk_hthread *thr, duk_uint_t hobject_flags); | |
833 | #endif | |
834 | DUK_INTERNAL_DECL duk_hcompiledfunction *duk_hcompiledfunction_alloc(duk_heap *heap, duk_uint_t hobject_flags); | |
835 | DUK_INTERNAL_DECL duk_hnativefunction *duk_hnativefunction_alloc(duk_heap *heap, duk_uint_t hobject_flags); | |
836 | DUK_INTERNAL duk_hbufferobject *duk_hbufferobject_alloc(duk_heap *heap, duk_uint_t hobject_flags); | |
837 | DUK_INTERNAL_DECL duk_hthread *duk_hthread_alloc(duk_heap *heap, duk_uint_t hobject_flags); | |
838 | ||
839 | /* low-level property functions */ | |
840 | DUK_INTERNAL_DECL void duk_hobject_find_existing_entry(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_int_t *e_idx, duk_int_t *h_idx); | |
841 | DUK_INTERNAL_DECL duk_tval *duk_hobject_find_existing_entry_tval_ptr(duk_heap *heap, duk_hobject *obj, duk_hstring *key); | |
842 | DUK_INTERNAL_DECL duk_tval *duk_hobject_find_existing_entry_tval_ptr_and_attrs(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_int_t *out_attrs); | |
843 | DUK_INTERNAL_DECL duk_tval *duk_hobject_find_existing_array_entry_tval_ptr(duk_heap *heap, duk_hobject *obj, duk_uarridx_t i); | |
844 | DUK_INTERNAL_DECL duk_bool_t duk_hobject_get_own_propdesc(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *out_desc, duk_small_uint_t flags); | |
845 | ||
846 | /* XXX: when optimizing for guaranteed property slots, use a guaranteed | |
847 | * slot for internal value; this call can then access it directly. | |
848 | */ | |
849 | #define duk_hobject_get_internal_value_tval_ptr(heap,obj) \ | |
850 | duk_hobject_find_existing_entry_tval_ptr((heap), (obj), DUK_HEAP_STRING_INT_VALUE((heap))) | |
851 | ||
852 | /* core property functions */ | |
853 | DUK_INTERNAL_DECL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key); | |
854 | DUK_INTERNAL_DECL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_tval *tv_val, duk_bool_t throw_flag); | |
855 | DUK_INTERNAL_DECL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_bool_t throw_flag); | |
856 | DUK_INTERNAL_DECL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key); | |
857 | ||
858 | /* internal property functions */ | |
859 | #define DUK_DELPROP_FLAG_THROW (1 << 0) | |
860 | #define DUK_DELPROP_FLAG_FORCE (1 << 1) | |
861 | DUK_INTERNAL_DECL duk_bool_t duk_hobject_delprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags); | |
862 | DUK_INTERNAL_DECL duk_bool_t duk_hobject_hasprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key); | |
863 | DUK_INTERNAL_DECL void duk_hobject_define_property_internal(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags); | |
864 | DUK_INTERNAL_DECL void duk_hobject_define_property_internal_arridx(duk_hthread *thr, duk_hobject *obj, duk_uarridx_t arr_idx, duk_small_uint_t flags); | |
865 | DUK_INTERNAL_DECL void duk_hobject_define_accessor_internal(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_hobject *getter, duk_hobject *setter, duk_small_uint_t propflags); | |
866 | DUK_INTERNAL_DECL void duk_hobject_set_length(duk_hthread *thr, duk_hobject *obj, duk_uint32_t length); /* XXX: duk_uarridx_t? */ | |
867 | DUK_INTERNAL_DECL void duk_hobject_set_length_zero(duk_hthread *thr, duk_hobject *obj); | |
868 | DUK_INTERNAL_DECL duk_uint32_t duk_hobject_get_length(duk_hthread *thr, duk_hobject *obj); /* XXX: duk_uarridx_t? */ | |
869 | ||
870 | /* helpers for defineProperty() and defineProperties() */ | |
871 | DUK_INTERNAL_DECL | |
872 | void duk_hobject_prepare_property_descriptor(duk_context *ctx, | |
873 | duk_idx_t idx_in, | |
874 | duk_uint_t *out_defprop_flags, | |
875 | duk_idx_t *out_idx_value, | |
876 | duk_hobject **out_getter, | |
877 | duk_hobject **out_setter); | |
878 | DUK_INTERNAL_DECL | |
879 | void duk_hobject_define_property_helper(duk_context *ctx, | |
880 | duk_uint_t defprop_flags, | |
881 | duk_hobject *obj, | |
882 | duk_hstring *key, | |
883 | duk_idx_t idx_value, | |
884 | duk_hobject *get, | |
885 | duk_hobject *set); | |
886 | ||
887 | /* Object built-in methods */ | |
888 | DUK_INTERNAL_DECL duk_ret_t duk_hobject_object_get_own_property_descriptor(duk_context *ctx); | |
889 | DUK_INTERNAL_DECL void duk_hobject_object_seal_freeze_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_freeze); | |
890 | DUK_INTERNAL_DECL duk_bool_t duk_hobject_object_is_sealed_frozen_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_frozen); | |
891 | DUK_INTERNAL_DECL duk_bool_t duk_hobject_object_ownprop_helper(duk_context *ctx, duk_small_uint_t required_desc_flags); | |
892 | ||
893 | /* internal properties */ | |
894 | DUK_INTERNAL_DECL duk_bool_t duk_hobject_get_internal_value(duk_heap *heap, duk_hobject *obj, duk_tval *tv); | |
895 | DUK_INTERNAL_DECL duk_hstring *duk_hobject_get_internal_value_string(duk_heap *heap, duk_hobject *obj); | |
896 | ||
897 | /* hobject management functions */ | |
898 | DUK_INTERNAL_DECL void duk_hobject_compact_props(duk_hthread *thr, duk_hobject *obj); | |
899 | ||
900 | /* ES6 proxy */ | |
901 | #if defined(DUK_USE_ES6_PROXY) | |
902 | DUK_INTERNAL_DECL duk_bool_t duk_hobject_proxy_check(duk_hthread *thr, duk_hobject *obj, duk_hobject **out_target, duk_hobject **out_handler); | |
903 | DUK_INTERNAL_DECL duk_hobject *duk_hobject_resolve_proxy_target(duk_hthread *thr, duk_hobject *obj); | |
904 | #endif | |
905 | ||
906 | /* enumeration */ | |
907 | DUK_INTERNAL_DECL void duk_hobject_enumerator_create(duk_context *ctx, duk_small_uint_t enum_flags); | |
908 | DUK_INTERNAL_DECL duk_ret_t duk_hobject_get_enumerated_keys(duk_context *ctx, duk_small_uint_t enum_flags); | |
909 | DUK_INTERNAL_DECL duk_bool_t duk_hobject_enumerator_next(duk_context *ctx, duk_bool_t get_value); | |
910 | ||
911 | /* macros */ | |
912 | DUK_INTERNAL_DECL void duk_hobject_set_prototype_updref(duk_hthread *thr, duk_hobject *h, duk_hobject *p); | |
913 | ||
914 | /* finalization */ | |
915 | DUK_INTERNAL_DECL void duk_hobject_run_finalizer(duk_hthread *thr, duk_hobject *obj); | |
916 | ||
917 | /* pc2line */ | |
918 | #if defined(DUK_USE_PC2LINE) | |
919 | DUK_INTERNAL_DECL void duk_hobject_pc2line_pack(duk_hthread *thr, duk_compiler_instr *instrs, duk_uint_fast32_t length); | |
920 | DUK_INTERNAL_DECL duk_uint_fast32_t duk_hobject_pc2line_query(duk_context *ctx, duk_idx_t idx_func, duk_uint_fast32_t pc); | |
921 | #endif | |
922 | ||
923 | /* misc */ | |
924 | DUK_INTERNAL_DECL duk_bool_t duk_hobject_prototype_chain_contains(duk_hthread *thr, duk_hobject *h, duk_hobject *p, duk_bool_t ignore_loop); | |
925 | ||
926 | #endif /* DUK_HOBJECT_H_INCLUDED */ |